33#include " pch.h"
44#include " Public/AppInstallerDateTime.h"
55
6+ using namespace std ::chrono;
7+
68namespace AppInstaller ::Utility
79{
8- // If moved to C++20, this can be replaced with standard library implementations.
9- void OutputTimePoint (std::ostream& stream, const std::chrono::system_clock::time_point& time, bool useRFC3339)
10+ namespace
1011 {
11- using namespace std ::chrono;
12-
13- tm localTime{};
14- auto tt = system_clock::to_time_t (time);
15- _localtime64_s (&localTime, &tt);
16-
17- stream
18- << std::setw (4 ) << (1900 + localTime.tm_year ) << ' -'
19- << std::setw (2 ) << std::setfill (' 0' ) << (1 + localTime.tm_mon ) << ' -'
20- << std::setw (2 ) << std::setfill (' 0' ) << localTime.tm_mday << (useRFC3339 ? ' T' : ' ' )
21- << std::setw (2 ) << std::setfill (' 0' ) << localTime.tm_hour << ' :'
22- << std::setw (2 ) << std::setfill (' 0' ) << localTime.tm_min << ' :'
23- << std::setw (2 ) << std::setfill (' 0' ) << localTime.tm_sec << ' .' ;
24-
25- // Get partial seconds
26- auto sinceEpoch = time.time_since_epoch ();
27- auto leftoverMillis = duration_cast<milliseconds>(sinceEpoch) - duration_cast<seconds>(sinceEpoch);
12+ struct OutputTimePointContext
13+ {
14+ OutputTimePointContext (std::ostream& stream, const std::chrono::system_clock::time_point& time, TimeFacet facet) :
15+ Stream (stream), Time(time), Facet(facet)
16+ {
17+ auto tt = system_clock::to_time_t (time);
18+ _localtime64_s (&LocalTime, &tt);
19+ }
20+
21+ std::ostream& Stream;
22+ const std::chrono::system_clock::time_point& Time;
23+ tm LocalTime{};
24+ TimeFacet Facet;
25+ };
26+
27+ struct OutputTimePointFacetInfo
28+ {
29+ TimeFacet Facet;
30+ char FollowingSeparator;
31+ void (*Action)(const OutputTimePointContext&);
32+ };
33+ }
2834
29- stream << std::setw (3 ) << std::setfill (' 0' ) << leftoverMillis.count ();
35+ void OutputTimePoint (std::ostream& stream, const std::chrono::system_clock::time_point& time, bool useRFC3339)
36+ {
37+ OutputTimePoint (stream, time, TimeFacet::Default | (useRFC3339 ? TimeFacet::RFC3339 : TimeFacet::None));
38+ }
3039
31- if (useRFC3339)
40+ // If moved to C++20, this can be replaced with standard library implementations.
41+ void OutputTimePoint (std::ostream& stream, const std::chrono::system_clock::time_point& time, TimeFacet facet)
42+ {
43+ OutputTimePointContext context{ stream, time, facet };
44+ using Ctx = const OutputTimePointContext&;
45+
46+ bool useRFC3339 = WI_IsFlagSet (facet, TimeFacet::RFC3339);
47+ bool filename = WI_IsFlagSet (facet, TimeFacet::Filename);
48+ char day_time_separator = useRFC3339 ? ' T' : (filename ? ' -' : ' ' );
49+ char time_field_separator = filename ? ' -' : ' :' ;
50+
51+ bool needsSeparator = false ;
52+ char currentSeparator = ' -' ;
53+
54+ for (const auto & info : {
55+ OutputTimePointFacetInfo{ TimeFacet::ShortYear, ' -' , [](Ctx ctx) { ctx.Stream << (ctx.LocalTime .tm_year - 100 ); }},
56+ OutputTimePointFacetInfo{ TimeFacet::Year, ' -' , [](Ctx ctx) { ctx.Stream << (1900 + ctx.LocalTime .tm_year ); }},
57+ OutputTimePointFacetInfo{ TimeFacet::Month, ' -' , [](Ctx ctx) { ctx.Stream << std::setw (2 ) << std::setfill (' 0' ) << (1 + ctx.LocalTime .tm_mon ); }},
58+ OutputTimePointFacetInfo{ TimeFacet::Day, day_time_separator, [](Ctx ctx) { ctx.Stream << std::setw (2 ) << std::setfill (' 0' ) << ctx.LocalTime .tm_mday ; }},
59+ OutputTimePointFacetInfo{ TimeFacet::Hour, time_field_separator, [](Ctx ctx) { ctx.Stream << std::setw (2 ) << std::setfill (' 0' ) << ctx.LocalTime .tm_hour ; }},
60+ OutputTimePointFacetInfo{ TimeFacet::Minute, time_field_separator, [](Ctx ctx) { ctx.Stream << std::setw (2 ) << std::setfill (' 0' ) << ctx.LocalTime .tm_min ; }},
61+ OutputTimePointFacetInfo{ TimeFacet::Second, ' .' , [](Ctx ctx) { ctx.Stream << std::setw (2 ) << std::setfill (' 0' ) << ctx.LocalTime .tm_sec ; }},
62+ OutputTimePointFacetInfo{ TimeFacet::Millisecond, ' -' , [](Ctx ctx)
63+ {
64+ // Get partial seconds
65+ auto sinceEpoch = ctx.Time .time_since_epoch ();
66+ auto leftoverMillis = duration_cast<milliseconds>(sinceEpoch) - duration_cast<seconds>(sinceEpoch);
67+
68+ ctx.Stream << std::setw (3 ) << std::setfill (' 0' ) << leftoverMillis.count ();
69+ }},
70+ OutputTimePointFacetInfo{ TimeFacet::RFC3339, ' \0 ' , [](Ctx ctx)
71+ {
72+ // RFC 3339 requires adding time zone info.
73+ // No need to bother getting the actual time zone as we don't need it.
74+ // -00:00 represents an unspecified time zone, not UTC.
75+ ctx.Stream << " 00:00" ;
76+ }},
77+ })
3278 {
33- // RFC 3339 requires adding time zone info.
34- // No need to bother getting the actual time zone as we don't need it.
35- // -00:00 represents an unspecified time zone, not UTC.
36- stream << " -00:00" ;
79+ if (WI_AreAllFlagsSet (facet, info.Facet ))
80+ {
81+ if (needsSeparator)
82+ {
83+ stream << currentSeparator;
84+ }
85+
86+ info.Action (context);
87+ needsSeparator = true ;
88+ }
89+
90+ // Getting this right for every mix of facets is probably not possible.
91+ // Future needs can dictate changes here.
92+ currentSeparator = info.FollowingSeparator ;
3793 }
3894 }
3995
@@ -44,16 +100,16 @@ namespace AppInstaller::Utility
44100 return std::move (stream).str ();
45101 }
46102
47- std::string GetCurrentTimeForFilename ( )
103+ std::string TimePointToString ( const std::chrono::system_clock::time_point& time, TimeFacet facet )
48104 {
49- std::stringstream stream;
50- OutputTimePoint (stream, std::chrono::system_clock::now ());
51-
52- auto result = stream.str ();
53- std::replace (result.begin (), result.end (), ' :' , ' -' );
54- std::replace (result.begin (), result.end (), ' ' , ' -' );
105+ std::ostringstream stream;
106+ OutputTimePoint (stream, time, facet);
107+ return std::move (stream).str ();
108+ }
55109
56- return result;
110+ std::string GetCurrentTimeForFilename (bool shortTime)
111+ {
112+ return TimePointToString (std::chrono::system_clock::now (), (shortTime ? TimeFacet::ShortYearSecondPrecision : TimeFacet::Default) | TimeFacet::Filename);
57113 }
58114
59115 std::string GetCurrentDateForARP ()
0 commit comments