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