@@ -30,7 +30,9 @@ using namespace Platform;
30
30
using namespace Windows ::Storage::Streams;
31
31
#endif // #if !defined(__cplusplus_winrt)
32
32
33
- #if !defined(_MS_WINDOWS)
33
+ #if defined(_MS_WINDOWS)
34
+ #include < regex>
35
+ #else
34
36
#include < boost/date_time/posix_time/posix_time.hpp>
35
37
#include < boost/date_time/posix_time/posix_time_io.hpp>
36
38
// GCC 4.8 does not support regex, use boost. TODO: switch to std::regex in GCC 4.9
@@ -554,24 +556,25 @@ utility::string_t datetime::to_string(date_format format) const
554
556
}
555
557
else if ( format == ISO_8601 )
556
558
{
559
+ const size_t buffSize = 64 ;
557
560
#if _WIN32_WINNT < _WIN32_WINNT_VISTA
558
- TCHAR dateStr[18 ] = {0 };
559
- status = GetDateFormat (LOCALE_INVARIANT, 0 , &systemTime, " yyyy-MM-dd" , dateStr, sizeof (dateStr) / sizeof ( wchar_t ) );
561
+ TCHAR dateStr[buffSize ] = {0 };
562
+ status = GetDateFormat (LOCALE_INVARIANT, 0 , &systemTime, " yyyy-MM-dd" , dateStr, buffSize );
560
563
#else
561
- wchar_t dateStr[18 ] = {0 };
562
- status = GetDateFormatEx (LOCALE_NAME_INVARIANT, 0 , &systemTime, L" yyyy-MM-dd" , dateStr, sizeof (dateStr) / sizeof ( wchar_t ) , NULL );
564
+ wchar_t dateStr[buffSize ] = {0 };
565
+ status = GetDateFormatEx (LOCALE_NAME_INVARIANT, 0 , &systemTime, L" yyyy-MM-dd" , dateStr, buffSize , NULL );
563
566
#endif // _WIN32_WINNT < _WIN32_WINNT_VISTA
564
567
if (status == 0 )
565
568
{
566
569
throw utility::details::create_system_error (GetLastError ());
567
570
}
568
571
569
572
#if _WIN32_WINNT < _WIN32_WINNT_VISTA
570
- TCHAR timeStr[10 ] = {0 };
571
- status = GetTimeFormat (LOCALE_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, " HH':'mm':'ss" , timeStr, sizeof (timeStr) / sizeof ( wchar_t ) );
573
+ TCHAR timeStr[buffSize ] = {0 };
574
+ status = GetTimeFormat (LOCALE_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, " HH':'mm':'ss" , timeStr, buffSize );
572
575
#else
573
- wchar_t timeStr[10 ] = {0 };
574
- status = GetTimeFormatEx (LOCALE_NAME_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L" HH':'mm':'ss" , timeStr, sizeof (timeStr) / sizeof ( wchar_t ) );
576
+ wchar_t timeStr[buffSize ] = {0 };
577
+ status = GetTimeFormatEx (LOCALE_NAME_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L" HH':'mm':'ss" , timeStr, buffSize );
575
578
#endif // _WIN32_WINNT < _WIN32_WINNT_VISTA
576
579
if (status == 0 )
577
580
{
@@ -632,7 +635,7 @@ utility::string_t datetime::to_string(date_format format) const
632
635
}
633
636
634
637
#ifdef _MS_WINDOWS
635
- bool __cdecl datetime::system_type_to_datetime (void * pvsysTime, double seconds, datetime * pdt)
638
+ bool __cdecl datetime::system_type_to_datetime (void * pvsysTime, uint64_t seconds, datetime * pdt)
636
639
{
637
640
SYSTEMTIME* psysTime = (SYSTEMTIME*)pvsysTime;
638
641
FILETIME fileTime;
@@ -644,8 +647,7 @@ bool __cdecl datetime::system_type_to_datetime(void* pvsysTime, double seconds,
644
647
largeInt.HighPart = fileTime.dwHighDateTime ;
645
648
646
649
// Add hundredths of nanoseconds
647
- uint64_t hn = (uint64_t )(seconds * _secondTicks);
648
- largeInt.QuadPart += hn;
650
+ largeInt.QuadPart += seconds;
649
651
650
652
*pdt = datetime (largeInt.QuadPart );
651
653
return true ;
@@ -676,6 +678,9 @@ uint64_t timeticks_from_second(const utility::string_t& str)
676
678
// / </summary>
677
679
datetime __cdecl datetime::from_string (const utility::string_t & dateString, date_format format)
678
680
{
681
+ // avoid floating point math to preserve precision
682
+ uint64_t ufrac_second = 0 ;
683
+
679
684
#ifdef _MS_WINDOWS
680
685
datetime result;
681
686
if ( format == RFC_1123 )
@@ -704,7 +709,7 @@ datetime __cdecl datetime::from_string(const utility::string_t& dateString, date
704
709
if (loc != monthnames+12 )
705
710
{
706
711
sysTime.wMonth = (short ) ((loc - monthnames) + 1 );
707
- if (system_type_to_datetime (&sysTime, 0.0 , &result))
712
+ if (system_type_to_datetime (&sysTime, ufrac_second , &result))
708
713
{
709
714
return result;
710
715
}
@@ -715,23 +720,33 @@ datetime __cdecl datetime::from_string(const utility::string_t& dateString, date
715
720
{
716
721
// Unlike FILETIME, SYSTEMTIME does not have enough precision to hold seconds in 100 nanosecond
717
722
// increments. Therefore, start with seconds and milliseconds set to 0, then add them separately
718
- // from this double:
719
- double seconds;
723
+
724
+ // Try to extract the fractional second from the timestamp
725
+ std::wregex r_frac_second (L" (.+)(\\ .\\ d+)(Z$)" );
726
+ std::wsmatch m;
727
+
728
+ std::wstring input (dateString);
729
+ if (std::regex_search (dateString, m, r_frac_second))
730
+ {
731
+ auto frac = m[2 ].str (); // this is the fractional second
732
+ ufrac_second = timeticks_from_second (frac);
733
+ input = m[1 ].str () + m[3 ].str ();
734
+ }
720
735
721
736
{
722
737
SYSTEMTIME sysTime = { 0 };
723
- const wchar_t * formatString = L" %4d-%2d-%2dT%2d:%2d:%lfZ " ;
724
- auto n = swscanf_s (dateString .c_str (), formatString,
738
+ const wchar_t * formatString = L" %4d-%2d-%2dT%2d:%2d:%2dZ " ;
739
+ auto n = swscanf_s (input .c_str (), formatString,
725
740
&sysTime.wYear ,
726
741
&sysTime.wMonth ,
727
742
&sysTime.wDay ,
728
743
&sysTime.wHour ,
729
744
&sysTime.wMinute ,
730
- &seconds );
745
+ &sysTime. wSecond );
731
746
732
747
if (n == 3 || n == 6 )
733
748
{
734
- if (system_type_to_datetime (&sysTime, seconds , &result))
749
+ if (system_type_to_datetime (&sysTime, ufrac_second , &result))
735
750
{
736
751
return result;
737
752
}
@@ -741,12 +756,12 @@ datetime __cdecl datetime::from_string(const utility::string_t& dateString, date
741
756
SYSTEMTIME sysTime = {0 };
742
757
DWORD date = 0 ;
743
758
744
- const wchar_t * formatString = L" %8dT%2d:%2d:%lfZ " ;
745
- auto n = swscanf_s (dateString .c_str (), formatString,
759
+ const wchar_t * formatString = L" %8dT%2d:%2d:%2dZ " ;
760
+ auto n = swscanf_s (input .c_str (), formatString,
746
761
&date,
747
762
&sysTime.wHour ,
748
763
&sysTime.wMinute ,
749
- &seconds );
764
+ &sysTime. wSecond );
750
765
751
766
if (n == 1 || n == 4 )
752
767
{
@@ -756,7 +771,7 @@ datetime __cdecl datetime::from_string(const utility::string_t& dateString, date
756
771
date /= 100 ;
757
772
sysTime.wYear = (WORD)date;
758
773
759
- if (system_type_to_datetime (&sysTime, seconds , &result))
774
+ if (system_type_to_datetime (&sysTime, ufrac_second , &result))
760
775
{
761
776
return result;
762
777
}
@@ -765,19 +780,18 @@ datetime __cdecl datetime::from_string(const utility::string_t& dateString, date
765
780
{
766
781
SYSTEMTIME sysTime = {0 };
767
782
GetSystemTime (&sysTime); // Fill date portion with today's information
768
- // Zero out second -- we will use the double for that
769
783
sysTime.wSecond = 0 ;
770
784
sysTime.wMilliseconds = 0 ;
771
785
772
- const wchar_t * formatString = L" %2d:%2d:%lfZ " ;
773
- auto n = swscanf_s (dateString .c_str (), formatString,
786
+ const wchar_t * formatString = L" %2d:%2d:%2dZ " ;
787
+ auto n = swscanf_s (input .c_str (), formatString,
774
788
&sysTime.wHour ,
775
789
&sysTime.wMinute ,
776
- &seconds );
790
+ &sysTime. wSecond );
777
791
778
792
if (n == 3 )
779
793
{
780
- if (system_type_to_datetime (&sysTime, seconds , &result))
794
+ if (system_type_to_datetime (&sysTime, ufrac_second , &result))
781
795
{
782
796
return result;
783
797
}
@@ -791,9 +805,6 @@ datetime __cdecl datetime::from_string(const utility::string_t& dateString, date
791
805
792
806
struct tm output = tm ();
793
807
794
- // avoid floating point math to preserve precision
795
- uint64_t ufrac_second = 0 ;
796
-
797
808
if ( format == RFC_1123 )
798
809
{
799
810
strptime (input.data (), " %a, %d %b %Y %H:%M:%S GMT" , &output);
@@ -810,7 +821,7 @@ datetime __cdecl datetime::from_string(const utility::string_t& dateString, date
810
821
ufrac_second = timeticks_from_second (frac);
811
822
input = m[1 ].str () + m[3 ].str ();
812
823
}
813
-
824
+
814
825
auto result = strptime (input.data (), " %Y-%m-%dT%H:%M:%SZ" , &output);
815
826
816
827
if ( result == nullptr )
0 commit comments