@@ -576,7 +576,19 @@ utility::string_t datetime::to_string(date_format format) const
576
576
throw utility::details::create_system_error (GetLastError ());
577
577
}
578
578
579
- outStream << dateStr << " T" << timeStr << " Z" ;
579
+ outStream << dateStr << " T" << timeStr;
580
+ uint64_t frac_sec = largeInt.QuadPart % _secondTicks;
581
+ if (frac_sec > 0 )
582
+ {
583
+ // Append fractional second, which is a 7-digit value with no trailing zeros
584
+ // This way, '1200' becomes '00012'
585
+ char buf[9 ] = { 0 };
586
+ sprintf_s (buf, sizeof (buf), " .%07d" , frac_sec);
587
+ // trim trailing zeros
588
+ for (int i = 7 ; buf[i] == ' 0' ; i--) buf[i] = ' \0 ' ;
589
+ outStream << buf;
590
+ }
591
+ outStream << " Z" ;
580
592
}
581
593
582
594
return outStream.str ();
@@ -598,12 +610,36 @@ utility::string_t datetime::to_string(date_format format) const
598
610
#endif
599
611
}
600
612
613
+ #ifdef _MS_WINDOWS
614
+ bool __cdecl datetime::system_type_to_datetime (void * pvsysTime, double seconds, datetime * pdt)
615
+ {
616
+ SYSTEMTIME* psysTime = (SYSTEMTIME*)pvsysTime;
617
+ FILETIME fileTime;
618
+
619
+ if (SystemTimeToFileTime (psysTime, &fileTime))
620
+ {
621
+ ULARGE_INTEGER largeInt;
622
+ largeInt.LowPart = fileTime.dwLowDateTime ;
623
+ largeInt.HighPart = fileTime.dwHighDateTime ;
624
+
625
+ // Add hundredths of nanoseconds
626
+ uint64_t hn = (uint64_t )(seconds * _secondTicks);
627
+ largeInt.QuadPart += hn;
628
+
629
+ *pdt = datetime (largeInt.QuadPart );
630
+ return true ;
631
+ }
632
+ return false ;
633
+ }
634
+ #endif
635
+
601
636
// / <summary>
602
637
// / Returns a string representation of the datetime. The string is formatted based on RFC 1123 or ISO 8601
603
638
// / </summary>
604
639
datetime __cdecl datetime::from_string (const utility::string_t & dateString, date_format format)
605
640
{
606
641
#ifdef _MS_WINDOWS
642
+ datetime result;
607
643
if ( format == RFC_1123 )
608
644
{
609
645
SYSTEMTIME sysTime = {0 };
@@ -629,100 +665,83 @@ datetime __cdecl datetime::from_string(const utility::string_t& dateString, date
629
665
630
666
if (loc != monthnames+12 )
631
667
{
632
- FILETIME fileTime;
633
668
sysTime.wMonth = (short ) ((loc - monthnames) + 1 );
634
-
635
- if (SystemTimeToFileTime (&sysTime, &fileTime))
669
+ if (system_type_to_datetime (&sysTime, 0.0 , &result))
636
670
{
637
- ULARGE_INTEGER largeInt;
638
- largeInt.LowPart = fileTime.dwLowDateTime ;
639
- largeInt.HighPart = fileTime.dwHighDateTime ;
640
-
641
- return datetime (largeInt.QuadPart );
671
+ return result;
642
672
}
643
673
}
644
674
}
645
675
}
646
676
else if ( format == ISO_8601 )
647
677
{
678
+ // Unlike FILETIME, SYSTEMTIME does not have enough precision to hold seconds in 100 nanosecond
679
+ // increments. Therefore, start with seconds and milliseconds set to 0, then add them separately
680
+ // from this double:
681
+ double seconds;
682
+
648
683
{
649
- SYSTEMTIME sysTime = {0 };
650
-
651
- const wchar_t * formatString = L" %4d-%2d-%2dT%2d:%2d:%2dZ" ;
684
+ SYSTEMTIME sysTime = { 0 };
685
+ const wchar_t * formatString = L" %4d-%2d-%2dT%2d:%2d:%lfZ" ;
652
686
auto n = swscanf_s (dateString.c_str (), formatString,
653
687
&sysTime.wYear ,
654
688
&sysTime.wMonth ,
655
689
&sysTime.wDay ,
656
690
&sysTime.wHour ,
657
691
&sysTime.wMinute ,
658
- &sysTime. wSecond );
692
+ &seconds );
659
693
660
694
if (n == 3 || n == 6 )
661
695
{
662
- FILETIME fileTime;
663
-
664
- if (SystemTimeToFileTime (&sysTime, &fileTime))
696
+ if (system_type_to_datetime (&sysTime, seconds, &result))
665
697
{
666
- ULARGE_INTEGER largeInt;
667
- largeInt.LowPart = fileTime.dwLowDateTime ;
668
- largeInt.HighPart = fileTime.dwHighDateTime ;
669
-
670
- return datetime (largeInt.QuadPart );
698
+ return result;
671
699
}
672
700
}
673
701
}
674
702
{
675
703
SYSTEMTIME sysTime = {0 };
676
704
DWORD date = 0 ;
677
705
678
- const wchar_t * formatString = L" %8dT%2d:%2d:%2dZ " ;
706
+ const wchar_t * formatString = L" %8dT%2d:%2d:%lfZ " ;
679
707
auto n = swscanf_s (dateString.c_str (), formatString,
680
708
&date,
681
709
&sysTime.wHour ,
682
710
&sysTime.wMinute ,
683
- &sysTime. wSecond );
711
+ &seconds );
684
712
685
713
if (n == 1 || n == 4 )
686
714
{
687
- FILETIME fileTime;
688
-
689
715
sysTime.wDay = date % 100 ;
690
716
date /= 100 ;
691
717
sysTime.wMonth = date % 100 ;
692
718
date /= 100 ;
693
719
sysTime.wYear = (WORD)date;
694
720
695
- if (SystemTimeToFileTime (&sysTime, &fileTime ))
721
+ if (system_type_to_datetime (&sysTime, seconds, &result ))
696
722
{
697
- ULARGE_INTEGER largeInt;
698
- largeInt.LowPart = fileTime.dwLowDateTime ;
699
- largeInt.HighPart = fileTime.dwHighDateTime ;
700
-
701
- return datetime (largeInt.QuadPart );
723
+ return result;
702
724
}
703
725
}
704
726
}
705
727
{
706
728
SYSTEMTIME sysTime = {0 };
707
729
GetSystemTime (&sysTime); // Fill date portion with today's information
730
+ // Zero out second -- we will use the double for that
731
+ sysTime.wSecond = 0 ;
732
+ sysTime.wMilliseconds = 0 ;
708
733
709
- const wchar_t * formatString = L" %2d:%2d:%2dZ " ;
734
+ const wchar_t * formatString = L" %2d:%2d:%lfZ " ;
710
735
auto n = swscanf_s (dateString.c_str (), formatString,
711
736
&sysTime.wHour ,
712
737
&sysTime.wMinute ,
713
- &sysTime. wSecond );
738
+ &seconds );
714
739
715
740
if (n == 3 )
716
741
{
717
- FILETIME fileTime;
718
-
719
- if (SystemTimeToFileTime (&sysTime, &fileTime))
742
+ if (system_type_to_datetime (&sysTime, seconds, &result))
720
743
{
721
- ULARGE_INTEGER largeInt;
722
- largeInt.LowPart = fileTime.dwLowDateTime ;
723
- largeInt.HighPart = fileTime.dwHighDateTime ;
724
-
725
- return datetime (largeInt.QuadPart );
744
+ return result;
726
745
}
727
746
}
728
747
}
0 commit comments