1 // Written in the D programming language
2 
3 /++
4 
5 $(SCRIPT inhibitQuickIndex = 1;)
6 $(DIVC quickindex,
7 $(BOOKTABLE,
8 $(TR $(TH Category) $(TH Functions))
9 $(TR $(TD Types) $(TD
10     $(LREF Clock)
11     $(LREF SysTime)
12     $(LREF DosFileTime)
13 ))
14 $(TR $(TD Conversion) $(TD
15     $(LREF parseRFC822DateTime)
16     $(LREF DosFileTimeToSysTime)
17     $(LREF FILETIMEToStdTime)
18     $(LREF FILETIMEToSysTime)
19     $(LREF stdTimeToFILETIME)
20     $(LREF stdTimeToUnixTime)
21     $(LREF SYSTEMTIMEToSysTime)
22     $(LREF SysTimeToDosFileTime)
23     $(LREF SysTimeToFILETIME)
24     $(LREF SysTimeToSYSTEMTIME)
25     $(LREF unixTimeToStdTime)
26 ))
27 ))
28 
29     License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
30     Authors:   $(HTTP jmdavisprog.com, Jonathan M Davis)
31     Source:    $(PHOBOSSRC std/datetime/systime.d)
32 +/
33 module std.datetime.systime;
34 
35 version (OSX)
36     version = Darwin;
37 else version (iOS)
38     version = Darwin;
39 else version (TVOS)
40     version = Darwin;
41 else version (WatchOS)
42     version = Darwin;
43 
44 /// Get the current time as a $(LREF SysTime)
45 @safe unittest
46 {
47     import std.datetime.timezone : LocalTime;
48     SysTime today = Clock.currTime();
49     assert(today.timezone is LocalTime());
50 }
51 
52 /// Construct a $(LREF SysTime) from a ISO time string
53 @safe unittest
54 {
55     import std.datetime.date : DateTime;
56     import std.datetime.timezone : UTC;
57 
58     auto st = SysTime.fromISOExtString("2018-01-01T10:30:00Z");
59     assert(st == SysTime(DateTime(2018, 1, 1, 10, 30, 0), UTC()));
60 }
61 
62 /// Make a specific point in time in the New York timezone
63 @safe unittest
64 {
65     import core.time : hours;
66     import std.datetime.date : DateTime;
67     import std.datetime.timezone : SimpleTimeZone;
68 
69     auto ny = SysTime(
70         DateTime(2018, 1, 1, 10, 30, 0),
71         new immutable SimpleTimeZone(-5.hours, "America/New_York")
72     );
73 
74     // ISO standard time strings
75     assert(ny.toISOString() == "20180101T103000-05:00");
76     assert(ny.toISOExtString() == "2018-01-01T10:30:00-05:00");
77 }
78 
79 // Note: reconsider using specific imports below after
80 // https://issues.dlang.org/show_bug.cgi?id=17630 has been fixed
81 import core.time;// : ClockType, convert, dur, Duration, seconds, TimeException;
82 import std.datetime.date;// : _monthNames, AllowDayOverflow, CmpTimeUnits, Date,
83     //DateTime, DateTimeException, DayOfWeek, enforceValid, getDayOfWeek, maxDay,
84     //Month, splitUnitsFromHNSecs, TimeOfDay, validTimeUnits, yearIsLeapYear;
85 import std.datetime.timezone;// : LocalTime, SimpleTimeZone, TimeZone, UTC;
86 import std.exception : enforce;
87 import std.format : format;
88 import std.range.primitives;
89 import std.traits : isIntegral, isSigned, isSomeString, isNarrowString;
90 
91 version (Windows)
92 {
93     import core.stdc.time : time_t;
94     import core.sys.windows.winbase;
95     import core.sys.windows.winnt;
96     import core.sys.windows.winsock2;
97 }
98 else version (Posix)
99 {
100     import core.sys.posix.signal : timespec;
101     import core.sys.posix.sys.types : time_t;
102 }
103 
104 version (StdUnittest)
105 {
106     import core.exception : AssertError;
107     import std.exception : assertThrown;
108 }
109 
110 
111 @safe unittest
112 {
113     initializeTests();
114 }
115 
116 
117 /++
118     Effectively a namespace to make it clear that the methods it contains are
119     getting the time from the system clock. It cannot be instantiated.
120  +/
121 final class Clock
122 {
123 public:
124 
125     /++
126         Returns the current time in the given time zone.
127 
128         Params:
129             clockType = The $(REF ClockType, core,time) indicates which system
130                         clock to use to get the current time. Very few programs
131                         need to use anything other than the default.
132             tz = The time zone for the SysTime that's returned.
133 
134         Throws:
135             $(REF DateTimeException,std,datetime,date) if it fails to get the
136             time.
137       +/
138     static SysTime currTime(ClockType clockType = ClockType.normal)(immutable TimeZone tz = LocalTime()) @safe
139     {
140         return SysTime(currStdTime!clockType, tz);
141     }
142 
143     @safe unittest
144     {
145         import std.format : format;
146         import core.time;
147         assert(currTime().timezone is LocalTime());
148         assert(currTime(UTC()).timezone is UTC());
149 
150         // core.stdc.time.time does not always use unix time on Windows systems.
151         // In particular, dmc does not use unix time. If we can guarantee that
152         // the MS runtime uses unix time, then we may be able run this test
153         // then, but for now, we're just not going to run this test on Windows.
154         version (Posix)
155         {
156             static import core.stdc.time;
157             static import std.math;
158             immutable unixTimeD = currTime().toUnixTime();
159             immutable unixTimeC = core.stdc.time.time(null);
160             assert(std.math.abs(unixTimeC - unixTimeD) <= 2);
161         }
162 
163         auto norm1 = Clock.currTime;
164         auto norm2 = Clock.currTime(UTC());
165         assert(norm1 <= norm2, format("%s %s", norm1, norm2));
166         assert(abs(norm1 - norm2) <= seconds(2));
167 
168         import std.meta : AliasSeq;
169         static foreach (ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second))
170         {{
171             auto value1 = Clock.currTime!ct;
172             auto value2 = Clock.currTime!ct(UTC());
173             assert(value1 <= value2, format("%s %s (ClockType: %s)", value1, value2, ct));
174             assert(abs(value1 - value2) <= seconds(2), format("ClockType.%s", ct));
175         }}
176     }
177 
178 
179     /++
180         Returns the number of hnsecs since midnight, January 1st, 1 A.D. for the
181         current time.
182 
183         Params:
184             clockType = The $(REF ClockType, core,time) indicates which system
185                         clock to use to get the current time. Very few programs
186                         need to use anything other than the default.
187 
188         Throws:
189             $(REF DateTimeException,std,datetime,date) if it fails to get the
190             time.
191       +/
192     static @property long currStdTime(ClockType clockType = ClockType.normal)() @trusted
193     {
194         static if (clockType != ClockType.coarse &&
195                    clockType != ClockType.normal &&
196                    clockType != ClockType.precise &&
197                    clockType != ClockType.second)
198         {
199             static assert(0, format("ClockType.%s is not supported by Clock.currTime or Clock.currStdTime", clockType));
200         }
201 
202         version (Windows)
203         {
204             FILETIME fileTime;
205             GetSystemTimeAsFileTime(&fileTime);
206             immutable result = FILETIMEToStdTime(&fileTime);
207             static if (clockType == ClockType.second)
208             {
209                 // Ideally, this would use core.std.time.time, but the C runtime
210                 // has to be using unix time for that to work, and that's not
211                 // guaranteed on Windows. Digital Mars does not use unix time.
212                 // MS may or may not. If it does, then this can be made to use
213                 // core.stdc.time for MS, but for now, we'll leave it like this.
214                 return convert!("seconds", "hnsecs")(convert!("hnsecs", "seconds")(result));
215             }
216             else
217                 return result;
218         }
219         else version (Posix)
220         {
221             static import core.stdc.time;
222             enum hnsecsToUnixEpoch = unixTimeToStdTime(0);
223 
224             version (Darwin)
225             {
226                 static if (clockType == ClockType.second)
227                     return unixTimeToStdTime(core.stdc.time.time(null));
228                 else
229                 {
230                     import core.sys.posix.sys.time : gettimeofday, timeval;
231                     timeval tv = void;
232                     // Posix gettimeofday called with a valid timeval address
233                     // and a null second parameter doesn't fail.
234                     gettimeofday(&tv, null);
235                     return convert!("seconds", "hnsecs")(tv.tv_sec) +
236                            tv.tv_usec * 10 +
237                            hnsecsToUnixEpoch;
238                 }
239             }
240             else version (linux)
241             {
242                 static if (clockType == ClockType.second)
243                     return unixTimeToStdTime(core.stdc.time.time(null));
244                 else
245                 {
246                     import core.sys.linux.time : CLOCK_REALTIME_COARSE;
247                     import core.sys.posix.time : clock_gettime, CLOCK_REALTIME;
248                     static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_COARSE;
249                     else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
250                     else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
251                     else static assert(0, "Previous static if is wrong.");
252                     timespec ts = void;
253                     immutable error = clock_gettime(clockArg, &ts);
254                     // Posix clock_gettime called with a valid address and valid clock_id is only
255                     // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
256                     // is long or larger overflow won't happen before 292 billion years A.D.
257                     static if (ts.tv_sec.max < long.max)
258                     {
259                         if (error)
260                             throw new TimeException("Call to clock_gettime() failed");
261                     }
262                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
263                            ts.tv_nsec / 100 +
264                            hnsecsToUnixEpoch;
265                 }
266             }
267             else version (FreeBSD)
268             {
269                 import core.sys.freebsd.time : clock_gettime, CLOCK_REALTIME,
270                     CLOCK_REALTIME_FAST, CLOCK_REALTIME_PRECISE, CLOCK_SECOND;
271                 static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_FAST;
272                 else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
273                 else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME_PRECISE;
274                 else static if (clockType == ClockType.second)  alias clockArg = CLOCK_SECOND;
275                 else static assert(0, "Previous static if is wrong.");
276                 timespec ts = void;
277                 immutable error = clock_gettime(clockArg, &ts);
278                 // Posix clock_gettime called with a valid address and valid clock_id is only
279                 // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
280                 // is long or larger overflow won't happen before 292 billion years A.D.
281                 static if (ts.tv_sec.max < long.max)
282                 {
283                     if (error)
284                         throw new TimeException("Call to clock_gettime() failed");
285                 }
286                 return convert!("seconds", "hnsecs")(ts.tv_sec) +
287                        ts.tv_nsec / 100 +
288                        hnsecsToUnixEpoch;
289             }
290             else version (NetBSD)
291             {
292                 static if (clockType == ClockType.second)
293                     return unixTimeToStdTime(core.stdc.time.time(null));
294                 else
295                 {
296                     import core.sys.netbsd.time : clock_gettime, CLOCK_REALTIME;
297                     timespec ts = void;
298                     immutable error = clock_gettime(CLOCK_REALTIME, &ts);
299                     // Posix clock_gettime called with a valid address and valid clock_id is only
300                     // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
301                     // is long or larger overflow won't happen before 292 billion years A.D.
302                     static if (ts.tv_sec.max < long.max)
303                     {
304                         if (error)
305                             throw new TimeException("Call to clock_gettime() failed");
306                     }
307                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
308                            ts.tv_nsec / 100 +
309                            hnsecsToUnixEpoch;
310                 }
311             }
312             else version (DragonFlyBSD)
313             {
314                 import core.sys.dragonflybsd.time : clock_gettime, CLOCK_REALTIME,
315                     CLOCK_REALTIME_FAST, CLOCK_REALTIME_PRECISE, CLOCK_SECOND;
316                 static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_FAST;
317                 else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
318                 else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME_PRECISE;
319                 else static if (clockType == ClockType.second)  alias clockArg = CLOCK_SECOND;
320                 else static assert(0, "Previous static if is wrong.");
321                 timespec ts = void;
322                 immutable error = clock_gettime(clockArg, &ts);
323                 // Posix clock_gettime called with a valid address and valid clock_id is only
324                 // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
325                 // is long or larger overflow won't happen before 292 billion years A.D.
326                 static if (ts.tv_sec.max < long.max)
327                 {
328                     if (error)
329                         throw new TimeException("Call to clock_gettime() failed");
330                 }
331                 return convert!("seconds", "hnsecs")(ts.tv_sec) +
332                        ts.tv_nsec / 100 +
333                        hnsecsToUnixEpoch;
334             }
335             else version (Solaris)
336             {
337                 static if (clockType == ClockType.second)
338                     return unixTimeToStdTime(core.stdc.time.time(null));
339                 else
340                 {
341                     import core.sys.solaris.time : clock_gettime, CLOCK_REALTIME;
342                     static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME;
343                     else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
344                     else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
345                     else static assert(0, "Previous static if is wrong.");
346                     timespec ts = void;
347                     immutable error = clock_gettime(clockArg, &ts);
348                     // Posix clock_gettime called with a valid address and valid clock_id is only
349                     // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
350                     // is long or larger overflow won't happen before 292 billion years A.D.
351                     static if (ts.tv_sec.max < long.max)
352                     {
353                         if (error)
354                             throw new TimeException("Call to clock_gettime() failed");
355                     }
356                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
357                            ts.tv_nsec / 100 +
358                            hnsecsToUnixEpoch;
359                 }
360             }
361             else static assert(0, "Unsupported OS");
362         }
363         else static assert(0, "Unsupported OS");
364     }
365 
366     @safe unittest
367     {
368         import std.format : format;
369         import std.math : abs;
370         import std.meta : AliasSeq;
371         enum limit = convert!("seconds", "hnsecs")(2);
372 
373         auto norm1 = Clock.currStdTime;
374         auto norm2 = Clock.currStdTime;
375         assert(norm1 <= norm2, format("%s %s", norm1, norm2));
376         assert(abs(norm1 - norm2) <= limit);
377 
378         static foreach (ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second))
379         {{
380             auto value1 = Clock.currStdTime!ct;
381             auto value2 = Clock.currStdTime!ct;
382             assert(value1 <= value2, format("%s %s (ClockType: %s)", value1, value2, ct));
383             assert(abs(value1 - value2) <= limit);
384         }}
385     }
386 
387 
388 private:
389 
390     @disable this();
391 }
392 
393 /// Get the current time as a $(LREF SysTime)
394 @safe unittest
395 {
396     import std.datetime.timezone : LocalTime;
397     SysTime today = Clock.currTime();
398     assert(today.timezone is LocalTime());
399 }
400 
401 
402 /++
403     `SysTime` is the type used to get the current time from the
404     system or doing anything that involves time zones. Unlike
405     $(REF DateTime,std,datetime,date), the time zone is an integral part of
406     `SysTime` (though for local time applications, time zones can be ignored
407     and it will work, since it defaults to using the local time zone). It holds
408     its internal time in std time (hnsecs since midnight, January 1st, 1 A.D.
409     UTC), so it interfaces well with the system time. However, that means that,
410     unlike $(REF DateTime,std,datetime,date), it is not optimized for
411     calendar-based operations, and getting individual units from it such as
412     years or days is going to involve conversions and be less efficient.
413 
414     For calendar-based operations that don't
415     care about time zones, then $(REF DateTime,std,datetime,date) would be
416     the type to use. For system time, use `SysTime`.
417 
418     $(LREF Clock.currTime) will return the current time as a `SysTime`.
419     To convert a `SysTime` to a $(REF Date,std,datetime,date) or
420     $(REF DateTime,std,datetime,date), simply cast it. To convert a
421     $(REF Date,std,datetime,date) or $(REF DateTime,std,datetime,date) to a
422     `SysTime`, use `SysTime`'s constructor, and pass in the intended time
423     zone with it (or don't pass in a $(REF TimeZone,std,datetime,timezone), and
424     the local time zone will be used). Be aware, however, that converting from a
425     $(REF DateTime,std,datetime,date) to a `SysTime` will not necessarily
426     be 100% accurate due to DST (one hour of the year doesn't exist and another
427     occurs twice). To not risk any conversion errors, keep times as
428     `SysTime`s. Aside from DST though, there shouldn't be any conversion
429     problems.
430 
431     For using time zones other than local time or UTC, use
432     $(REF PosixTimeZone,std,datetime,timezone) on Posix systems (or on Windows,
433     if providing the TZ Database files), and use
434     $(REF WindowsTimeZone,std,datetime,timezone) on Windows systems. The time in
435     `SysTime` is kept internally in hnsecs from midnight, January 1st, 1 A.D.
436     UTC. Conversion error cannot happen when changing the time zone of a
437     `SysTime`. $(REF LocalTime,std,datetime,timezone) is the
438     $(REF TimeZone,std,datetime,timezone) class which represents the local time,
439     and `UTC` is the $(REF TimeZone,std,datetime,timezone) class which
440     represents UTC. `SysTime` uses $(REF LocalTime,std,datetime,timezone) if
441     no $(REF TimeZone,std,datetime,timezone) is provided. For more details on
442     time zones, see the documentation for $(REF TimeZone,std,datetime,timezone),
443     $(REF PosixTimeZone,std,datetime,timezone), and
444     $(REF WindowsTimeZone,std,datetime,timezone).
445 
446     `SysTime`'s range is from approximately 29,000 B.C. to approximately
447     29,000 A.D.
448   +/
449 struct SysTime
450 {
451     import core.stdc.time : tm;
452     version (Posix) import core.sys.posix.sys.time : timeval;
453     import std.typecons : Rebindable;
454 
455 public:
456 
457     /++
458         Params:
459             dateTime = The $(REF DateTime,std,datetime,date) to use to set
460                        this $(LREF SysTime)'s internal std time. As
461                        $(REF DateTime,std,datetime,date) has no concept of
462                        time zone, tz is used as its time zone.
463             tz       = The $(REF TimeZone,std,datetime,timezone) to use for this
464                        $(LREF SysTime). If null,
465                        $(REF LocalTime,std,datetime,timezone) will be used. The
466                        given $(REF DateTime,std,datetime,date) is assumed to
467                        be in the given time zone.
468       +/
469     this(DateTime dateTime, immutable TimeZone tz = null) @safe nothrow
470     {
471         try
472             this(dateTime, Duration.zero, tz);
473         catch (Exception e)
474             assert(0, "SysTime's constructor threw when it shouldn't have.");
475     }
476 
477     @safe unittest
478     {
479         static void test(DateTime dt, immutable TimeZone tz, long expected)
480         {
481             auto sysTime = SysTime(dt, tz);
482             assert(sysTime._stdTime == expected);
483             assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given DateTime: %s", dt));
484         }
485 
486         test(DateTime.init, UTC(), 0);
487         test(DateTime(1, 1, 1, 12, 30, 33), UTC(), 450_330_000_000L);
488         test(DateTime(0, 12, 31, 12, 30, 33), UTC(), -413_670_000_000L);
489         test(DateTime(1, 1, 1, 0, 0, 0), UTC(), 0);
490         test(DateTime(1, 1, 1, 0, 0, 1), UTC(), 10_000_000L);
491         test(DateTime(0, 12, 31, 23, 59, 59), UTC(), -10_000_000L);
492 
493         test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(dur!"minutes"(-60)), 36_000_000_000L);
494         test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(Duration.zero), 0);
495         test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(dur!"minutes"(60)), -36_000_000_000L);
496 
497         static void testScope(scope ref DateTime dt) @safe
498         {
499             auto st = SysTime(dt);
500         }
501     }
502 
503     /++
504         Params:
505             dateTime = The $(REF DateTime,std,datetime,date) to use to set
506                        this $(LREF SysTime)'s internal std time. As
507                        $(REF DateTime,std,datetime,date) has no concept of
508                        time zone, tz is used as its time zone.
509             fracSecs = The fractional seconds portion of the time.
510             tz       = The $(REF TimeZone,std,datetime,timezone) to use for this
511                        $(LREF SysTime). If null,
512                        $(REF LocalTime,std,datetime,timezone) will be used. The
513                        given $(REF DateTime,std,datetime,date) is assumed to
514                        be in the given time zone.
515 
516         Throws:
517             $(REF DateTimeException,std,datetime,date) if `fracSecs` is negative or if it's
518             greater than or equal to one second.
519       +/
520     this(DateTime dateTime, Duration fracSecs, immutable TimeZone tz = null) @safe
521     {
522         enforce(fracSecs >= Duration.zero, new DateTimeException("A SysTime cannot have negative fractional seconds."));
523         enforce(fracSecs < seconds(1), new DateTimeException("Fractional seconds must be less than one second."));
524         auto nonNullTZ = tz is null ? LocalTime() : tz;
525 
526         immutable dateDiff = dateTime.date - Date.init;
527         immutable todDiff = dateTime.timeOfDay - TimeOfDay.init;
528 
529         immutable adjustedTime = dateDiff + todDiff + fracSecs;
530         immutable standardTime = nonNullTZ.tzToUTC(adjustedTime.total!"hnsecs");
531 
532         this(standardTime, nonNullTZ);
533     }
534 
535     @safe unittest
536     {
537         import core.time;
538         static void test(DateTime dt, Duration fracSecs, immutable TimeZone tz, long expected)
539         {
540             auto sysTime = SysTime(dt, fracSecs, tz);
541             assert(sysTime._stdTime == expected);
542             assert(sysTime._timezone is (tz is null ? LocalTime() : tz),
543                    format("Given DateTime: %s, Given Duration: %s", dt, fracSecs));
544         }
545 
546         test(DateTime.init, Duration.zero, UTC(), 0);
547         test(DateTime(1, 1, 1, 12, 30, 33), Duration.zero, UTC(), 450_330_000_000L);
548         test(DateTime(0, 12, 31, 12, 30, 33), Duration.zero, UTC(), -413_670_000_000L);
549         test(DateTime(1, 1, 1, 0, 0, 0), msecs(1), UTC(), 10_000L);
550         test(DateTime(0, 12, 31, 23, 59, 59), msecs(999), UTC(), -10_000L);
551 
552         test(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC(), -1);
553         test(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC(), -9_999_999);
554         test(DateTime(0, 12, 31, 23, 59, 59), Duration.zero, UTC(), -10_000_000);
555 
556         assertThrown!DateTimeException(SysTime(DateTime.init, hnsecs(-1), UTC()));
557         assertThrown!DateTimeException(SysTime(DateTime.init, seconds(1), UTC()));
558 
559         static void testScope(scope ref DateTime dt, scope ref Duration d) @safe
560         {
561             auto st = SysTime(dt, d);
562         }
563     }
564 
565     /++
566         Params:
567             date = The $(REF Date,std,datetime,date) to use to set this
568                    $(LREF SysTime)'s internal std time. As
569                    $(REF Date,std,datetime,date) has no concept of time zone, tz
570                    is used as its time zone.
571             tz   = The $(REF TimeZone,std,datetime,timezone) to use for this
572                    $(LREF SysTime). If null,
573                    $(REF LocalTime,std,datetime,timezone) will be used. The
574                    given $(REF Date,std,datetime,date) is assumed to be in the
575                    given time zone.
576       +/
577     this(Date date, immutable TimeZone tz = null) @safe nothrow
578     {
579         _timezone = tz is null ? LocalTime() : tz;
580 
581         try
582         {
583             immutable adjustedTime = (date - Date(1, 1, 1)).total!"hnsecs";
584             immutable standardTime = _timezone.tzToUTC(adjustedTime);
585 
586             this(standardTime, _timezone);
587         }
588         catch (Exception e)
589             assert(0, "Date's constructor through when it shouldn't have.");
590     }
591 
592     @safe unittest
593     {
594         static void test(Date d, immutable TimeZone tz, long expected)
595         {
596             auto sysTime = SysTime(d, tz);
597             assert(sysTime._stdTime == expected);
598             assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given Date: %s", d));
599         }
600 
601         test(Date.init, UTC(), 0);
602         test(Date(1, 1, 1), UTC(), 0);
603         test(Date(1, 1, 2), UTC(), 864000000000);
604         test(Date(0, 12, 31), UTC(), -864000000000);
605 
606         static void testScope(scope ref Date d) @safe
607         {
608             auto st = SysTime(d);
609         }
610     }
611 
612     /++
613         Note:
614             Whereas the other constructors take in the given date/time, assume
615             that it's in the given time zone, and convert it to hnsecs in UTC
616             since midnight, January 1st, 1 A.D. UTC - i.e. std time - this
617             constructor takes a std time, which is specifically already in UTC,
618             so no conversion takes place. Of course, the various getter
619             properties and functions will use the given time zone's conversion
620             function to convert the results to that time zone, but no conversion
621             of the arguments to this constructor takes place.
622 
623         Params:
624             stdTime = The number of hnsecs since midnight, January 1st, 1 A.D.
625                       UTC.
626             tz      = The $(REF TimeZone,std,datetime,timezone) to use for this
627                       $(LREF SysTime). If null,
628                       $(REF LocalTime,std,datetime,timezone) will be used.
629       +/
630     this(long stdTime, immutable TimeZone tz = null) @safe pure nothrow
631     {
632         _stdTime = stdTime;
633         _timezone = tz is null ? LocalTime() : tz;
634     }
635 
636     @safe unittest
637     {
638         static void test(long stdTime, immutable TimeZone tz)
639         {
640             auto sysTime = SysTime(stdTime, tz);
641             assert(sysTime._stdTime == stdTime);
642             assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given stdTime: %s", stdTime));
643         }
644 
645         foreach (stdTime; [-1234567890L, -250, 0, 250, 1235657390L])
646         {
647             foreach (tz; testTZs)
648                 test(stdTime, tz);
649         }
650     }
651 
652 
653     /++
654         Params:
655             rhs = The $(LREF SysTime) to assign to this one.
656 
657         Returns: The `this` of this `SysTime`.
658       +/
659     ref SysTime opAssign()(auto ref const(SysTime) rhs) return @safe pure nothrow scope
660     {
661         _stdTime = rhs._stdTime;
662         _timezone = rhs._timezone;
663         return this;
664     }
665 
666     @safe unittest
667     {
668         SysTime st;
669         st = SysTime(DateTime(2012, 12, 21, 1, 2, 3), UTC());
670         assert(st == SysTime(DateTime(2012, 12, 21, 1, 2, 3), UTC()));
671 
672         const other = SysTime(DateTime(19, 1, 7, 13, 14, 15), LocalTime());
673         st = other;
674         assert(st == other);
675 
676         static void testScope(scope ref SysTime left, const scope SysTime right) @safe
677         {
678             left = right;
679         }
680     }
681 
682 
683     /++
684         Checks for equality between this $(LREF SysTime) and the given
685         $(LREF SysTime).
686 
687         Note that the time zone is ignored. Only the internal
688         std times (which are in UTC) are compared.
689      +/
690     bool opEquals()(auto ref const(SysTime) rhs) @safe const pure nothrow scope
691     {
692         return _stdTime == rhs._stdTime;
693     }
694 
695     @safe unittest
696     {
697         import std.range : chain;
698 
699         assert(SysTime(DateTime.init, UTC()) == SysTime(0, UTC()));
700         assert(SysTime(DateTime.init, UTC()) == SysTime(0));
701         assert(SysTime(Date.init, UTC()) == SysTime(0));
702         assert(SysTime(0) == SysTime(0));
703 
704         static void test(DateTime dt, immutable TimeZone tz1, immutable TimeZone tz2)
705         {
706             auto st1 = SysTime(dt);
707             st1.timezone = tz1;
708 
709             auto st2 = SysTime(dt);
710             st2.timezone = tz2;
711 
712             assert(st1 == st2);
713         }
714 
715         foreach (tz1; testTZs)
716         {
717             foreach (tz2; testTZs)
718             {
719                 foreach (dt; chain(testDateTimesBC, testDateTimesAD))
720                     test(dt, tz1, tz2);
721             }
722         }
723 
724         auto st = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
725         const cst = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
726         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
727         assert(st == st);
728         assert(st == cst);
729         assert(st == ist);
730         assert(cst == st);
731         assert(cst == cst);
732         assert(cst == ist);
733         assert(ist == st);
734         assert(ist == cst);
735         assert(ist == ist);
736 
737         static void testScope(scope ref SysTime left, const scope SysTime right) @safe
738         {
739             assert(left == right);
740             assert(right == left);
741         }
742     }
743 
744 
745     /++
746         Compares this $(LREF SysTime) with the given $(LREF SysTime).
747 
748         Time zone is irrelevant when comparing $(LREF SysTime)s.
749 
750         Returns:
751             $(BOOKTABLE,
752             $(TR $(TD this &lt; rhs) $(TD &lt; 0))
753             $(TR $(TD this == rhs) $(TD 0))
754             $(TR $(TD this &gt; rhs) $(TD &gt; 0))
755             )
756      +/
757     int opCmp()(auto ref const(SysTime) rhs) @safe const pure nothrow scope
758     {
759         if (_stdTime < rhs._stdTime)
760             return -1;
761         if (_stdTime > rhs._stdTime)
762             return 1;
763         return 0;
764     }
765 
766     @safe unittest
767     {
768         import std.algorithm.iteration : map;
769         import std.array : array;
770         import std.range : chain;
771 
772         assert(SysTime(DateTime.init, UTC()).opCmp(SysTime(0, UTC())) == 0);
773         assert(SysTime(DateTime.init, UTC()).opCmp(SysTime(0)) == 0);
774         assert(SysTime(Date.init, UTC()).opCmp(SysTime(0)) == 0);
775         assert(SysTime(0).opCmp(SysTime(0)) == 0);
776 
777         static void testEqual(SysTime st, immutable TimeZone tz1, immutable TimeZone tz2)
778         {
779             auto st1 = st;
780             st1.timezone = tz1;
781 
782             auto st2 = st;
783             st2.timezone = tz2;
784 
785             assert(st1.opCmp(st2) == 0);
786         }
787 
788         auto sts = array(map!SysTime(chain(testDateTimesBC, testDateTimesAD)));
789 
790         foreach (st; sts)
791         {
792             foreach (tz1; testTZs)
793             {
794                 foreach (tz2; testTZs)
795                     testEqual(st, tz1, tz2);
796             }
797         }
798 
799         static void testCmp(SysTime st1, immutable TimeZone tz1, SysTime st2, immutable TimeZone tz2)
800         {
801             st1.timezone = tz1;
802             st2.timezone = tz2;
803             assert(st1.opCmp(st2) < 0);
804             assert(st2.opCmp(st1) > 0);
805         }
806 
807         foreach (si, st1; sts)
808         {
809             foreach (st2; sts[si + 1 .. $])
810             {
811                 foreach (tz1; testTZs)
812                 {
813                     foreach (tz2; testTZs)
814                         testCmp(st1, tz1, st2, tz2);
815                 }
816             }
817         }
818 
819         auto st = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
820         const cst = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
821         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
822         assert(st.opCmp(st) == 0);
823         assert(st.opCmp(cst) == 0);
824         assert(st.opCmp(ist) == 0);
825         assert(cst.opCmp(st) == 0);
826         assert(cst.opCmp(cst) == 0);
827         assert(cst.opCmp(ist) == 0);
828         assert(ist.opCmp(st) == 0);
829         assert(ist.opCmp(cst) == 0);
830         assert(ist.opCmp(ist) == 0);
831 
832         static void testScope(scope ref SysTime left, const scope SysTime right) @safe
833         {
834             assert(left < right);
835             assert(right > left);
836         }
837     }
838 
839 
840     /++
841         Returns: A hash of the $(LREF SysTime).
842      +/
843     size_t toHash() const @nogc pure nothrow @safe scope
844     {
845         static if (is(size_t == ulong))
846             return _stdTime;
847         else
848         {
849             // MurmurHash2
850             enum ulong m = 0xc6a4a7935bd1e995UL;
851             enum ulong n = m * 16;
852             enum uint r = 47;
853 
854             ulong k = _stdTime;
855             k *= m;
856             k ^= k >> r;
857             k *= m;
858 
859             ulong h = n;
860             h ^= k;
861             h *= m;
862 
863             return cast(size_t) h;
864         }
865     }
866 
867     @safe unittest
868     {
869         assert(SysTime(0).toHash == SysTime(0).toHash);
870         assert(SysTime(DateTime(2000, 1, 1)).toHash == SysTime(DateTime(2000, 1, 1)).toHash);
871         assert(SysTime(DateTime(2000, 1, 1)).toHash != SysTime(DateTime(2000, 1, 2)).toHash);
872 
873         // test that timezones aren't taken into account
874         assert(SysTime(0, LocalTime()).toHash == SysTime(0, LocalTime()).toHash);
875         assert(SysTime(0, LocalTime()).toHash == SysTime(0, UTC()).toHash);
876         assert(SysTime(DateTime(2000, 1, 1), LocalTime()).toHash == SysTime(DateTime(2000, 1, 1), LocalTime()).toHash);
877         immutable zone = new SimpleTimeZone(dur!"minutes"(60));
878         assert(SysTime(DateTime(2000, 1, 1, 1), zone).toHash == SysTime(DateTime(2000, 1, 1), UTC()).toHash);
879         assert(SysTime(DateTime(2000, 1, 1), zone).toHash != SysTime(DateTime(2000, 1, 1), UTC()).toHash);
880 
881         static void testScope(scope ref SysTime st) @safe
882         {
883             auto result = st.toHash();
884         }
885     }
886 
887 
888     /++
889         Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
890         are B.C.
891      +/
892     @property short year() @safe const nothrow scope
893     {
894         return (cast(Date) this).year;
895     }
896 
897     @safe unittest
898     {
899         import std.range : chain;
900         static void test(SysTime sysTime, long expected)
901         {
902             assert(sysTime.year == expected, format("Value given: %s", sysTime));
903         }
904 
905         test(SysTime(0, UTC()), 1);
906         test(SysTime(1, UTC()), 1);
907         test(SysTime(-1, UTC()), 0);
908 
909         foreach (year; chain(testYearsBC, testYearsAD))
910         {
911             foreach (md; testMonthDays)
912             {
913                 foreach (tod; testTODs)
914                 {
915                     auto dt = DateTime(Date(year, md.month, md.day), tod);
916                     foreach (tz; testTZs)
917                     {
918                         foreach (fs; testFracSecs)
919                             test(SysTime(dt, fs, tz), year);
920                     }
921                 }
922             }
923         }
924 
925         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
926         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
927         assert(cst.year == 1999);
928         assert(ist.year == 1999);
929 
930         static void testScope(scope ref SysTime st) @safe
931         {
932             auto result = st.year;
933         }
934     }
935 
936     /++
937         Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
938         are B.C.
939 
940         Params:
941             year = The year to set this $(LREF SysTime)'s year to.
942 
943         Throws:
944             $(REF DateTimeException,std,datetime,date) if the new year is not
945             a leap year and the resulting date would be on February 29th.
946      +/
947     @property void year(int year) @safe scope
948     {
949         auto hnsecs = adjTime;
950         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
951 
952         if (hnsecs < 0)
953         {
954             hnsecs += convert!("hours", "hnsecs")(24);
955             --days;
956         }
957 
958         auto date = Date(cast(int) days);
959         date.year = year;
960 
961         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
962         adjTime = newDaysHNSecs + hnsecs;
963     }
964 
965     ///
966     @safe unittest
967     {
968         import std.datetime.date : DateTime;
969 
970         assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).year == 1999);
971         assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).year == 2010);
972         assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).year == -7);
973     }
974 
975     @safe unittest
976     {
977         import std.range : chain;
978 
979         static void test(SysTime st, int year, SysTime expected)
980         {
981             st.year = year;
982             assert(st == expected);
983         }
984 
985         foreach (st; chain(testSysTimesBC, testSysTimesAD))
986         {
987             auto dt = cast(DateTime) st;
988 
989             foreach (year; chain(testYearsBC, testYearsAD))
990             {
991                 auto e = SysTime(DateTime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second),
992                                  st.fracSecs,
993                                  st.timezone);
994                 test(st, year, e);
995             }
996         }
997 
998         foreach (fs; testFracSecs)
999         {
1000             foreach (tz; testTZs)
1001             {
1002                 foreach (tod; testTODs)
1003                 {
1004                     test(SysTime(DateTime(Date(1999, 2, 28), tod), fs, tz), 2000,
1005                          SysTime(DateTime(Date(2000, 2, 28), tod), fs, tz));
1006                     test(SysTime(DateTime(Date(2000, 2, 28), tod), fs, tz), 1999,
1007                          SysTime(DateTime(Date(1999, 2, 28), tod), fs, tz));
1008                 }
1009 
1010                 foreach (tod; testTODsThrown)
1011                 {
1012                     auto st = SysTime(DateTime(Date(2000, 2, 29), tod), fs, tz);
1013                     assertThrown!DateTimeException(st.year = 1999);
1014                 }
1015             }
1016         }
1017 
1018         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1019         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1020         static assert(!__traits(compiles, cst.year = 7));
1021         static assert(!__traits(compiles, ist.year = 7));
1022 
1023         static void testScope(scope ref SysTime st) @safe
1024         {
1025             st.year = 42;
1026         }
1027     }
1028 
1029     /++
1030         Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
1031 
1032         Throws:
1033             $(REF DateTimeException,std,datetime,date) if `isAD` is true.
1034      +/
1035     @property ushort yearBC() @safe const scope
1036     {
1037         return (cast(Date) this).yearBC;
1038     }
1039 
1040     ///
1041     @safe unittest
1042     {
1043         import std.datetime.date : DateTime;
1044 
1045         assert(SysTime(DateTime(0, 1, 1, 12, 30, 33)).yearBC == 1);
1046         assert(SysTime(DateTime(-1, 1, 1, 10, 7, 2)).yearBC == 2);
1047         assert(SysTime(DateTime(-100, 1, 1, 4, 59, 0)).yearBC == 101);
1048     }
1049 
1050     @safe unittest
1051     {
1052         import std.exception : assertNotThrown;
1053         foreach (st; testSysTimesBC)
1054         {
1055             auto msg = format("SysTime: %s", st);
1056             assertNotThrown!DateTimeException(st.yearBC, msg);
1057             assert(st.yearBC == (st.year * -1) + 1, msg);
1058         }
1059 
1060         foreach (st; [testSysTimesAD[0], testSysTimesAD[$/2], testSysTimesAD[$-1]])
1061             assertThrown!DateTimeException(st.yearBC, format("SysTime: %s", st));
1062 
1063         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1064         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1065         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1066         st.year = 12;
1067         assert(st.year == 12);
1068         static assert(!__traits(compiles, cst.year = 12));
1069         static assert(!__traits(compiles, ist.year = 12));
1070 
1071         static void testScope(scope ref SysTime st) @safe
1072         {
1073             auto result = st.yearBC;
1074         }
1075     }
1076 
1077 
1078     /++
1079         Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
1080 
1081         Params:
1082             year = The year B.C. to set this $(LREF SysTime)'s year to.
1083 
1084         Throws:
1085             $(REF DateTimeException,std,datetime,date) if a non-positive value
1086             is given.
1087      +/
1088     @property void yearBC(int year) @safe scope
1089     {
1090         auto hnsecs = adjTime;
1091         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1092 
1093         if (hnsecs < 0)
1094         {
1095             hnsecs += convert!("hours", "hnsecs")(24);
1096             --days;
1097         }
1098 
1099         auto date = Date(cast(int) days);
1100         date.yearBC = year;
1101 
1102         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
1103         adjTime = newDaysHNSecs + hnsecs;
1104     }
1105 
1106     @safe unittest
1107     {
1108         auto st = SysTime(DateTime(2010, 1, 1, 7, 30, 0));
1109         st.yearBC = 1;
1110         assert(st == SysTime(DateTime(0, 1, 1, 7, 30, 0)));
1111 
1112         st.yearBC = 10;
1113         assert(st == SysTime(DateTime(-9, 1, 1, 7, 30, 0)));
1114     }
1115 
1116     @safe unittest
1117     {
1118         import std.range : chain;
1119         static void test(SysTime st, int year, SysTime expected)
1120         {
1121             st.yearBC = year;
1122             assert(st == expected, format("SysTime: %s", st));
1123         }
1124 
1125         foreach (st; chain(testSysTimesBC, testSysTimesAD))
1126         {
1127             auto dt = cast(DateTime) st;
1128 
1129             foreach (year; testYearsBC)
1130             {
1131                 auto e = SysTime(DateTime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second),
1132                                  st.fracSecs,
1133                                  st.timezone);
1134                 test(st, (year * -1) + 1, e);
1135             }
1136         }
1137 
1138         foreach (st; [testSysTimesBC[0], testSysTimesBC[$ - 1], testSysTimesAD[0], testSysTimesAD[$ - 1]])
1139         {
1140             foreach (year; testYearsBC)
1141                 assertThrown!DateTimeException(st.yearBC = year);
1142         }
1143 
1144         foreach (fs; testFracSecs)
1145         {
1146             foreach (tz; testTZs)
1147             {
1148                 foreach (tod; testTODs)
1149                 {
1150                     test(SysTime(DateTime(Date(-1999, 2, 28), tod), fs, tz), 2001,
1151                          SysTime(DateTime(Date(-2000, 2, 28), tod), fs, tz));
1152                     test(SysTime(DateTime(Date(-2000, 2, 28), tod), fs, tz), 2000,
1153                          SysTime(DateTime(Date(-1999, 2, 28), tod), fs, tz));
1154                 }
1155 
1156                 foreach (tod; testTODsThrown)
1157                 {
1158                     auto st = SysTime(DateTime(Date(-2000, 2, 29), tod), fs, tz);
1159                     assertThrown!DateTimeException(st.year = -1999);
1160                 }
1161             }
1162         }
1163 
1164         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1165         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1166         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1167         st.yearBC = 12;
1168         assert(st.yearBC == 12);
1169         static assert(!__traits(compiles, cst.yearBC = 12));
1170         static assert(!__traits(compiles, ist.yearBC = 12));
1171 
1172         static void testScope(scope ref SysTime st) @safe
1173         {
1174             st.yearBC = 42;
1175         }
1176     }
1177 
1178 
1179     /++
1180         Month of a Gregorian Year.
1181      +/
1182     @property Month month() @safe const nothrow scope
1183     {
1184         return (cast(Date) this).month;
1185     }
1186 
1187     ///
1188     @safe unittest
1189     {
1190         import std.datetime.date : DateTime;
1191 
1192         assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).month == 7);
1193         assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).month == 10);
1194         assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).month == 4);
1195     }
1196 
1197     @safe unittest
1198     {
1199         import std.range : chain;
1200 
1201         static void test(SysTime sysTime, Month expected)
1202         {
1203             assert(sysTime.month == expected, format("Value given: %s", sysTime));
1204         }
1205 
1206         test(SysTime(0, UTC()), Month.jan);
1207         test(SysTime(1, UTC()), Month.jan);
1208         test(SysTime(-1, UTC()), Month.dec);
1209 
1210         foreach (year; chain(testYearsBC, testYearsAD))
1211         {
1212             foreach (md; testMonthDays)
1213             {
1214                 foreach (tod; testTODs)
1215                 {
1216                     auto dt = DateTime(Date(year, md.month, md.day), tod);
1217                     foreach (fs; testFracSecs)
1218                     {
1219                         foreach (tz; testTZs)
1220                             test(SysTime(dt, fs, tz), md.month);
1221                     }
1222                 }
1223             }
1224         }
1225 
1226         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1227         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1228         assert(cst.month == 7);
1229         assert(ist.month == 7);
1230 
1231         static void testScope(scope ref SysTime st) @safe
1232         {
1233             auto result = st.month;
1234         }
1235     }
1236 
1237 
1238     /++
1239         Month of a Gregorian Year.
1240 
1241         Params:
1242             month = The month to set this $(LREF SysTime)'s month to.
1243 
1244         Throws:
1245             $(REF DateTimeException,std,datetime,date) if the given month is
1246             not a valid month.
1247      +/
1248     @property void month(Month month) @safe scope
1249     {
1250         auto hnsecs = adjTime;
1251         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1252 
1253         if (hnsecs < 0)
1254         {
1255             hnsecs += convert!("hours", "hnsecs")(24);
1256             --days;
1257         }
1258 
1259         auto date = Date(cast(int) days);
1260         date.month = month;
1261 
1262         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
1263         adjTime = newDaysHNSecs + hnsecs;
1264     }
1265 
1266     @safe unittest
1267     {
1268         import std.algorithm.iteration : filter;
1269         import std.range : chain;
1270 
1271         static void test(SysTime st, Month month, SysTime expected)
1272         {
1273             st.month = cast(Month) month;
1274             assert(st == expected);
1275         }
1276 
1277         foreach (st; chain(testSysTimesBC, testSysTimesAD))
1278         {
1279             auto dt = cast(DateTime) st;
1280 
1281             foreach (md; testMonthDays)
1282             {
1283                 if (st.day > maxDay(dt.year, md.month))
1284                     continue;
1285                 auto e = SysTime(DateTime(dt.year, md.month, dt.day, dt.hour, dt.minute, dt.second),
1286                                  st.fracSecs,
1287                                  st.timezone);
1288                 test(st, md.month, e);
1289             }
1290         }
1291 
1292         foreach (fs; testFracSecs)
1293         {
1294             foreach (tz; testTZs)
1295             {
1296                 foreach (tod; testTODs)
1297                 {
1298                     foreach (year; filter!((a){return yearIsLeapYear(a);}) (chain(testYearsBC, testYearsAD)))
1299                     {
1300                         test(SysTime(DateTime(Date(year, 1, 29), tod), fs, tz),
1301                              Month.feb,
1302                              SysTime(DateTime(Date(year, 2, 29), tod), fs, tz));
1303                     }
1304 
1305                     foreach (year; chain(testYearsBC, testYearsAD))
1306                     {
1307                         test(SysTime(DateTime(Date(year, 1, 28), tod), fs, tz),
1308                              Month.feb,
1309                              SysTime(DateTime(Date(year, 2, 28), tod), fs, tz));
1310                         test(SysTime(DateTime(Date(year, 7, 30), tod), fs, tz),
1311                              Month.jun,
1312                              SysTime(DateTime(Date(year, 6, 30), tod), fs, tz));
1313                     }
1314                 }
1315             }
1316         }
1317 
1318         foreach (fs; [testFracSecs[0], testFracSecs[$-1]])
1319         {
1320             foreach (tz; testTZs)
1321             {
1322                 foreach (tod; testTODsThrown)
1323                 {
1324                     foreach (year; [testYearsBC[$-3], testYearsBC[$-2],
1325                                     testYearsBC[$-2], testYearsAD[0],
1326                                     testYearsAD[$-2], testYearsAD[$-1]])
1327                     {
1328                         auto day = yearIsLeapYear(year) ? 30 : 29;
1329                         auto st1 = SysTime(DateTime(Date(year, 1, day), tod), fs, tz);
1330                         assertThrown!DateTimeException(st1.month = Month.feb);
1331 
1332                         auto st2 = SysTime(DateTime(Date(year, 7, 31), tod), fs, tz);
1333                         assertThrown!DateTimeException(st2.month = Month.jun);
1334                     }
1335                 }
1336             }
1337         }
1338 
1339         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1340         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1341         static assert(!__traits(compiles, cst.month = Month.dec));
1342         static assert(!__traits(compiles, ist.month = Month.dec));
1343 
1344         static void testScope(scope ref SysTime st) @safe
1345         {
1346             st.month = Month.dec;
1347         }
1348     }
1349 
1350     /++
1351         Day of a Gregorian Month.
1352      +/
1353     @property ubyte day() @safe const nothrow scope
1354     {
1355         return (cast(Date) this).day;
1356     }
1357 
1358     ///
1359     @safe unittest
1360     {
1361         import std.datetime.date : DateTime;
1362 
1363         assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).day == 6);
1364         assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).day == 4);
1365         assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).day == 5);
1366     }
1367 
1368     @safe unittest
1369     {
1370         import std.range : chain;
1371 
1372         static void test(SysTime sysTime, int expected)
1373         {
1374             assert(sysTime.day == expected, format("Value given: %s", sysTime));
1375         }
1376 
1377         test(SysTime(0, UTC()), 1);
1378         test(SysTime(1, UTC()), 1);
1379         test(SysTime(-1, UTC()), 31);
1380 
1381         foreach (year; chain(testYearsBC, testYearsAD))
1382         {
1383             foreach (md; testMonthDays)
1384             {
1385                 foreach (tod; testTODs)
1386                 {
1387                     auto dt = DateTime(Date(year, md.month, md.day), tod);
1388 
1389                     foreach (tz; testTZs)
1390                     {
1391                         foreach (fs; testFracSecs)
1392                             test(SysTime(dt, fs, tz), md.day);
1393                     }
1394                 }
1395             }
1396         }
1397 
1398         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1399         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1400          assert(cst.day == 6);
1401         assert(ist.day == 6);
1402 
1403         static void testScope(scope ref SysTime st) @safe
1404         {
1405             auto result = st.day;
1406         }
1407     }
1408 
1409 
1410     /++
1411         Day of a Gregorian Month.
1412 
1413         Params:
1414             day = The day of the month to set this $(LREF SysTime)'s day to.
1415 
1416         Throws:
1417             $(REF DateTimeException,std,datetime,date) if the given day is not
1418             a valid day of the current month.
1419      +/
1420     @property void day(int day) @safe scope
1421     {
1422         auto hnsecs = adjTime;
1423         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1424 
1425         if (hnsecs < 0)
1426         {
1427             hnsecs += convert!("hours", "hnsecs")(24);
1428             --days;
1429         }
1430 
1431         auto date = Date(cast(int) days);
1432         date.day = day;
1433 
1434         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
1435         adjTime = newDaysHNSecs + hnsecs;
1436     }
1437 
1438     @safe unittest
1439     {
1440         import std.range : chain;
1441         import std.traits : EnumMembers;
1442 
1443         foreach (day; chain(testDays))
1444         {
1445             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1446             {
1447                 auto dt = cast(DateTime) st;
1448 
1449                 if (day > maxDay(dt.year, dt.month))
1450                     continue;
1451                 auto expected = SysTime(DateTime(dt.year, dt.month, day, dt.hour, dt.minute, dt.second),
1452                                         st.fracSecs,
1453                                         st.timezone);
1454                 st.day = day;
1455                 assert(st == expected, format("[%s] [%s]", st, expected));
1456             }
1457         }
1458 
1459         foreach (tz; testTZs)
1460         {
1461             foreach (tod; testTODs)
1462             {
1463                 foreach (fs; testFracSecs)
1464                 {
1465                     foreach (year; chain(testYearsBC, testYearsAD))
1466                     {
1467                         foreach (month; EnumMembers!Month)
1468                         {
1469                             auto st = SysTime(DateTime(Date(year, month, 1), tod), fs, tz);
1470                             immutable max = maxDay(year, month);
1471                             auto expected = SysTime(DateTime(Date(year, month, max), tod), fs, tz);
1472 
1473                             st.day = max;
1474                             assert(st == expected, format("[%s] [%s]", st, expected));
1475                         }
1476                     }
1477                 }
1478             }
1479         }
1480 
1481         foreach (tz; testTZs)
1482         {
1483             foreach (tod; testTODsThrown)
1484             {
1485                 foreach (fs; [testFracSecs[0], testFracSecs[$-1]])
1486                 {
1487                     foreach (year; [testYearsBC[$-3], testYearsBC[$-2],
1488                                     testYearsBC[$-2], testYearsAD[0],
1489                                     testYearsAD[$-2], testYearsAD[$-1]])
1490                     {
1491                         foreach (month; EnumMembers!Month)
1492                         {
1493                             auto st = SysTime(DateTime(Date(year, month, 1), tod), fs, tz);
1494                             immutable max = maxDay(year, month);
1495 
1496                             assertThrown!DateTimeException(st.day = max + 1);
1497                         }
1498                     }
1499                 }
1500             }
1501         }
1502 
1503         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1504         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1505         static assert(!__traits(compiles, cst.day = 27));
1506         static assert(!__traits(compiles, ist.day = 27));
1507 
1508         static void testScope(scope ref SysTime st) @safe
1509         {
1510             st.day = 12;
1511         }
1512     }
1513 
1514 
1515     /++
1516         Hours past midnight.
1517      +/
1518     @property ubyte hour() @safe const nothrow scope
1519     {
1520         auto hnsecs = adjTime;
1521         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1522 
1523         if (hnsecs < 0)
1524         {
1525             hnsecs += convert!("hours", "hnsecs")(24);
1526             --days;
1527         }
1528 
1529         return cast(ubyte) getUnitsFromHNSecs!"hours"(hnsecs);
1530     }
1531 
1532     @safe unittest
1533     {
1534         import std.range : chain;
1535 
1536         static void test(SysTime sysTime, int expected)
1537         {
1538             assert(sysTime.hour == expected, format("Value given: %s", sysTime));
1539         }
1540 
1541         test(SysTime(0, UTC()), 0);
1542         test(SysTime(1, UTC()), 0);
1543         test(SysTime(-1, UTC()), 23);
1544 
1545         foreach (tz; testTZs)
1546         {
1547             foreach (year; chain(testYearsBC, testYearsAD))
1548             {
1549                 foreach (md; testMonthDays)
1550                 {
1551                     foreach (hour; testHours)
1552                     {
1553                         foreach (minute; testMinSecs)
1554                         {
1555                             foreach (second; testMinSecs)
1556                             {
1557                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1558                                 foreach (fs; testFracSecs)
1559                                     test(SysTime(dt, fs, tz), hour);
1560                             }
1561                         }
1562                     }
1563                 }
1564             }
1565         }
1566 
1567         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1568         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1569         assert(cst.hour == 12);
1570         assert(ist.hour == 12);
1571 
1572         static void testScope(scope ref SysTime st) @safe
1573         {
1574             auto result = st.hour;
1575         }
1576     }
1577 
1578 
1579     /++
1580         Hours past midnight.
1581 
1582         Params:
1583             hour = The hours to set this $(LREF SysTime)'s hour to.
1584 
1585         Throws:
1586             $(REF DateTimeException,std,datetime,date) if the given hour are
1587             not a valid hour of the day.
1588      +/
1589     @property void hour(int hour) @safe scope
1590     {
1591         enforceValid!"hours"(hour);
1592 
1593         auto hnsecs = adjTime;
1594         auto days = splitUnitsFromHNSecs!"days"(hnsecs);
1595         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1596         immutable negative = hnsecs < 0;
1597 
1598         if (negative)
1599             hnsecs += convert!("hours", "hnsecs")(24);
1600 
1601         hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
1602         hnsecs += convert!("hours", "hnsecs")(hour);
1603 
1604         if (negative)
1605             hnsecs -= convert!("hours", "hnsecs")(24);
1606 
1607         adjTime = daysHNSecs + hnsecs;
1608     }
1609 
1610     @safe unittest
1611     {
1612         import std.range : chain;
1613 
1614         foreach (hour; chain(testHours))
1615         {
1616             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1617             {
1618                 auto dt = cast(DateTime) st;
1619                 auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, hour, dt.minute, dt.second),
1620                                         st.fracSecs,
1621                                         st.timezone);
1622                 st.hour = hour;
1623                 assert(st == expected, format("[%s] [%s]", st, expected));
1624             }
1625         }
1626 
1627         auto st = testSysTimesAD[0];
1628         assertThrown!DateTimeException(st.hour = -1);
1629         assertThrown!DateTimeException(st.hour = 60);
1630 
1631         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1632         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1633         static assert(!__traits(compiles, cst.hour = 27));
1634         static assert(!__traits(compiles, ist.hour = 27));
1635 
1636         static void testScope(scope ref SysTime st) @safe
1637         {
1638             st.hour = 12;
1639         }
1640     }
1641 
1642 
1643     /++
1644         Minutes past the current hour.
1645      +/
1646     @property ubyte minute() @safe const nothrow scope
1647     {
1648         auto hnsecs = adjTime;
1649         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1650 
1651         if (hnsecs < 0)
1652         {
1653             hnsecs += convert!("hours", "hnsecs")(24);
1654             --days;
1655         }
1656 
1657         hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
1658 
1659         return cast(ubyte) getUnitsFromHNSecs!"minutes"(hnsecs);
1660     }
1661 
1662     @safe unittest
1663     {
1664         import std.range : chain;
1665 
1666         static void test(SysTime sysTime, int expected)
1667         {
1668             assert(sysTime.minute == expected, format("Value given: %s", sysTime));
1669         }
1670 
1671         test(SysTime(0, UTC()), 0);
1672         test(SysTime(1, UTC()), 0);
1673         test(SysTime(-1, UTC()), 59);
1674 
1675         foreach (tz; testTZs)
1676         {
1677             foreach (year; chain(testYearsBC, testYearsAD))
1678             {
1679                 foreach (md; testMonthDays)
1680                 {
1681                     foreach (hour; testHours)
1682                     {
1683                         foreach (minute; testMinSecs)
1684                         {
1685                             foreach (second; testMinSecs)
1686                             {
1687                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1688                                 foreach (fs; testFracSecs)
1689                                     test(SysTime(dt, fs, tz), minute);
1690                             }
1691                         }
1692                     }
1693                 }
1694             }
1695         }
1696 
1697         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1698         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1699         assert(cst.minute == 30);
1700         assert(ist.minute == 30);
1701 
1702         static void testScope(scope ref SysTime st) @safe
1703         {
1704             auto result = st.minute;
1705         }
1706     }
1707 
1708 
1709     /++
1710         Minutes past the current hour.
1711 
1712         Params:
1713             minute = The minute to set this $(LREF SysTime)'s minute to.
1714 
1715         Throws:
1716             $(REF DateTimeException,std,datetime,date) if the given minute are
1717             not a valid minute of an hour.
1718      +/
1719     @property void minute(int minute) @safe scope
1720     {
1721         enforceValid!"minutes"(minute);
1722 
1723         auto hnsecs = adjTime;
1724         auto days = splitUnitsFromHNSecs!"days"(hnsecs);
1725         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1726         immutable negative = hnsecs < 0;
1727 
1728         if (negative)
1729             hnsecs += convert!("hours", "hnsecs")(24);
1730 
1731         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
1732         hnsecs = removeUnitsFromHNSecs!"minutes"(hnsecs);
1733 
1734         hnsecs += convert!("hours", "hnsecs")(hour);
1735         hnsecs += convert!("minutes", "hnsecs")(minute);
1736 
1737         if (negative)
1738             hnsecs -= convert!("hours", "hnsecs")(24);
1739 
1740         adjTime = daysHNSecs + hnsecs;
1741     }
1742 
1743     @safe unittest
1744     {
1745         import std.range : chain;
1746 
1747         foreach (minute; testMinSecs)
1748         {
1749             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1750             {
1751                 auto dt = cast(DateTime) st;
1752                 auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, dt.hour, minute, dt.second),
1753                                         st.fracSecs,
1754                                         st.timezone);
1755                 st.minute = minute;
1756                 assert(st == expected, format("[%s] [%s]", st, expected));
1757             }
1758         }
1759 
1760         auto st = testSysTimesAD[0];
1761         assertThrown!DateTimeException(st.minute = -1);
1762         assertThrown!DateTimeException(st.minute = 60);
1763 
1764         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1765         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1766         static assert(!__traits(compiles, cst.minute = 27));
1767         static assert(!__traits(compiles, ist.minute = 27));
1768 
1769         static void testScope(scope ref SysTime st) @safe
1770         {
1771             st.minute = 12;
1772         }
1773     }
1774 
1775 
1776     /++
1777         Seconds past the current minute.
1778      +/
1779     @property ubyte second() @safe const nothrow scope
1780     {
1781         auto hnsecs = adjTime;
1782         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1783 
1784         if (hnsecs < 0)
1785         {
1786             hnsecs += convert!("hours", "hnsecs")(24);
1787             --days;
1788         }
1789 
1790         hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
1791         hnsecs = removeUnitsFromHNSecs!"minutes"(hnsecs);
1792 
1793         return cast(ubyte) getUnitsFromHNSecs!"seconds"(hnsecs);
1794     }
1795 
1796     @safe unittest
1797     {
1798         import std.range : chain;
1799 
1800         static void test(SysTime sysTime, int expected)
1801         {
1802             assert(sysTime.second == expected, format("Value given: %s", sysTime));
1803         }
1804 
1805         test(SysTime(0, UTC()), 0);
1806         test(SysTime(1, UTC()), 0);
1807         test(SysTime(-1, UTC()), 59);
1808 
1809         foreach (tz; testTZs)
1810         {
1811             foreach (year; chain(testYearsBC, testYearsAD))
1812             {
1813                 foreach (md; testMonthDays)
1814                 {
1815                     foreach (hour; testHours)
1816                     {
1817                         foreach (minute; testMinSecs)
1818                         {
1819                             foreach (second; testMinSecs)
1820                             {
1821                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1822                                 foreach (fs; testFracSecs)
1823                                     test(SysTime(dt, fs, tz), second);
1824                             }
1825                         }
1826                     }
1827                 }
1828             }
1829         }
1830 
1831         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1832         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1833         assert(cst.second == 33);
1834         assert(ist.second == 33);
1835 
1836         static void testScope(scope ref SysTime st) @safe
1837         {
1838             auto result = st.second;
1839         }
1840     }
1841 
1842 
1843     /++
1844         Seconds past the current minute.
1845 
1846         Params:
1847             second = The second to set this $(LREF SysTime)'s second to.
1848 
1849         Throws:
1850             $(REF DateTimeException,std,datetime,date) if the given second are
1851             not a valid second of a minute.
1852      +/
1853     @property void second(int second) @safe scope
1854     {
1855         enforceValid!"seconds"(second);
1856 
1857         auto hnsecs = adjTime;
1858         auto days = splitUnitsFromHNSecs!"days"(hnsecs);
1859         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1860         immutable negative = hnsecs < 0;
1861 
1862         if (negative)
1863             hnsecs += convert!("hours", "hnsecs")(24);
1864 
1865         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
1866         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
1867         hnsecs = removeUnitsFromHNSecs!"seconds"(hnsecs);
1868 
1869         hnsecs += convert!("hours", "hnsecs")(hour);
1870         hnsecs += convert!("minutes", "hnsecs")(minute);
1871         hnsecs += convert!("seconds", "hnsecs")(second);
1872 
1873         if (negative)
1874             hnsecs -= convert!("hours", "hnsecs")(24);
1875 
1876         adjTime = daysHNSecs + hnsecs;
1877     }
1878 
1879     @safe unittest
1880     {
1881         import std.range : chain;
1882 
1883         foreach (second; testMinSecs)
1884         {
1885             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1886             {
1887                 auto dt = cast(DateTime) st;
1888                 auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, second),
1889                                         st.fracSecs,
1890                                         st.timezone);
1891                 st.second = second;
1892                 assert(st == expected, format("[%s] [%s]", st, expected));
1893             }
1894         }
1895 
1896         auto st = testSysTimesAD[0];
1897         assertThrown!DateTimeException(st.second = -1);
1898         assertThrown!DateTimeException(st.second = 60);
1899 
1900         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1901         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1902         static assert(!__traits(compiles, cst.seconds = 27));
1903         static assert(!__traits(compiles, ist.seconds = 27));
1904 
1905         static void testScope(scope ref SysTime st) @safe
1906         {
1907             st.second = 12;
1908         }
1909     }
1910 
1911 
1912     /++
1913         Fractional seconds past the second (i.e. the portion of a
1914         $(LREF SysTime) which is less than a second).
1915      +/
1916     @property Duration fracSecs() @safe const nothrow scope
1917     {
1918         auto hnsecs = removeUnitsFromHNSecs!"days"(adjTime);
1919 
1920         if (hnsecs < 0)
1921             hnsecs += convert!("hours", "hnsecs")(24);
1922 
1923         return dur!"hnsecs"(removeUnitsFromHNSecs!"seconds"(hnsecs));
1924     }
1925 
1926     ///
1927     @safe unittest
1928     {
1929         import core.time : msecs, usecs, hnsecs, nsecs;
1930         import std.datetime.date : DateTime;
1931 
1932         auto dt = DateTime(1982, 4, 1, 20, 59, 22);
1933         assert(SysTime(dt, msecs(213)).fracSecs == msecs(213));
1934         assert(SysTime(dt, usecs(5202)).fracSecs == usecs(5202));
1935         assert(SysTime(dt, hnsecs(1234567)).fracSecs == hnsecs(1234567));
1936 
1937         // SysTime and Duration both have a precision of hnsecs (100 ns),
1938         // so nsecs are going to be truncated.
1939         assert(SysTime(dt, nsecs(123456789)).fracSecs == nsecs(123456700));
1940     }
1941 
1942     @safe unittest
1943     {
1944         import std.range : chain;
1945         import core.time;
1946 
1947         assert(SysTime(0, UTC()).fracSecs == Duration.zero);
1948         assert(SysTime(1, UTC()).fracSecs == hnsecs(1));
1949         assert(SysTime(-1, UTC()).fracSecs == hnsecs(9_999_999));
1950 
1951         foreach (tz; testTZs)
1952         {
1953             foreach (year; chain(testYearsBC, testYearsAD))
1954             {
1955                 foreach (md; testMonthDays)
1956                 {
1957                     foreach (hour; testHours)
1958                     {
1959                         foreach (minute; testMinSecs)
1960                         {
1961                             foreach (second; testMinSecs)
1962                             {
1963                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1964                                 foreach (fs; testFracSecs)
1965                                     assert(SysTime(dt, fs, tz).fracSecs == fs);
1966                             }
1967                         }
1968                     }
1969                 }
1970             }
1971         }
1972 
1973         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1974         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1975         assert(cst.fracSecs == Duration.zero);
1976         assert(ist.fracSecs == Duration.zero);
1977 
1978         static void testScope(scope ref SysTime st) @safe
1979         {
1980             auto result = st.fracSecs;
1981         }
1982     }
1983 
1984 
1985     /++
1986         Fractional seconds past the second (i.e. the portion of a
1987         $(LREF SysTime) which is less than a second).
1988 
1989         Params:
1990             fracSecs = The duration to set this $(LREF SysTime)'s fractional
1991                        seconds to.
1992 
1993         Throws:
1994             $(REF DateTimeException,std,datetime,date) if the given duration
1995             is negative or if it's greater than or equal to one second.
1996      +/
1997     @property void fracSecs(Duration fracSecs) @safe scope
1998     {
1999         enforce(fracSecs >= Duration.zero, new DateTimeException("A SysTime cannot have negative fractional seconds."));
2000         enforce(fracSecs < seconds(1), new DateTimeException("Fractional seconds must be less than one second."));
2001 
2002         auto oldHNSecs = adjTime;
2003         auto days = splitUnitsFromHNSecs!"days"(oldHNSecs);
2004         immutable daysHNSecs = convert!("days", "hnsecs")(days);
2005         immutable negative = oldHNSecs < 0;
2006 
2007         if (negative)
2008             oldHNSecs += convert!("hours", "hnsecs")(24);
2009 
2010         immutable seconds = splitUnitsFromHNSecs!"seconds"(oldHNSecs);
2011         immutable secondsHNSecs = convert!("seconds", "hnsecs")(seconds);
2012         auto newHNSecs = fracSecs.total!"hnsecs" + secondsHNSecs;
2013 
2014         if (negative)
2015             newHNSecs -= convert!("hours", "hnsecs")(24);
2016 
2017         adjTime = daysHNSecs + newHNSecs;
2018     }
2019 
2020     ///
2021     @safe unittest
2022     {
2023         import core.time : Duration, msecs, hnsecs, nsecs;
2024         import std.datetime.date : DateTime;
2025 
2026         auto st = SysTime(DateTime(1982, 4, 1, 20, 59, 22));
2027         assert(st.fracSecs == Duration.zero);
2028 
2029         st.fracSecs = msecs(213);
2030         assert(st.fracSecs == msecs(213));
2031 
2032         st.fracSecs = hnsecs(1234567);
2033         assert(st.fracSecs == hnsecs(1234567));
2034 
2035         // SysTime has a precision of hnsecs (100 ns), so nsecs are
2036         // going to be truncated.
2037         st.fracSecs = nsecs(123456789);
2038         assert(st.fracSecs == hnsecs(1234567));
2039     }
2040 
2041     @safe unittest
2042     {
2043         import std.range : chain;
2044         import core.time;
2045 
2046         foreach (fracSec; testFracSecs)
2047         {
2048             foreach (st; chain(testSysTimesBC, testSysTimesAD))
2049             {
2050                 auto dt = cast(DateTime) st;
2051                 auto expected = SysTime(dt, fracSec, st.timezone);
2052                 st.fracSecs = fracSec;
2053                 assert(st == expected, format("[%s] [%s]", st, expected));
2054             }
2055         }
2056 
2057         auto st = testSysTimesAD[0];
2058         assertThrown!DateTimeException(st.fracSecs = hnsecs(-1));
2059         assertThrown!DateTimeException(st.fracSecs = seconds(1));
2060 
2061         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2062         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2063         static assert(!__traits(compiles, cst.fracSecs = msecs(7)));
2064         static assert(!__traits(compiles, ist.fracSecs = msecs(7)));
2065 
2066         static void testScope(scope ref SysTime st) @safe
2067         {
2068             st.fracSecs = Duration.zero;
2069         }
2070     }
2071 
2072 
2073     /++
2074         The total hnsecs from midnight, January 1st, 1 A.D. UTC. This is the
2075         internal representation of $(LREF SysTime).
2076      +/
2077     @property long stdTime() @safe const pure nothrow scope
2078     {
2079         return _stdTime;
2080     }
2081 
2082     @safe unittest
2083     {
2084         import core.time;
2085         assert(SysTime(0).stdTime == 0);
2086         assert(SysTime(1).stdTime == 1);
2087         assert(SysTime(-1).stdTime == -1);
2088         assert(SysTime(DateTime(1, 1, 1, 0, 0, 33), hnsecs(502), UTC()).stdTime == 330_000_502L);
2089         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 0), UTC()).stdTime == 621_355_968_000_000_000L);
2090 
2091         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2092         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2093         assert(cst.stdTime > 0);
2094         assert(ist.stdTime > 0);
2095 
2096         static void testScope(scope ref SysTime st) @safe
2097         {
2098             auto result = st.stdTime;
2099         }
2100     }
2101 
2102 
2103     /++
2104         The total hnsecs from midnight, January 1st, 1 A.D. UTC. This is the
2105         internal representation of $(LREF SysTime).
2106 
2107         Params:
2108             stdTime = The number of hnsecs since January 1st, 1 A.D. UTC.
2109      +/
2110     @property void stdTime(long stdTime) @safe pure nothrow scope
2111     {
2112         _stdTime = stdTime;
2113     }
2114 
2115     @safe unittest
2116     {
2117         import core.time;
2118         static void test(long stdTime, SysTime expected, size_t line = __LINE__)
2119         {
2120             auto st = SysTime(0, UTC());
2121             st.stdTime = stdTime;
2122             assert(st == expected);
2123         }
2124 
2125         test(0, SysTime(Date(1, 1, 1), UTC()));
2126         test(1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()));
2127         test(-1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()));
2128         test(330_000_502L, SysTime(DateTime(1, 1, 1, 0, 0, 33), hnsecs(502), UTC()));
2129         test(621_355_968_000_000_000L, SysTime(DateTime(1970, 1, 1, 0, 0, 0), UTC()));
2130 
2131         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2132         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2133         static assert(!__traits(compiles, cst.stdTime = 27));
2134         static assert(!__traits(compiles, ist.stdTime = 27));
2135 
2136         static void testScope(scope ref SysTime st) @safe
2137         {
2138             st.stdTime = 42;
2139         }
2140     }
2141 
2142 
2143     /++
2144         The current time zone of this $(LREF SysTime). Its internal time is
2145         always kept in UTC, so there are no conversion issues between time zones
2146         due to DST. Functions which return all or part of the time - such as
2147         hours - adjust the time to this $(LREF SysTime)'s time zone before
2148         returning.
2149       +/
2150     @property immutable(TimeZone) timezone() @safe const pure nothrow scope
2151     {
2152         return _timezone;
2153     }
2154 
2155     @safe unittest
2156     {
2157         assert(SysTime.init.timezone is InitTimeZone());
2158         assert(SysTime(DateTime.init, UTC()).timezone is UTC());
2159 
2160         static void testScope(scope ref SysTime st) @safe
2161         {
2162             auto result = st.timezone;
2163         }
2164     }
2165 
2166 
2167     /++
2168         The current time zone of this $(LREF SysTime). It's internal time is
2169         always kept in UTC, so there are no conversion issues between time zones
2170         due to DST. Functions which return all or part of the time - such as
2171         hours - adjust the time to this $(LREF SysTime)'s time zone before
2172         returning.
2173 
2174         Params:
2175             timezone = The $(REF _TimeZone,std,datetime,_timezone) to set this
2176                        $(LREF SysTime)'s time zone to.
2177       +/
2178     @property void timezone(immutable TimeZone timezone) @safe pure nothrow scope
2179     {
2180         if (timezone is null)
2181             _timezone = LocalTime();
2182         else
2183             _timezone = timezone;
2184     }
2185 
2186     @safe unittest
2187     {
2188         SysTime st;
2189         st.timezone = null;
2190         assert(st.timezone is LocalTime());
2191         st.timezone = UTC();
2192         assert(st.timezone is UTC());
2193 
2194         static void testScope(scope ref SysTime st) @safe
2195         {
2196             st.timezone = UTC();
2197         }
2198     }
2199 
2200 
2201     /++
2202         Returns whether DST is in effect for this $(LREF SysTime).
2203       +/
2204     @property bool dstInEffect() @safe const nothrow scope
2205     {
2206         return _timezone.dstInEffect(_stdTime);
2207     }
2208 
2209     // This function's full unit testing is done in the time zone classes, but
2210     // this verifies that SysTime.init works correctly, since historically, it
2211     // has segfaulted due to a null _timezone.
2212     @safe unittest
2213     {
2214         assert(!SysTime.init.dstInEffect);
2215 
2216         static void testScope(scope ref SysTime st) @safe
2217         {
2218             auto result = st.dstInEffect;
2219         }
2220     }
2221 
2222 
2223     /++
2224         Returns what the offset from UTC is for this $(LREF SysTime).
2225         It includes the DST offset in effect at that time (if any).
2226       +/
2227     @property Duration utcOffset() @safe const nothrow scope
2228     {
2229         return _timezone.utcOffsetAt(_stdTime);
2230     }
2231 
2232     // This function's full unit testing is done in the time zone classes, but
2233     // this verifies that SysTime.init works correctly, since historically, it
2234     // has segfaulted due to a null _timezone.
2235     @safe unittest
2236     {
2237         assert(SysTime.init.utcOffset == Duration.zero);
2238 
2239         static void testScope(scope ref SysTime st) @safe
2240         {
2241             auto result = st.utcOffset;
2242         }
2243     }
2244 
2245 
2246     /++
2247         Returns a $(LREF SysTime) with the same std time as this one, but with
2248         $(REF LocalTime,std,datetime,timezone) as its time zone.
2249       +/
2250     SysTime toLocalTime() @safe const pure nothrow scope
2251     {
2252         return SysTime(_stdTime, LocalTime());
2253     }
2254 
2255     @safe unittest
2256     {
2257         import core.time;
2258         {
2259             auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
2260             assert(sysTime == sysTime.toLocalTime());
2261             assert(sysTime._stdTime == sysTime.toLocalTime()._stdTime);
2262             assert(sysTime.toLocalTime().timezone is LocalTime());
2263             assert(sysTime.toLocalTime().timezone is sysTime.timezone);
2264             assert(sysTime.toLocalTime().timezone !is UTC());
2265         }
2266 
2267         {
2268             auto stz = new immutable SimpleTimeZone(dur!"minutes"(-3 * 60));
2269             auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27), stz);
2270             assert(sysTime == sysTime.toLocalTime());
2271             assert(sysTime._stdTime == sysTime.toLocalTime()._stdTime);
2272             assert(sysTime.toLocalTime().timezone is LocalTime());
2273             assert(sysTime.toLocalTime().timezone !is UTC());
2274             assert(sysTime.toLocalTime().timezone !is stz);
2275         }
2276 
2277         static void testScope(scope ref SysTime st) @safe
2278         {
2279             auto result = st.toLocalTime();
2280         }
2281     }
2282 
2283 
2284     /++
2285         Returns a $(LREF SysTime) with the same std time as this one, but with
2286         `UTC` as its time zone.
2287       +/
2288     SysTime toUTC() @safe const pure nothrow scope
2289     {
2290         return SysTime(_stdTime, UTC());
2291     }
2292 
2293     @safe unittest
2294     {
2295         import core.time;
2296         auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
2297         assert(sysTime == sysTime.toUTC());
2298         assert(sysTime._stdTime == sysTime.toUTC()._stdTime);
2299         assert(sysTime.toUTC().timezone is UTC());
2300         assert(sysTime.toUTC().timezone !is LocalTime());
2301         assert(sysTime.toUTC().timezone !is sysTime.timezone);
2302 
2303         static void testScope(scope ref SysTime st) @safe
2304         {
2305             auto result = st.toUTC();
2306         }
2307     }
2308 
2309 
2310     /++
2311         Returns a $(LREF SysTime) with the same std time as this one, but with
2312         given time zone as its time zone.
2313       +/
2314     SysTime toOtherTZ(immutable TimeZone tz) @safe const pure nothrow scope
2315     {
2316         if (tz is null)
2317             return SysTime(_stdTime, LocalTime());
2318         else
2319             return SysTime(_stdTime, tz);
2320     }
2321 
2322     @safe unittest
2323     {
2324         import core.time;
2325         auto stz = new immutable SimpleTimeZone(dur!"minutes"(11 * 60));
2326         auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
2327         assert(sysTime == sysTime.toOtherTZ(stz));
2328         assert(sysTime._stdTime == sysTime.toOtherTZ(stz)._stdTime);
2329         assert(sysTime.toOtherTZ(stz).timezone is stz);
2330         assert(sysTime.toOtherTZ(stz).timezone !is LocalTime());
2331         assert(sysTime.toOtherTZ(stz).timezone !is UTC());
2332         assert(sysTime.toOtherTZ(null).timezone is LocalTime());
2333 
2334         static void testScope(scope ref SysTime st) @safe
2335         {
2336             auto result = st.toOtherTZ(null);
2337         }
2338     }
2339 
2340 
2341     /++
2342         Converts this $(LREF SysTime) to unix time (i.e. seconds from midnight,
2343         January 1st, 1970 in UTC).
2344 
2345         The C standard does not specify the representation of time_t, so it is
2346         implementation defined. On POSIX systems, unix time is equivalent to
2347         time_t, but that's not necessarily true on other systems (e.g. it is
2348         not true for the Digital Mars C runtime). So, be careful when using unix
2349         time with C functions on non-POSIX systems.
2350 
2351         By default, the return type is time_t (which is normally an alias for
2352         int on 32-bit systems and long on 64-bit systems), but if a different
2353         size is required than either int or long can be passed as a template
2354         argument to get the desired size.
2355 
2356         If the return type is int, and the result can't fit in an int, then the
2357         closest value that can be held in 32 bits will be used (so `int.max`
2358         if it goes over and `int.min` if it goes under). However, no attempt
2359         is made to deal with integer overflow if the return type is long.
2360 
2361         Params:
2362             T = The return type (int or long). It defaults to time_t, which is
2363                 normally 32 bits on a 32-bit system and 64 bits on a 64-bit
2364                 system.
2365 
2366         Returns:
2367             A signed integer representing the unix time which is equivalent to
2368             this SysTime.
2369       +/
2370     T toUnixTime(T = time_t)() @safe const pure nothrow scope
2371         if (is(T == int) || is(T == long))
2372     {
2373         return stdTimeToUnixTime!T(_stdTime);
2374     }
2375 
2376     ///
2377     @safe unittest
2378     {
2379         import core.time : hours;
2380         import std.datetime.date : DateTime;
2381         import std.datetime.timezone : SimpleTimeZone, UTC;
2382 
2383         assert(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime() == 0);
2384 
2385         auto pst = new immutable SimpleTimeZone(hours(-8));
2386         assert(SysTime(DateTime(1970, 1, 1), pst).toUnixTime() == 28800);
2387 
2388         auto utc = SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC());
2389         assert(utc.toUnixTime() == 1_198_311_285);
2390 
2391         auto ca = SysTime(DateTime(2007, 12, 22, 8, 14, 45), pst);
2392         assert(ca.toUnixTime() == 1_198_340_085);
2393 
2394         static void testScope(scope ref SysTime st) @safe
2395         {
2396             auto result = st.toUnixTime();
2397         }
2398     }
2399 
2400     @safe unittest
2401     {
2402         import std.meta : AliasSeq;
2403         import core.time;
2404         assert(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime() == 0);
2405         static foreach (units; ["hnsecs", "usecs", "msecs"])
2406             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 0), dur!units(1), UTC()).toUnixTime() == 0);
2407         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toUnixTime() == 1);
2408         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toUnixTime() == 0);
2409         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toUnixTime() == 0);
2410         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toUnixTime() == 0);
2411         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toUnixTime() == -1);
2412     }
2413 
2414 
2415     /++
2416         Converts from unix time (i.e. seconds from midnight, January 1st, 1970
2417         in UTC) to a $(LREF SysTime).
2418 
2419         The C standard does not specify the representation of time_t, so it is
2420         implementation defined. On POSIX systems, unix time is equivalent to
2421         time_t, but that's not necessarily true on other systems (e.g. it is
2422         not true for the Digital Mars C runtime). So, be careful when using unix
2423         time with C functions on non-POSIX systems.
2424 
2425         Params:
2426             unixTime = Seconds from midnight, January 1st, 1970 in UTC.
2427             tz = The time zone for the SysTime that's returned.
2428       +/
2429     static SysTime fromUnixTime(long unixTime, immutable TimeZone tz = LocalTime()) @safe pure nothrow
2430     {
2431         return SysTime(unixTimeToStdTime(unixTime), tz);
2432     }
2433 
2434     ///
2435     @safe unittest
2436     {
2437         import core.time : hours;
2438         import std.datetime.date : DateTime;
2439         import std.datetime.timezone : SimpleTimeZone, UTC;
2440 
2441         assert(SysTime.fromUnixTime(0) ==
2442                SysTime(DateTime(1970, 1, 1), UTC()));
2443 
2444         auto pst = new immutable SimpleTimeZone(hours(-8));
2445         assert(SysTime.fromUnixTime(28800) ==
2446                SysTime(DateTime(1970, 1, 1), pst));
2447 
2448         auto st1 = SysTime.fromUnixTime(1_198_311_285, UTC());
2449         assert(st1 == SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC()));
2450         assert(st1.timezone is UTC());
2451         assert(st1 == SysTime(DateTime(2007, 12, 22, 0, 14, 45), pst));
2452 
2453         auto st2 = SysTime.fromUnixTime(1_198_311_285, pst);
2454         assert(st2 == SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC()));
2455         assert(st2.timezone is pst);
2456         assert(st2 == SysTime(DateTime(2007, 12, 22, 0, 14, 45), pst));
2457     }
2458 
2459     @safe unittest
2460     {
2461         import core.time;
2462         assert(SysTime.fromUnixTime(0) == SysTime(DateTime(1970, 1, 1), UTC()));
2463         assert(SysTime.fromUnixTime(1) == SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()));
2464         assert(SysTime.fromUnixTime(-1) == SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()));
2465 
2466         auto st = SysTime.fromUnixTime(0);
2467         auto dt = cast(DateTime) st;
2468         assert(dt <= DateTime(1970, 2, 1) && dt >= DateTime(1969, 12, 31));
2469         assert(st.timezone is LocalTime());
2470 
2471         auto aest = new immutable SimpleTimeZone(hours(10));
2472         assert(SysTime.fromUnixTime(-36000) == SysTime(DateTime(1970, 1, 1), aest));
2473     }
2474 
2475 
2476     /++
2477         Returns a `timeval` which represents this $(LREF SysTime).
2478 
2479         Note that like all conversions in std.datetime, this is a truncating
2480         conversion.
2481 
2482         If `timeval.tv_sec` is int, and the result can't fit in an int, then
2483         the closest value that can be held in 32 bits will be used for
2484         `tv_sec`. (so `int.max` if it goes over and `int.min` if it
2485         goes under).
2486       +/
2487     timeval toTimeVal() @safe const pure nothrow scope
2488     {
2489         immutable tv_sec = toUnixTime!(typeof(timeval.tv_sec))();
2490         immutable fracHNSecs = removeUnitsFromHNSecs!"seconds"(_stdTime - 621_355_968_000_000_000L);
2491         immutable tv_usec = cast(typeof(timeval.tv_usec))convert!("hnsecs", "usecs")(fracHNSecs);
2492         return timeval(tv_sec, tv_usec);
2493     }
2494 
2495     @safe unittest
2496     {
2497         import core.time;
2498         assert(SysTime(DateTime(1970, 1, 1), UTC()).toTimeVal() == timeval(0, 0));
2499         assert(SysTime(DateTime(1970, 1, 1), hnsecs(9), UTC()).toTimeVal() == timeval(0, 0));
2500         assert(SysTime(DateTime(1970, 1, 1), hnsecs(10), UTC()).toTimeVal() == timeval(0, 1));
2501         assert(SysTime(DateTime(1970, 1, 1), usecs(7), UTC()).toTimeVal() == timeval(0, 7));
2502 
2503         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toTimeVal() == timeval(1, 0));
2504         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(9), UTC()).toTimeVal() == timeval(1, 0));
2505         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(10), UTC()).toTimeVal() == timeval(1, 1));
2506         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), usecs(7), UTC()).toTimeVal() == timeval(1, 7));
2507 
2508         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toTimeVal() == timeval(0, 0));
2509         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_990), UTC()).toTimeVal() == timeval(0, -1));
2510 
2511         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toTimeVal() == timeval(0, -1));
2512         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999), UTC()).toTimeVal() == timeval(0, -999_001));
2513         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toTimeVal() == timeval(0, -1000));
2514         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toTimeVal() == timeval(-1, 0));
2515         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 58), usecs(17), UTC()).toTimeVal() == timeval(-1, -999_983));
2516 
2517         static void testScope(scope ref SysTime st) @safe
2518         {
2519             auto result = st.toTimeVal();
2520         }
2521     }
2522 
2523 
2524     version (StdDdoc)
2525     {
2526         private struct timespec {}
2527         /++
2528             Returns a `timespec` which represents this $(LREF SysTime).
2529 
2530             $(BLUE This function is Posix-Only.)
2531           +/
2532         timespec toTimeSpec() @safe const pure nothrow scope;
2533     }
2534     else version (Posix)
2535     {
2536         timespec toTimeSpec() @safe const pure nothrow scope
2537         {
2538             immutable tv_sec = toUnixTime!(typeof(timespec.tv_sec))();
2539             immutable fracHNSecs = removeUnitsFromHNSecs!"seconds"(_stdTime - 621_355_968_000_000_000L);
2540             immutable tv_nsec = cast(typeof(timespec.tv_nsec))convert!("hnsecs", "nsecs")(fracHNSecs);
2541             return timespec(tv_sec, tv_nsec);
2542         }
2543 
2544         @safe unittest
2545         {
2546             import core.time;
2547             assert(SysTime(DateTime(1970, 1, 1), UTC()).toTimeSpec() == timespec(0, 0));
2548             assert(SysTime(DateTime(1970, 1, 1), hnsecs(9), UTC()).toTimeSpec() == timespec(0, 900));
2549             assert(SysTime(DateTime(1970, 1, 1), hnsecs(10), UTC()).toTimeSpec() == timespec(0, 1000));
2550             assert(SysTime(DateTime(1970, 1, 1), usecs(7), UTC()).toTimeSpec() == timespec(0, 7000));
2551 
2552             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toTimeSpec() == timespec(1, 0));
2553             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(9), UTC()).toTimeSpec() == timespec(1, 900));
2554             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(10), UTC()).toTimeSpec() == timespec(1, 1000));
2555             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), usecs(7), UTC()).toTimeSpec() == timespec(1, 7000));
2556 
2557             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toTimeSpec() ==
2558                    timespec(0, -100));
2559             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_990), UTC()).toTimeSpec() ==
2560                    timespec(0, -1000));
2561 
2562             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toTimeSpec() ==
2563                    timespec(0, -1_000));
2564             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999), UTC()).toTimeSpec() ==
2565                    timespec(0, -999_001_000));
2566             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toTimeSpec() ==
2567                    timespec(0, -1_000_000));
2568             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toTimeSpec() ==
2569                    timespec(-1, 0));
2570             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 58), usecs(17), UTC()).toTimeSpec() ==
2571                    timespec(-1, -999_983_000));
2572 
2573             static void testScope(scope ref SysTime st) @safe
2574             {
2575                 auto result = st.toTimeSpec();
2576             }
2577         }
2578     }
2579 
2580     /++
2581         Returns a `tm` which represents this $(LREF SysTime).
2582       +/
2583     tm toTM() @safe const nothrow scope
2584     {
2585         auto dateTime = cast(DateTime) this;
2586         tm timeInfo;
2587 
2588         timeInfo.tm_sec = dateTime.second;
2589         timeInfo.tm_min = dateTime.minute;
2590         timeInfo.tm_hour = dateTime.hour;
2591         timeInfo.tm_mday = dateTime.day;
2592         timeInfo.tm_mon = dateTime.month - 1;
2593         timeInfo.tm_year = dateTime.year - 1900;
2594         timeInfo.tm_wday = dateTime.dayOfWeek;
2595         timeInfo.tm_yday = dateTime.dayOfYear - 1;
2596         timeInfo.tm_isdst = _timezone.dstInEffect(_stdTime);
2597 
2598         version (Posix)
2599         {
2600             import std.utf : toUTFz;
2601             timeInfo.tm_gmtoff = cast(int) convert!("hnsecs", "seconds")(adjTime - _stdTime);
2602             auto zone = timeInfo.tm_isdst ? _timezone.dstName : _timezone.stdName;
2603             timeInfo.tm_zone = zone.toUTFz!(char*)();
2604         }
2605 
2606         return timeInfo;
2607     }
2608 
2609     @system unittest
2610     {
2611         import std.conv : to;
2612         import core.time;
2613 
2614         version (Posix)
2615         {
2616             import std.datetime.timezone : clearTZEnvVar, setTZEnvVar;
2617             setTZEnvVar("America/Los_Angeles");
2618             scope(exit) clearTZEnvVar();
2619         }
2620 
2621         {
2622             auto timeInfo = SysTime(DateTime(1970, 1, 1)).toTM();
2623 
2624             assert(timeInfo.tm_sec == 0);
2625             assert(timeInfo.tm_min == 0);
2626             assert(timeInfo.tm_hour == 0);
2627             assert(timeInfo.tm_mday == 1);
2628             assert(timeInfo.tm_mon == 0);
2629             assert(timeInfo.tm_year == 70);
2630             assert(timeInfo.tm_wday == 4);
2631             assert(timeInfo.tm_yday == 0);
2632 
2633             version (Posix)
2634                 assert(timeInfo.tm_isdst == 0);
2635             else version (Windows)
2636                 assert(timeInfo.tm_isdst == 0 || timeInfo.tm_isdst == 1);
2637 
2638             version (Posix)
2639             {
2640                 assert(timeInfo.tm_gmtoff == -8 * 60 * 60);
2641                 assert(to!string(timeInfo.tm_zone) == "PST");
2642             }
2643         }
2644 
2645         {
2646             auto timeInfo = SysTime(DateTime(2010, 7, 4, 12, 15, 7), hnsecs(15)).toTM();
2647 
2648             assert(timeInfo.tm_sec == 7);
2649             assert(timeInfo.tm_min == 15);
2650             assert(timeInfo.tm_hour == 12);
2651             assert(timeInfo.tm_mday == 4);
2652             assert(timeInfo.tm_mon == 6);
2653             assert(timeInfo.tm_year == 110);
2654             assert(timeInfo.tm_wday == 0);
2655             assert(timeInfo.tm_yday == 184);
2656 
2657             version (Posix)
2658                 assert(timeInfo.tm_isdst == 1);
2659             else version (Windows)
2660                 assert(timeInfo.tm_isdst == 0 || timeInfo.tm_isdst == 1);
2661 
2662             version (Posix)
2663             {
2664                 assert(timeInfo.tm_gmtoff == -7 * 60 * 60);
2665                 assert(to!string(timeInfo.tm_zone) == "PDT");
2666             }
2667         }
2668 
2669         // This is more to verify that SysTime.init.toTM() doesn't segfault and
2670         // does something sane rather than that the value is anything
2671         // particularly useful.
2672         {
2673             auto timeInfo = SysTime.init.toTM();
2674 
2675             assert(timeInfo.tm_sec == 0);
2676             assert(timeInfo.tm_min == 0);
2677             assert(timeInfo.tm_hour == 0);
2678             assert(timeInfo.tm_mday == 1);
2679             assert(timeInfo.tm_mon == 0);
2680             assert(timeInfo.tm_year == -1899);
2681             assert(timeInfo.tm_wday == 1);
2682             assert(timeInfo.tm_yday == 0);
2683             assert(timeInfo.tm_isdst == 0);
2684 
2685             version (Posix)
2686             {
2687                 assert(timeInfo.tm_gmtoff == 0);
2688                 assert(to!string(timeInfo.tm_zone) == "SysTime.init's timezone");
2689             }
2690         }
2691 
2692         static void testScope(scope ref SysTime st) @safe
2693         {
2694             auto result = st.toTM();
2695         }
2696     }
2697 
2698 
2699     /++
2700         Adds the given number of years or months to this $(LREF SysTime). A
2701         negative number will subtract.
2702 
2703         Note that if day overflow is allowed, and the date with the adjusted
2704         year/month overflows the number of days in the new month, then the month
2705         will be incremented by one, and the day set to the number of days
2706         overflowed. (e.g. if the day were 31 and the new month were June, then
2707         the month would be incremented to July, and the new day would be 1). If
2708         day overflow is not allowed, then the day will be set to the last valid
2709         day in the month (e.g. June 31st would become June 30th).
2710 
2711         Params:
2712             units         = The type of units to add ("years" or "months").
2713             value         = The number of months or years to add to this
2714                             $(LREF SysTime).
2715             allowOverflow = Whether the days should be allowed to overflow,
2716                             causing the month to increment.
2717       +/
2718     ref SysTime add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow scope
2719         if (units == "years" || units == "months")
2720     {
2721         auto hnsecs = adjTime;
2722         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
2723 
2724         if (hnsecs < 0)
2725         {
2726             hnsecs += convert!("hours", "hnsecs")(24);
2727             --days;
2728         }
2729 
2730         auto date = Date(cast(int) days);
2731         date.add!units(value, allowOverflow);
2732         days = date.dayOfGregorianCal - 1;
2733 
2734         if (days < 0)
2735         {
2736             hnsecs -= convert!("hours", "hnsecs")(24);
2737             ++days;
2738         }
2739 
2740         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
2741 
2742         adjTime = newDaysHNSecs + hnsecs;
2743 
2744         return this;
2745     }
2746 
2747     @safe unittest
2748     {
2749         auto st1 = SysTime(DateTime(2010, 1, 1, 12, 30, 33));
2750         st1.add!"months"(11);
2751         assert(st1 == SysTime(DateTime(2010, 12, 1, 12, 30, 33)));
2752 
2753         auto st2 = SysTime(DateTime(2010, 1, 1, 12, 30, 33));
2754         st2.add!"months"(-11);
2755         assert(st2 == SysTime(DateTime(2009, 2, 1, 12, 30, 33)));
2756 
2757         auto st3 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
2758         st3.add!"years"(1);
2759         assert(st3 == SysTime(DateTime(2001, 3, 1, 12, 30, 33)));
2760 
2761         auto st4 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
2762         st4.add!"years"(1, AllowDayOverflow.no);
2763         assert(st4 == SysTime(DateTime(2001, 2, 28, 12, 30, 33)));
2764     }
2765 
2766     // Test add!"years"() with AllowDayOverflow.yes
2767     @safe unittest
2768     {
2769         import core.time;
2770         // Test A.D.
2771         {
2772             auto sysTime = SysTime(Date(1999, 7, 6));
2773             sysTime.add!"years"(7);
2774             assert(sysTime == SysTime(Date(2006, 7, 6)));
2775             sysTime.add!"years"(-9);
2776             assert(sysTime == SysTime(Date(1997, 7, 6)));
2777         }
2778 
2779         {
2780             auto sysTime = SysTime(Date(1999, 2, 28));
2781             sysTime.add!"years"(1);
2782             assert(sysTime == SysTime(Date(2000, 2, 28)));
2783         }
2784 
2785         {
2786             auto sysTime = SysTime(Date(2000, 2, 29));
2787             sysTime.add!"years"(-1);
2788             assert(sysTime == SysTime(Date(1999, 3, 1)));
2789         }
2790 
2791         {
2792             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 7, 3), msecs(234));
2793             sysTime.add!"years"(7);
2794             assert(sysTime == SysTime(DateTime(2006, 7, 6, 12, 7, 3), msecs(234)));
2795             sysTime.add!"years"(-9);
2796             assert(sysTime == SysTime(DateTime(1997, 7, 6, 12, 7, 3), msecs(234)));
2797         }
2798 
2799         {
2800             auto sysTime = SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207));
2801             sysTime.add!"years"(1);
2802             assert(sysTime == SysTime(DateTime(2000, 2, 28, 0, 7, 2), usecs(1207)));
2803         }
2804 
2805         {
2806             auto sysTime = SysTime(DateTime(2000, 2, 29, 0, 7, 2), usecs(1207));
2807             sysTime.add!"years"(-1);
2808             assert(sysTime == SysTime(DateTime(1999, 3, 1, 0, 7, 2), usecs(1207)));
2809         }
2810 
2811         // Test B.C.
2812         {
2813             auto sysTime = SysTime(Date(-1999, 7, 6));
2814             sysTime.add!"years"(-7);
2815             assert(sysTime == SysTime(Date(-2006, 7, 6)));
2816             sysTime.add!"years"(9);
2817             assert(sysTime == SysTime(Date(-1997, 7, 6)));
2818         }
2819 
2820         {
2821             auto sysTime = SysTime(Date(-1999, 2, 28));
2822             sysTime.add!"years"(-1);
2823             assert(sysTime == SysTime(Date(-2000, 2, 28)));
2824         }
2825 
2826         {
2827             auto sysTime = SysTime(Date(-2000, 2, 29));
2828             sysTime.add!"years"(1);
2829             assert(sysTime == SysTime(Date(-1999, 3, 1)));
2830         }
2831 
2832         {
2833             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 7, 3), msecs(234));
2834             sysTime.add!"years"(-7);
2835             assert(sysTime == SysTime(DateTime(-2006, 7, 6, 12, 7, 3), msecs(234)));
2836             sysTime.add!"years"(9);
2837             assert(sysTime == SysTime(DateTime(-1997, 7, 6, 12, 7, 3), msecs(234)));
2838         }
2839 
2840         {
2841             auto sysTime = SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3));
2842             sysTime.add!"years"(-1);
2843             assert(sysTime == SysTime(DateTime(-2000, 2, 28, 3, 3, 3), hnsecs(3)));
2844         }
2845 
2846         {
2847             auto sysTime = SysTime(DateTime(-2000, 2, 29, 3, 3, 3), hnsecs(3));
2848             sysTime.add!"years"(1);
2849             assert(sysTime == SysTime(DateTime(-1999, 3, 1, 3, 3, 3), hnsecs(3)));
2850         }
2851 
2852         // Test Both
2853         {
2854             auto sysTime = SysTime(Date(4, 7, 6));
2855             sysTime.add!"years"(-5);
2856             assert(sysTime == SysTime(Date(-1, 7, 6)));
2857             sysTime.add!"years"(5);
2858             assert(sysTime == SysTime(Date(4, 7, 6)));
2859         }
2860 
2861         {
2862             auto sysTime = SysTime(Date(-4, 7, 6));
2863             sysTime.add!"years"(5);
2864             assert(sysTime == SysTime(Date(1, 7, 6)));
2865             sysTime.add!"years"(-5);
2866             assert(sysTime == SysTime(Date(-4, 7, 6)));
2867         }
2868 
2869         {
2870             auto sysTime = SysTime(Date(4, 7, 6));
2871             sysTime.add!"years"(-8);
2872             assert(sysTime == SysTime(Date(-4, 7, 6)));
2873             sysTime.add!"years"(8);
2874             assert(sysTime == SysTime(Date(4, 7, 6)));
2875         }
2876 
2877         {
2878             auto sysTime = SysTime(Date(-4, 7, 6));
2879             sysTime.add!"years"(8);
2880             assert(sysTime == SysTime(Date(4, 7, 6)));
2881             sysTime.add!"years"(-8);
2882             assert(sysTime == SysTime(Date(-4, 7, 6)));
2883         }
2884 
2885         {
2886             auto sysTime = SysTime(Date(-4, 2, 29));
2887             sysTime.add!"years"(5);
2888             assert(sysTime == SysTime(Date(1, 3, 1)));
2889         }
2890 
2891         {
2892             auto sysTime = SysTime(Date(4, 2, 29));
2893             sysTime.add!"years"(-5);
2894             assert(sysTime == SysTime(Date(-1, 3, 1)));
2895         }
2896 
2897         {
2898             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
2899             sysTime.add!"years"(-1);
2900             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
2901             sysTime.add!"years"(1);
2902             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
2903         }
2904 
2905         {
2906             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
2907             sysTime.add!"years"(-1);
2908             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2909             sysTime.add!"years"(1);
2910             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2911         }
2912 
2913         {
2914             auto sysTime = SysTime(DateTime(0, 1, 1, 0, 0, 0));
2915             sysTime.add!"years"(1);
2916             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
2917             sysTime.add!"years"(-1);
2918             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
2919         }
2920 
2921         {
2922             auto sysTime = SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999));
2923             sysTime.add!"years"(1);
2924             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2925             sysTime.add!"years"(-1);
2926             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2927         }
2928 
2929         {
2930             auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
2931             sysTime.add!"years"(-5);
2932             assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
2933             sysTime.add!"years"(5);
2934             assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
2935         }
2936 
2937         {
2938             auto sysTime = SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329));
2939             sysTime.add!"years"(5);
2940             assert(sysTime == SysTime(DateTime(1, 7, 6, 14, 7, 1), usecs(54329)));
2941             sysTime.add!"years"(-5);
2942             assert(sysTime == SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329)));
2943         }
2944 
2945         {
2946             auto sysTime = SysTime(DateTime(-4, 2, 29, 5, 5, 5), msecs(555));
2947             sysTime.add!"years"(5);
2948             assert(sysTime == SysTime(DateTime(1, 3, 1, 5, 5, 5), msecs(555)));
2949         }
2950 
2951         {
2952             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
2953             sysTime.add!"years"(-5);
2954             assert(sysTime == SysTime(DateTime(-1, 3, 1, 5, 5, 5), msecs(555)));
2955         }
2956 
2957         {
2958             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
2959             sysTime.add!"years"(-5).add!"years"(7);
2960             assert(sysTime == SysTime(DateTime(6, 3, 1, 5, 5, 5), msecs(555)));
2961         }
2962 
2963         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2964         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2965         static assert(!__traits(compiles, cst.add!"years"(4)));
2966         static assert(!__traits(compiles, ist.add!"years"(4)));
2967 
2968         static void testScope(scope ref SysTime st) @safe
2969         {
2970             auto result = st.add!"years"(42);
2971         }
2972     }
2973 
2974     // Test add!"years"() with AllowDayOverflow.no
2975     @safe unittest
2976     {
2977         import core.time;
2978         // Test A.D.
2979         {
2980             auto sysTime = SysTime(Date(1999, 7, 6));
2981             sysTime.add!"years"(7, AllowDayOverflow.no);
2982             assert(sysTime == SysTime(Date(2006, 7, 6)));
2983             sysTime.add!"years"(-9, AllowDayOverflow.no);
2984             assert(sysTime == SysTime(Date(1997, 7, 6)));
2985         }
2986 
2987         {
2988             auto sysTime = SysTime(Date(1999, 2, 28));
2989             sysTime.add!"years"(1, AllowDayOverflow.no);
2990             assert(sysTime == SysTime(Date(2000, 2, 28)));
2991         }
2992 
2993         {
2994             auto sysTime = SysTime(Date(2000, 2, 29));
2995             sysTime.add!"years"(-1, AllowDayOverflow.no);
2996             assert(sysTime == SysTime(Date(1999, 2, 28)));
2997         }
2998 
2999         {
3000             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 7, 3), msecs(234));
3001             sysTime.add!"years"(7, AllowDayOverflow.no);
3002             assert(sysTime == SysTime(DateTime(2006, 7, 6, 12, 7, 3), msecs(234)));
3003             sysTime.add!"years"(-9, AllowDayOverflow.no);
3004             assert(sysTime == SysTime(DateTime(1997, 7, 6, 12, 7, 3), msecs(234)));
3005         }
3006 
3007         {
3008             auto sysTime = SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207));
3009             sysTime.add!"years"(1, AllowDayOverflow.no);
3010             assert(sysTime == SysTime(DateTime(2000, 2, 28, 0, 7, 2), usecs(1207)));
3011         }
3012 
3013         {
3014             auto sysTime = SysTime(DateTime(2000, 2, 29, 0, 7, 2), usecs(1207));
3015             sysTime.add!"years"(-1, AllowDayOverflow.no);
3016             assert(sysTime == SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207)));
3017         }
3018 
3019         // Test B.C.
3020         {
3021             auto sysTime = SysTime(Date(-1999, 7, 6));
3022             sysTime.add!"years"(-7, AllowDayOverflow.no);
3023             assert(sysTime == SysTime(Date(-2006, 7, 6)));
3024             sysTime.add!"years"(9, AllowDayOverflow.no);
3025             assert(sysTime == SysTime(Date(-1997, 7, 6)));
3026         }
3027 
3028         {
3029             auto sysTime = SysTime(Date(-1999, 2, 28));
3030             sysTime.add!"years"(-1, AllowDayOverflow.no);
3031             assert(sysTime == SysTime(Date(-2000, 2, 28)));
3032         }
3033 
3034         {
3035             auto sysTime = SysTime(Date(-2000, 2, 29));
3036             sysTime.add!"years"(1, AllowDayOverflow.no);
3037             assert(sysTime == SysTime(Date(-1999, 2, 28)));
3038         }
3039 
3040         {
3041             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 7, 3), msecs(234));
3042             sysTime.add!"years"(-7, AllowDayOverflow.no);
3043             assert(sysTime == SysTime(DateTime(-2006, 7, 6, 12, 7, 3), msecs(234)));
3044             sysTime.add!"years"(9, AllowDayOverflow.no);
3045             assert(sysTime == SysTime(DateTime(-1997, 7, 6, 12, 7, 3), msecs(234)));
3046         }
3047 
3048         {
3049             auto sysTime = SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3));
3050             sysTime.add!"years"(-1, AllowDayOverflow.no);
3051             assert(sysTime == SysTime(DateTime(-2000, 2, 28, 3, 3, 3), hnsecs(3)));
3052         }
3053 
3054         {
3055             auto sysTime = SysTime(DateTime(-2000, 2, 29, 3, 3, 3), hnsecs(3));
3056             sysTime.add!"years"(1, AllowDayOverflow.no);
3057             assert(sysTime == SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3)));
3058         }
3059 
3060         // Test Both
3061         {
3062             auto sysTime = SysTime(Date(4, 7, 6));
3063             sysTime.add!"years"(-5, AllowDayOverflow.no);
3064             assert(sysTime == SysTime(Date(-1, 7, 6)));
3065             sysTime.add!"years"(5, AllowDayOverflow.no);
3066             assert(sysTime == SysTime(Date(4, 7, 6)));
3067         }
3068 
3069         {
3070             auto sysTime = SysTime(Date(-4, 7, 6));
3071             sysTime.add!"years"(5, AllowDayOverflow.no);
3072             assert(sysTime == SysTime(Date(1, 7, 6)));
3073             sysTime.add!"years"(-5, AllowDayOverflow.no);
3074             assert(sysTime == SysTime(Date(-4, 7, 6)));
3075         }
3076 
3077         {
3078             auto sysTime = SysTime(Date(4, 7, 6));
3079             sysTime.add!"years"(-8, AllowDayOverflow.no);
3080             assert(sysTime == SysTime(Date(-4, 7, 6)));
3081             sysTime.add!"years"(8, AllowDayOverflow.no);
3082             assert(sysTime == SysTime(Date(4, 7, 6)));
3083         }
3084 
3085         {
3086             auto sysTime = SysTime(Date(-4, 7, 6));
3087             sysTime.add!"years"(8, AllowDayOverflow.no);
3088             assert(sysTime == SysTime(Date(4, 7, 6)));
3089             sysTime.add!"years"(-8, AllowDayOverflow.no);
3090             assert(sysTime == SysTime(Date(-4, 7, 6)));
3091         }
3092 
3093         {
3094             auto sysTime = SysTime(Date(-4, 2, 29));
3095             sysTime.add!"years"(5, AllowDayOverflow.no);
3096             assert(sysTime == SysTime(Date(1, 2, 28)));
3097         }
3098 
3099         {
3100             auto sysTime = SysTime(Date(4, 2, 29));
3101             sysTime.add!"years"(-5, AllowDayOverflow.no);
3102             assert(sysTime == SysTime(Date(-1, 2, 28)));
3103         }
3104 
3105         {
3106             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
3107             sysTime.add!"years"(-1, AllowDayOverflow.no);
3108             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
3109             sysTime.add!"years"(1, AllowDayOverflow.no);
3110             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3111         }
3112 
3113         {
3114             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3115             sysTime.add!"years"(-1, AllowDayOverflow.no);
3116             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3117             sysTime.add!"years"(1, AllowDayOverflow.no);
3118             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3119         }
3120 
3121         {
3122             auto sysTime = SysTime(DateTime(0, 1, 1, 0, 0, 0));
3123             sysTime.add!"years"(1, AllowDayOverflow.no);
3124             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3125             sysTime.add!"years"(-1, AllowDayOverflow.no);
3126             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
3127         }
3128 
3129         {
3130             auto sysTime = SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3131             sysTime.add!"years"(1, AllowDayOverflow.no);
3132             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3133             sysTime.add!"years"(-1, AllowDayOverflow.no);
3134             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3135         }
3136 
3137         {
3138             auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
3139             sysTime.add!"years"(-5);
3140             assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
3141             sysTime.add!"years"(5);
3142             assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
3143         }
3144 
3145         {
3146             auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
3147             sysTime.add!"years"(-5, AllowDayOverflow.no);
3148             assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
3149             sysTime.add!"years"(5, AllowDayOverflow.no);
3150             assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
3151         }
3152 
3153         {
3154             auto sysTime = SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329));
3155             sysTime.add!"years"(5, AllowDayOverflow.no);
3156             assert(sysTime == SysTime(DateTime(1, 7, 6, 14, 7, 1), usecs(54329)));
3157             sysTime.add!"years"(-5, AllowDayOverflow.no);
3158             assert(sysTime == SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329)));
3159         }
3160 
3161         {
3162             auto sysTime = SysTime(DateTime(-4, 2, 29, 5, 5, 5), msecs(555));
3163             sysTime.add!"years"(5, AllowDayOverflow.no);
3164             assert(sysTime == SysTime(DateTime(1, 2, 28, 5, 5, 5), msecs(555)));
3165         }
3166 
3167         {
3168             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
3169             sysTime.add!"years"(-5, AllowDayOverflow.no);
3170             assert(sysTime == SysTime(DateTime(-1, 2, 28, 5, 5, 5), msecs(555)));
3171         }
3172 
3173         {
3174             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
3175             sysTime.add!"years"(-5, AllowDayOverflow.no).add!"years"(7, AllowDayOverflow.no);
3176             assert(sysTime == SysTime(DateTime(6, 2, 28, 5, 5, 5), msecs(555)));
3177         }
3178     }
3179 
3180     // Test add!"months"() with AllowDayOverflow.yes
3181     @safe unittest
3182     {
3183         import core.time;
3184         // Test A.D.
3185         {
3186             auto sysTime = SysTime(Date(1999, 7, 6));
3187             sysTime.add!"months"(3);
3188             assert(sysTime == SysTime(Date(1999, 10, 6)));
3189             sysTime.add!"months"(-4);
3190             assert(sysTime == SysTime(Date(1999, 6, 6)));
3191         }
3192 
3193         {
3194             auto sysTime = SysTime(Date(1999, 7, 6));
3195             sysTime.add!"months"(6);
3196             assert(sysTime == SysTime(Date(2000, 1, 6)));
3197             sysTime.add!"months"(-6);
3198             assert(sysTime == SysTime(Date(1999, 7, 6)));
3199         }
3200 
3201         {
3202             auto sysTime = SysTime(Date(1999, 7, 6));
3203             sysTime.add!"months"(27);
3204             assert(sysTime == SysTime(Date(2001, 10, 6)));
3205             sysTime.add!"months"(-28);
3206             assert(sysTime == SysTime(Date(1999, 6, 6)));
3207         }
3208 
3209         {
3210             auto sysTime = SysTime(Date(1999, 5, 31));
3211             sysTime.add!"months"(1);
3212             assert(sysTime == SysTime(Date(1999, 7, 1)));
3213         }
3214 
3215         {
3216             auto sysTime = SysTime(Date(1999, 5, 31));
3217             sysTime.add!"months"(-1);
3218             assert(sysTime == SysTime(Date(1999, 5, 1)));
3219         }
3220 
3221         {
3222             auto sysTime = SysTime(Date(1999, 2, 28));
3223             sysTime.add!"months"(12);
3224             assert(sysTime == SysTime(Date(2000, 2, 28)));
3225         }
3226 
3227         {
3228             auto sysTime = SysTime(Date(2000, 2, 29));
3229             sysTime.add!"months"(12);
3230             assert(sysTime == SysTime(Date(2001, 3, 1)));
3231         }
3232 
3233         {
3234             auto sysTime = SysTime(Date(1999, 7, 31));
3235             sysTime.add!"months"(1);
3236             assert(sysTime == SysTime(Date(1999, 8, 31)));
3237             sysTime.add!"months"(1);
3238             assert(sysTime == SysTime(Date(1999, 10, 1)));
3239         }
3240 
3241         {
3242             auto sysTime = SysTime(Date(1998, 8, 31));
3243             sysTime.add!"months"(13);
3244             assert(sysTime == SysTime(Date(1999, 10, 1)));
3245             sysTime.add!"months"(-13);
3246             assert(sysTime == SysTime(Date(1998, 9, 1)));
3247         }
3248 
3249         {
3250             auto sysTime = SysTime(Date(1997, 12, 31));
3251             sysTime.add!"months"(13);
3252             assert(sysTime == SysTime(Date(1999, 1, 31)));
3253             sysTime.add!"months"(-13);
3254             assert(sysTime == SysTime(Date(1997, 12, 31)));
3255         }
3256 
3257         {
3258             auto sysTime = SysTime(Date(1997, 12, 31));
3259             sysTime.add!"months"(14);
3260             assert(sysTime == SysTime(Date(1999, 3, 3)));
3261             sysTime.add!"months"(-14);
3262             assert(sysTime == SysTime(Date(1998, 1, 3)));
3263         }
3264 
3265         {
3266             auto sysTime = SysTime(Date(1998, 12, 31));
3267             sysTime.add!"months"(14);
3268             assert(sysTime == SysTime(Date(2000, 3, 2)));
3269             sysTime.add!"months"(-14);
3270             assert(sysTime == SysTime(Date(1999, 1, 2)));
3271         }
3272 
3273         {
3274             auto sysTime = SysTime(Date(1999, 12, 31));
3275             sysTime.add!"months"(14);
3276             assert(sysTime == SysTime(Date(2001, 3, 3)));
3277             sysTime.add!"months"(-14);
3278             assert(sysTime == SysTime(Date(2000, 1, 3)));
3279         }
3280 
3281         {
3282             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
3283             sysTime.add!"months"(3);
3284             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
3285             sysTime.add!"months"(-4);
3286             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
3287         }
3288 
3289         {
3290             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
3291             sysTime.add!"months"(14);
3292             assert(sysTime == SysTime(DateTime(2000, 3, 2, 7, 7, 7), hnsecs(422202)));
3293             sysTime.add!"months"(-14);
3294             assert(sysTime == SysTime(DateTime(1999, 1, 2, 7, 7, 7), hnsecs(422202)));
3295         }
3296 
3297         {
3298             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
3299             sysTime.add!"months"(14);
3300             assert(sysTime == SysTime(DateTime(2001, 3, 3, 7, 7, 7), hnsecs(422202)));
3301             sysTime.add!"months"(-14);
3302             assert(sysTime == SysTime(DateTime(2000, 1, 3, 7, 7, 7), hnsecs(422202)));
3303         }
3304 
3305         // Test B.C.
3306         {
3307             auto sysTime = SysTime(Date(-1999, 7, 6));
3308             sysTime.add!"months"(3);
3309             assert(sysTime == SysTime(Date(-1999, 10, 6)));
3310             sysTime.add!"months"(-4);
3311             assert(sysTime == SysTime(Date(-1999, 6, 6)));
3312         }
3313 
3314         {
3315             auto sysTime = SysTime(Date(-1999, 7, 6));
3316             sysTime.add!"months"(6);
3317             assert(sysTime == SysTime(Date(-1998, 1, 6)));
3318             sysTime.add!"months"(-6);
3319             assert(sysTime == SysTime(Date(-1999, 7, 6)));
3320         }
3321 
3322         {
3323             auto sysTime = SysTime(Date(-1999, 7, 6));
3324             sysTime.add!"months"(-27);
3325             assert(sysTime == SysTime(Date(-2001, 4, 6)));
3326             sysTime.add!"months"(28);
3327             assert(sysTime == SysTime(Date(-1999, 8, 6)));
3328         }
3329 
3330         {
3331             auto sysTime = SysTime(Date(-1999, 5, 31));
3332             sysTime.add!"months"(1);
3333             assert(sysTime == SysTime(Date(-1999, 7, 1)));
3334         }
3335 
3336         {
3337             auto sysTime = SysTime(Date(-1999, 5, 31));
3338             sysTime.add!"months"(-1);
3339             assert(sysTime == SysTime(Date(-1999, 5, 1)));
3340         }
3341 
3342         {
3343             auto sysTime = SysTime(Date(-1999, 2, 28));
3344             sysTime.add!"months"(-12);
3345             assert(sysTime == SysTime(Date(-2000, 2, 28)));
3346         }
3347 
3348         {
3349             auto sysTime = SysTime(Date(-2000, 2, 29));
3350             sysTime.add!"months"(-12);
3351             assert(sysTime == SysTime(Date(-2001, 3, 1)));
3352         }
3353 
3354         {
3355             auto sysTime = SysTime(Date(-1999, 7, 31));
3356             sysTime.add!"months"(1);
3357             assert(sysTime == SysTime(Date(-1999, 8, 31)));
3358             sysTime.add!"months"(1);
3359             assert(sysTime == SysTime(Date(-1999, 10, 1)));
3360         }
3361 
3362         {
3363             auto sysTime = SysTime(Date(-1998, 8, 31));
3364             sysTime.add!"months"(13);
3365             assert(sysTime == SysTime(Date(-1997, 10, 1)));
3366             sysTime.add!"months"(-13);
3367             assert(sysTime == SysTime(Date(-1998, 9, 1)));
3368         }
3369 
3370         {
3371             auto sysTime = SysTime(Date(-1997, 12, 31));
3372             sysTime.add!"months"(13);
3373             assert(sysTime == SysTime(Date(-1995, 1, 31)));
3374             sysTime.add!"months"(-13);
3375             assert(sysTime == SysTime(Date(-1997, 12, 31)));
3376         }
3377 
3378         {
3379             auto sysTime = SysTime(Date(-1997, 12, 31));
3380             sysTime.add!"months"(14);
3381             assert(sysTime == SysTime(Date(-1995, 3, 3)));
3382             sysTime.add!"months"(-14);
3383             assert(sysTime == SysTime(Date(-1996, 1, 3)));
3384         }
3385 
3386         {
3387             auto sysTime = SysTime(Date(-2002, 12, 31));
3388             sysTime.add!"months"(14);
3389             assert(sysTime == SysTime(Date(-2000, 3, 2)));
3390             sysTime.add!"months"(-14);
3391             assert(sysTime == SysTime(Date(-2001, 1, 2)));
3392         }
3393 
3394         {
3395             auto sysTime = SysTime(Date(-2001, 12, 31));
3396             sysTime.add!"months"(14);
3397             assert(sysTime == SysTime(Date(-1999, 3, 3)));
3398             sysTime.add!"months"(-14);
3399             assert(sysTime == SysTime(Date(-2000, 1, 3)));
3400         }
3401 
3402         {
3403             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
3404             sysTime.add!"months"(3);
3405             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
3406             sysTime.add!"months"(-4);
3407             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
3408         }
3409 
3410         {
3411             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
3412             sysTime.add!"months"(14);
3413             assert(sysTime == SysTime(DateTime(-2000, 3, 2, 7, 7, 7), hnsecs(422202)));
3414             sysTime.add!"months"(-14);
3415             assert(sysTime == SysTime(DateTime(-2001, 1, 2, 7, 7, 7), hnsecs(422202)));
3416         }
3417 
3418         {
3419             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
3420             sysTime.add!"months"(14);
3421             assert(sysTime == SysTime(DateTime(-1999, 3, 3, 7, 7, 7), hnsecs(422202)));
3422             sysTime.add!"months"(-14);
3423             assert(sysTime == SysTime(DateTime(-2000, 1, 3, 7, 7, 7), hnsecs(422202)));
3424         }
3425 
3426         // Test Both
3427         {
3428             auto sysTime = SysTime(Date(1, 1, 1));
3429             sysTime.add!"months"(-1);
3430             assert(sysTime == SysTime(Date(0, 12, 1)));
3431             sysTime.add!"months"(1);
3432             assert(sysTime == SysTime(Date(1, 1, 1)));
3433         }
3434 
3435         {
3436             auto sysTime = SysTime(Date(4, 1, 1));
3437             sysTime.add!"months"(-48);
3438             assert(sysTime == SysTime(Date(0, 1, 1)));
3439             sysTime.add!"months"(48);
3440             assert(sysTime == SysTime(Date(4, 1, 1)));
3441         }
3442 
3443         {
3444             auto sysTime = SysTime(Date(4, 3, 31));
3445             sysTime.add!"months"(-49);
3446             assert(sysTime == SysTime(Date(0, 3, 2)));
3447             sysTime.add!"months"(49);
3448             assert(sysTime == SysTime(Date(4, 4, 2)));
3449         }
3450 
3451         {
3452             auto sysTime = SysTime(Date(4, 3, 31));
3453             sysTime.add!"months"(-85);
3454             assert(sysTime == SysTime(Date(-3, 3, 3)));
3455             sysTime.add!"months"(85);
3456             assert(sysTime == SysTime(Date(4, 4, 3)));
3457         }
3458 
3459         {
3460             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
3461             sysTime.add!"months"(-1);
3462             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3463             sysTime.add!"months"(1);
3464             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3465         }
3466 
3467         {
3468             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3469             sysTime.add!"months"(-1);
3470             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3471             sysTime.add!"months"(1);
3472             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3473         }
3474 
3475         {
3476             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
3477             sysTime.add!"months"(1);
3478             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3479             sysTime.add!"months"(-1);
3480             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3481         }
3482 
3483         {
3484             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
3485             sysTime.add!"months"(1);
3486             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3487             sysTime.add!"months"(-1);
3488             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3489         }
3490 
3491         {
3492             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
3493             sysTime.add!"months"(-1);
3494             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 7, 9), hnsecs(17)));
3495             sysTime.add!"months"(1);
3496             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
3497         }
3498 
3499         {
3500             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
3501             sysTime.add!"months"(-85);
3502             assert(sysTime == SysTime(DateTime(-3, 3, 3, 12, 11, 10), msecs(9)));
3503             sysTime.add!"months"(85);
3504             assert(sysTime == SysTime(DateTime(4, 4, 3, 12, 11, 10), msecs(9)));
3505         }
3506 
3507         {
3508             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3509             sysTime.add!"months"(85);
3510             assert(sysTime == SysTime(DateTime(4, 5, 1, 12, 11, 10), msecs(9)));
3511             sysTime.add!"months"(-85);
3512             assert(sysTime == SysTime(DateTime(-3, 4, 1, 12, 11, 10), msecs(9)));
3513         }
3514 
3515         {
3516             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3517             sysTime.add!"months"(85).add!"months"(-83);
3518             assert(sysTime == SysTime(DateTime(-3, 6, 1, 12, 11, 10), msecs(9)));
3519         }
3520 
3521         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3522         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3523         static assert(!__traits(compiles, cst.add!"months"(4)));
3524         static assert(!__traits(compiles, ist.add!"months"(4)));
3525 
3526         static void testScope(scope ref SysTime st) @safe
3527         {
3528             auto result = st.add!"months"(42);
3529         }
3530     }
3531 
3532     // Test add!"months"() with AllowDayOverflow.no
3533     @safe unittest
3534     {
3535         import core.time;
3536         // Test A.D.
3537         {
3538             auto sysTime = SysTime(Date(1999, 7, 6));
3539             sysTime.add!"months"(3, AllowDayOverflow.no);
3540             assert(sysTime == SysTime(Date(1999, 10, 6)));
3541             sysTime.add!"months"(-4, AllowDayOverflow.no);
3542             assert(sysTime == SysTime(Date(1999, 6, 6)));
3543         }
3544 
3545         {
3546             auto sysTime = SysTime(Date(1999, 7, 6));
3547             sysTime.add!"months"(6, AllowDayOverflow.no);
3548             assert(sysTime == SysTime(Date(2000, 1, 6)));
3549             sysTime.add!"months"(-6, AllowDayOverflow.no);
3550             assert(sysTime == SysTime(Date(1999, 7, 6)));
3551         }
3552 
3553         {
3554             auto sysTime = SysTime(Date(1999, 7, 6));
3555             sysTime.add!"months"(27, AllowDayOverflow.no);
3556             assert(sysTime == SysTime(Date(2001, 10, 6)));
3557             sysTime.add!"months"(-28, AllowDayOverflow.no);
3558             assert(sysTime == SysTime(Date(1999, 6, 6)));
3559         }
3560 
3561         {
3562             auto sysTime = SysTime(Date(1999, 5, 31));
3563             sysTime.add!"months"(1, AllowDayOverflow.no);
3564             assert(sysTime == SysTime(Date(1999, 6, 30)));
3565         }
3566 
3567         {
3568             auto sysTime = SysTime(Date(1999, 5, 31));
3569             sysTime.add!"months"(-1, AllowDayOverflow.no);
3570             assert(sysTime == SysTime(Date(1999, 4, 30)));
3571         }
3572 
3573         {
3574             auto sysTime = SysTime(Date(1999, 2, 28));
3575             sysTime.add!"months"(12, AllowDayOverflow.no);
3576             assert(sysTime == SysTime(Date(2000, 2, 28)));
3577         }
3578 
3579         {
3580             auto sysTime = SysTime(Date(2000, 2, 29));
3581             sysTime.add!"months"(12, AllowDayOverflow.no);
3582             assert(sysTime == SysTime(Date(2001, 2, 28)));
3583         }
3584 
3585         {
3586             auto sysTime = SysTime(Date(1999, 7, 31));
3587             sysTime.add!"months"(1, AllowDayOverflow.no);
3588             assert(sysTime == SysTime(Date(1999, 8, 31)));
3589             sysTime.add!"months"(1, AllowDayOverflow.no);
3590             assert(sysTime == SysTime(Date(1999, 9, 30)));
3591         }
3592 
3593         {
3594             auto sysTime = SysTime(Date(1998, 8, 31));
3595             sysTime.add!"months"(13, AllowDayOverflow.no);
3596             assert(sysTime == SysTime(Date(1999, 9, 30)));
3597             sysTime.add!"months"(-13, AllowDayOverflow.no);
3598             assert(sysTime == SysTime(Date(1998, 8, 30)));
3599         }
3600 
3601         {
3602             auto sysTime = SysTime(Date(1997, 12, 31));
3603             sysTime.add!"months"(13, AllowDayOverflow.no);
3604             assert(sysTime == SysTime(Date(1999, 1, 31)));
3605             sysTime.add!"months"(-13, AllowDayOverflow.no);
3606             assert(sysTime == SysTime(Date(1997, 12, 31)));
3607         }
3608 
3609         {
3610             auto sysTime = SysTime(Date(1997, 12, 31));
3611             sysTime.add!"months"(14, AllowDayOverflow.no);
3612             assert(sysTime == SysTime(Date(1999, 2, 28)));
3613             sysTime.add!"months"(-14, AllowDayOverflow.no);
3614             assert(sysTime == SysTime(Date(1997, 12, 28)));
3615         }
3616 
3617         {
3618             auto sysTime = SysTime(Date(1998, 12, 31));
3619             sysTime.add!"months"(14, AllowDayOverflow.no);
3620             assert(sysTime == SysTime(Date(2000, 2, 29)));
3621             sysTime.add!"months"(-14, AllowDayOverflow.no);
3622             assert(sysTime == SysTime(Date(1998, 12, 29)));
3623         }
3624 
3625         {
3626             auto sysTime = SysTime(Date(1999, 12, 31));
3627             sysTime.add!"months"(14, AllowDayOverflow.no);
3628             assert(sysTime == SysTime(Date(2001, 2, 28)));
3629             sysTime.add!"months"(-14, AllowDayOverflow.no);
3630             assert(sysTime == SysTime(Date(1999, 12, 28)));
3631         }
3632 
3633         {
3634             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
3635             sysTime.add!"months"(3, AllowDayOverflow.no);
3636             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
3637             sysTime.add!"months"(-4, AllowDayOverflow.no);
3638             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
3639         }
3640 
3641         {
3642             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
3643             sysTime.add!"months"(14, AllowDayOverflow.no);
3644             assert(sysTime == SysTime(DateTime(2000, 2, 29, 7, 7, 7), hnsecs(422202)));
3645             sysTime.add!"months"(-14, AllowDayOverflow.no);
3646             assert(sysTime == SysTime(DateTime(1998, 12, 29, 7, 7, 7), hnsecs(422202)));
3647         }
3648 
3649         {
3650             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
3651             sysTime.add!"months"(14, AllowDayOverflow.no);
3652             assert(sysTime == SysTime(DateTime(2001, 2, 28, 7, 7, 7), hnsecs(422202)));
3653             sysTime.add!"months"(-14, AllowDayOverflow.no);
3654             assert(sysTime == SysTime(DateTime(1999, 12, 28, 7, 7, 7), hnsecs(422202)));
3655         }
3656 
3657         // Test B.C.
3658         {
3659             auto sysTime = SysTime(Date(-1999, 7, 6));
3660             sysTime.add!"months"(3, AllowDayOverflow.no);
3661             assert(sysTime == SysTime(Date(-1999, 10, 6)));
3662             sysTime.add!"months"(-4, AllowDayOverflow.no);
3663             assert(sysTime == SysTime(Date(-1999, 6, 6)));
3664         }
3665 
3666         {
3667             auto sysTime = SysTime(Date(-1999, 7, 6));
3668             sysTime.add!"months"(6, AllowDayOverflow.no);
3669             assert(sysTime == SysTime(Date(-1998, 1, 6)));
3670             sysTime.add!"months"(-6, AllowDayOverflow.no);
3671             assert(sysTime == SysTime(Date(-1999, 7, 6)));
3672         }
3673 
3674         {
3675             auto sysTime = SysTime(Date(-1999, 7, 6));
3676             sysTime.add!"months"(-27, AllowDayOverflow.no);
3677             assert(sysTime == SysTime(Date(-2001, 4, 6)));
3678             sysTime.add!"months"(28, AllowDayOverflow.no);
3679             assert(sysTime == SysTime(Date(-1999, 8, 6)));
3680         }
3681 
3682         {
3683             auto sysTime = SysTime(Date(-1999, 5, 31));
3684             sysTime.add!"months"(1, AllowDayOverflow.no);
3685             assert(sysTime == SysTime(Date(-1999, 6, 30)));
3686         }
3687 
3688         {
3689             auto sysTime = SysTime(Date(-1999, 5, 31));
3690             sysTime.add!"months"(-1, AllowDayOverflow.no);
3691             assert(sysTime == SysTime(Date(-1999, 4, 30)));
3692         }
3693 
3694         {
3695             auto sysTime = SysTime(Date(-1999, 2, 28));
3696             sysTime.add!"months"(-12, AllowDayOverflow.no);
3697             assert(sysTime == SysTime(Date(-2000, 2, 28)));
3698         }
3699 
3700         {
3701             auto sysTime = SysTime(Date(-2000, 2, 29));
3702             sysTime.add!"months"(-12, AllowDayOverflow.no);
3703             assert(sysTime == SysTime(Date(-2001, 2, 28)));
3704         }
3705 
3706         {
3707             auto sysTime = SysTime(Date(-1999, 7, 31));
3708             sysTime.add!"months"(1, AllowDayOverflow.no);
3709             assert(sysTime == SysTime(Date(-1999, 8, 31)));
3710             sysTime.add!"months"(1, AllowDayOverflow.no);
3711             assert(sysTime == SysTime(Date(-1999, 9, 30)));
3712         }
3713 
3714         {
3715             auto sysTime = SysTime(Date(-1998, 8, 31));
3716             sysTime.add!"months"(13, AllowDayOverflow.no);
3717             assert(sysTime == SysTime(Date(-1997, 9, 30)));
3718             sysTime.add!"months"(-13, AllowDayOverflow.no);
3719             assert(sysTime == SysTime(Date(-1998, 8, 30)));
3720         }
3721 
3722         {
3723             auto sysTime = SysTime(Date(-1997, 12, 31));
3724             sysTime.add!"months"(13, AllowDayOverflow.no);
3725             assert(sysTime == SysTime(Date(-1995, 1, 31)));
3726             sysTime.add!"months"(-13, AllowDayOverflow.no);
3727             assert(sysTime == SysTime(Date(-1997, 12, 31)));
3728         }
3729 
3730         {
3731             auto sysTime = SysTime(Date(-1997, 12, 31));
3732             sysTime.add!"months"(14, AllowDayOverflow.no);
3733             assert(sysTime == SysTime(Date(-1995, 2, 28)));
3734             sysTime.add!"months"(-14, AllowDayOverflow.no);
3735             assert(sysTime == SysTime(Date(-1997, 12, 28)));
3736         }
3737 
3738         {
3739             auto sysTime = SysTime(Date(-2002, 12, 31));
3740             sysTime.add!"months"(14, AllowDayOverflow.no);
3741             assert(sysTime == SysTime(Date(-2000, 2, 29)));
3742             sysTime.add!"months"(-14, AllowDayOverflow.no);
3743             assert(sysTime == SysTime(Date(-2002, 12, 29)));
3744         }
3745 
3746         {
3747             auto sysTime = SysTime(Date(-2001, 12, 31));
3748             sysTime.add!"months"(14, AllowDayOverflow.no);
3749             assert(sysTime == SysTime(Date(-1999, 2, 28)));
3750             sysTime.add!"months"(-14, AllowDayOverflow.no);
3751             assert(sysTime == SysTime(Date(-2001, 12, 28)));
3752         }
3753 
3754         {
3755             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
3756             sysTime.add!"months"(3, AllowDayOverflow.no);
3757             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
3758             sysTime.add!"months"(-4, AllowDayOverflow.no);
3759             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
3760         }
3761 
3762         {
3763             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
3764             sysTime.add!"months"(14, AllowDayOverflow.no);
3765             assert(sysTime == SysTime(DateTime(-2000, 2, 29, 7, 7, 7), hnsecs(422202)));
3766             sysTime.add!"months"(-14, AllowDayOverflow.no);
3767             assert(sysTime == SysTime(DateTime(-2002, 12, 29, 7, 7, 7), hnsecs(422202)));
3768         }
3769 
3770         {
3771             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
3772             sysTime.add!"months"(14, AllowDayOverflow.no);
3773             assert(sysTime == SysTime(DateTime(-1999, 2, 28, 7, 7, 7), hnsecs(422202)));
3774             sysTime.add!"months"(-14, AllowDayOverflow.no);
3775             assert(sysTime == SysTime(DateTime(-2001, 12, 28, 7, 7, 7), hnsecs(422202)));
3776         }
3777 
3778         // Test Both
3779         {
3780             auto sysTime = SysTime(Date(1, 1, 1));
3781             sysTime.add!"months"(-1, AllowDayOverflow.no);
3782             assert(sysTime == SysTime(Date(0, 12, 1)));
3783             sysTime.add!"months"(1, AllowDayOverflow.no);
3784             assert(sysTime == SysTime(Date(1, 1, 1)));
3785         }
3786 
3787         {
3788             auto sysTime = SysTime(Date(4, 1, 1));
3789             sysTime.add!"months"(-48, AllowDayOverflow.no);
3790             assert(sysTime == SysTime(Date(0, 1, 1)));
3791             sysTime.add!"months"(48, AllowDayOverflow.no);
3792             assert(sysTime == SysTime(Date(4, 1, 1)));
3793         }
3794 
3795         {
3796             auto sysTime = SysTime(Date(4, 3, 31));
3797             sysTime.add!"months"(-49, AllowDayOverflow.no);
3798             assert(sysTime == SysTime(Date(0, 2, 29)));
3799             sysTime.add!"months"(49, AllowDayOverflow.no);
3800             assert(sysTime == SysTime(Date(4, 3, 29)));
3801         }
3802 
3803         {
3804             auto sysTime = SysTime(Date(4, 3, 31));
3805             sysTime.add!"months"(-85, AllowDayOverflow.no);
3806             assert(sysTime == SysTime(Date(-3, 2, 28)));
3807             sysTime.add!"months"(85, AllowDayOverflow.no);
3808             assert(sysTime == SysTime(Date(4, 3, 28)));
3809         }
3810 
3811         {
3812             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
3813             sysTime.add!"months"(-1, AllowDayOverflow.no);
3814             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3815             sysTime.add!"months"(1, AllowDayOverflow.no);
3816             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3817         }
3818 
3819         {
3820             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3821             sysTime.add!"months"(-1, AllowDayOverflow.no);
3822             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3823             sysTime.add!"months"(1, AllowDayOverflow.no);
3824             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3825         }
3826 
3827         {
3828             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
3829             sysTime.add!"months"(1, AllowDayOverflow.no);
3830             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3831             sysTime.add!"months"(-1, AllowDayOverflow.no);
3832             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3833         }
3834 
3835         {
3836             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
3837             sysTime.add!"months"(1, AllowDayOverflow.no);
3838             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3839             sysTime.add!"months"(-1, AllowDayOverflow.no);
3840             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3841         }
3842 
3843         {
3844             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
3845             sysTime.add!"months"(-1, AllowDayOverflow.no);
3846             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 7, 9), hnsecs(17)));
3847             sysTime.add!"months"(1, AllowDayOverflow.no);
3848             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
3849         }
3850 
3851         {
3852             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
3853             sysTime.add!"months"(-85, AllowDayOverflow.no);
3854             assert(sysTime == SysTime(DateTime(-3, 2, 28, 12, 11, 10), msecs(9)));
3855             sysTime.add!"months"(85, AllowDayOverflow.no);
3856             assert(sysTime == SysTime(DateTime(4, 3, 28, 12, 11, 10), msecs(9)));
3857         }
3858 
3859         {
3860             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3861             sysTime.add!"months"(85, AllowDayOverflow.no);
3862             assert(sysTime == SysTime(DateTime(4, 4, 30, 12, 11, 10), msecs(9)));
3863             sysTime.add!"months"(-85, AllowDayOverflow.no);
3864             assert(sysTime == SysTime(DateTime(-3, 3, 30, 12, 11, 10), msecs(9)));
3865         }
3866 
3867         {
3868             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3869             sysTime.add!"months"(85, AllowDayOverflow.no).add!"months"(-83, AllowDayOverflow.no);
3870             assert(sysTime == SysTime(DateTime(-3, 5, 30, 12, 11, 10), msecs(9)));
3871         }
3872     }
3873 
3874 
3875     /++
3876         Adds the given number of years or months to this $(LREF SysTime). A
3877         negative number will subtract.
3878 
3879         The difference between rolling and adding is that rolling does not
3880         affect larger units. Rolling a $(LREF SysTime) 12 months
3881         gets the exact same $(LREF SysTime). However, the days can still be
3882         affected due to the differing number of days in each month.
3883 
3884         Because there are no units larger than years, there is no difference
3885         between adding and rolling years.
3886 
3887         Params:
3888             units         = The type of units to add ("years" or "months").
3889             value         = The number of months or years to add to this
3890                             $(LREF SysTime).
3891             allowOverflow = Whether the days should be allowed to overflow,
3892                             causing the month to increment.
3893       +/
3894     ref SysTime roll(string units)
3895                     (long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow scope
3896     if (units == "years")
3897     {
3898         return add!"years"(value, allowOverflow);
3899     }
3900 
3901     ///
3902     @safe unittest
3903     {
3904         import std.datetime.date : AllowDayOverflow, DateTime;
3905 
3906         auto st1 = SysTime(DateTime(2010, 1, 1, 12, 33, 33));
3907         st1.roll!"months"(1);
3908         assert(st1 == SysTime(DateTime(2010, 2, 1, 12, 33, 33)));
3909 
3910         auto st2 = SysTime(DateTime(2010, 1, 1, 12, 33, 33));
3911         st2.roll!"months"(-1);
3912         assert(st2 == SysTime(DateTime(2010, 12, 1, 12, 33, 33)));
3913 
3914         auto st3 = SysTime(DateTime(1999, 1, 29, 12, 33, 33));
3915         st3.roll!"months"(1);
3916         assert(st3 == SysTime(DateTime(1999, 3, 1, 12, 33, 33)));
3917 
3918         auto st4 = SysTime(DateTime(1999, 1, 29, 12, 33, 33));
3919         st4.roll!"months"(1, AllowDayOverflow.no);
3920         assert(st4 == SysTime(DateTime(1999, 2, 28, 12, 33, 33)));
3921 
3922         auto st5 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
3923         st5.roll!"years"(1);
3924         assert(st5 == SysTime(DateTime(2001, 3, 1, 12, 30, 33)));
3925 
3926         auto st6 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
3927         st6.roll!"years"(1, AllowDayOverflow.no);
3928         assert(st6 == SysTime(DateTime(2001, 2, 28, 12, 30, 33)));
3929     }
3930 
3931     @safe unittest
3932     {
3933         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3934         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3935         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3936         st.roll!"years"(4);
3937         static assert(!__traits(compiles, cst.roll!"years"(4)));
3938         static assert(!__traits(compiles, ist.roll!"years"(4)));
3939 
3940         static void testScope(scope ref SysTime st) @safe
3941         {
3942             auto result = st.roll!"years"(42);
3943         }
3944     }
3945 
3946 
3947     // Shares documentation with "years" overload.
3948     ref SysTime roll(string units)
3949                     (long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow scope
3950     if (units == "months")
3951     {
3952         auto hnsecs = adjTime;
3953         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
3954 
3955         if (hnsecs < 0)
3956         {
3957             hnsecs += convert!("hours", "hnsecs")(24);
3958             --days;
3959         }
3960 
3961         auto date = Date(cast(int) days);
3962         date.roll!"months"(value, allowOverflow);
3963         days = date.dayOfGregorianCal - 1;
3964 
3965         if (days < 0)
3966         {
3967             hnsecs -= convert!("hours", "hnsecs")(24);
3968             ++days;
3969         }
3970 
3971         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
3972         adjTime = newDaysHNSecs + hnsecs;
3973         return this;
3974     }
3975 
3976     // Test roll!"months"() with AllowDayOverflow.yes
3977     @safe unittest
3978     {
3979         import core.time;
3980         // Test A.D.
3981         {
3982             auto sysTime = SysTime(Date(1999, 7, 6));
3983             sysTime.roll!"months"(3);
3984             assert(sysTime == SysTime(Date(1999, 10, 6)));
3985             sysTime.roll!"months"(-4);
3986             assert(sysTime == SysTime(Date(1999, 6, 6)));
3987         }
3988 
3989         {
3990             auto sysTime = SysTime(Date(1999, 7, 6));
3991             sysTime.roll!"months"(6);
3992             assert(sysTime == SysTime(Date(1999, 1, 6)));
3993             sysTime.roll!"months"(-6);
3994             assert(sysTime == SysTime(Date(1999, 7, 6)));
3995         }
3996 
3997         {
3998             auto sysTime = SysTime(Date(1999, 7, 6));
3999             sysTime.roll!"months"(27);
4000             assert(sysTime == SysTime(Date(1999, 10, 6)));
4001             sysTime.roll!"months"(-28);
4002             assert(sysTime == SysTime(Date(1999, 6, 6)));
4003         }
4004 
4005         {
4006             auto sysTime = SysTime(Date(1999, 5, 31));
4007             sysTime.roll!"months"(1);
4008             assert(sysTime == SysTime(Date(1999, 7, 1)));
4009         }
4010 
4011         {
4012             auto sysTime = SysTime(Date(1999, 5, 31));
4013             sysTime.roll!"months"(-1);
4014             assert(sysTime == SysTime(Date(1999, 5, 1)));
4015         }
4016 
4017         {
4018             auto sysTime = SysTime(Date(1999, 2, 28));
4019             sysTime.roll!"months"(12);
4020             assert(sysTime == SysTime(Date(1999, 2, 28)));
4021         }
4022 
4023         {
4024             auto sysTime = SysTime(Date(2000, 2, 29));
4025             sysTime.roll!"months"(12);
4026             assert(sysTime == SysTime(Date(2000, 2, 29)));
4027         }
4028 
4029         {
4030             auto sysTime = SysTime(Date(1999, 7, 31));
4031             sysTime.roll!"months"(1);
4032             assert(sysTime == SysTime(Date(1999, 8, 31)));
4033             sysTime.roll!"months"(1);
4034             assert(sysTime == SysTime(Date(1999, 10, 1)));
4035         }
4036 
4037         {
4038             auto sysTime = SysTime(Date(1998, 8, 31));
4039             sysTime.roll!"months"(13);
4040             assert(sysTime == SysTime(Date(1998, 10, 1)));
4041             sysTime.roll!"months"(-13);
4042             assert(sysTime == SysTime(Date(1998, 9, 1)));
4043         }
4044 
4045         {
4046             auto sysTime = SysTime(Date(1997, 12, 31));
4047             sysTime.roll!"months"(13);
4048             assert(sysTime == SysTime(Date(1997, 1, 31)));
4049             sysTime.roll!"months"(-13);
4050             assert(sysTime == SysTime(Date(1997, 12, 31)));
4051         }
4052 
4053         {
4054             auto sysTime = SysTime(Date(1997, 12, 31));
4055             sysTime.roll!"months"(14);
4056             assert(sysTime == SysTime(Date(1997, 3, 3)));
4057             sysTime.roll!"months"(-14);
4058             assert(sysTime == SysTime(Date(1997, 1, 3)));
4059         }
4060 
4061         {
4062             auto sysTime = SysTime(Date(1998, 12, 31));
4063             sysTime.roll!"months"(14);
4064             assert(sysTime == SysTime(Date(1998, 3, 3)));
4065             sysTime.roll!"months"(-14);
4066             assert(sysTime == SysTime(Date(1998, 1, 3)));
4067         }
4068 
4069         {
4070             auto sysTime = SysTime(Date(1999, 12, 31));
4071             sysTime.roll!"months"(14);
4072             assert(sysTime == SysTime(Date(1999, 3, 3)));
4073             sysTime.roll!"months"(-14);
4074             assert(sysTime == SysTime(Date(1999, 1, 3)));
4075         }
4076 
4077         {
4078             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
4079             sysTime.roll!"months"(3);
4080             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
4081             sysTime.roll!"months"(-4);
4082             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
4083         }
4084 
4085         {
4086             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
4087             sysTime.roll!"months"(14);
4088             assert(sysTime == SysTime(DateTime(1998, 3, 3, 7, 7, 7), hnsecs(422202)));
4089             sysTime.roll!"months"(-14);
4090             assert(sysTime == SysTime(DateTime(1998, 1, 3, 7, 7, 7), hnsecs(422202)));
4091         }
4092 
4093         {
4094             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
4095             sysTime.roll!"months"(14);
4096             assert(sysTime == SysTime(DateTime(1999, 3, 3, 7, 7, 7), hnsecs(422202)));
4097             sysTime.roll!"months"(-14);
4098             assert(sysTime == SysTime(DateTime(1999, 1, 3, 7, 7, 7), hnsecs(422202)));
4099         }
4100 
4101         // Test B.C.
4102         {
4103             auto sysTime = SysTime(Date(-1999, 7, 6));
4104             sysTime.roll!"months"(3);
4105             assert(sysTime == SysTime(Date(-1999, 10, 6)));
4106             sysTime.roll!"months"(-4);
4107             assert(sysTime == SysTime(Date(-1999, 6, 6)));
4108         }
4109 
4110         {
4111             auto sysTime = SysTime(Date(-1999, 7, 6));
4112             sysTime.roll!"months"(6);
4113             assert(sysTime == SysTime(Date(-1999, 1, 6)));
4114             sysTime.roll!"months"(-6);
4115             assert(sysTime == SysTime(Date(-1999, 7, 6)));
4116         }
4117 
4118         {
4119             auto sysTime = SysTime(Date(-1999, 7, 6));
4120             sysTime.roll!"months"(-27);
4121             assert(sysTime == SysTime(Date(-1999, 4, 6)));
4122             sysTime.roll!"months"(28);
4123             assert(sysTime == SysTime(Date(-1999, 8, 6)));
4124         }
4125 
4126         {
4127             auto sysTime = SysTime(Date(-1999, 5, 31));
4128             sysTime.roll!"months"(1);
4129             assert(sysTime == SysTime(Date(-1999, 7, 1)));
4130         }
4131 
4132         {
4133             auto sysTime = SysTime(Date(-1999, 5, 31));
4134             sysTime.roll!"months"(-1);
4135             assert(sysTime == SysTime(Date(-1999, 5, 1)));
4136         }
4137 
4138         {
4139             auto sysTime = SysTime(Date(-1999, 2, 28));
4140             sysTime.roll!"months"(-12);
4141             assert(sysTime == SysTime(Date(-1999, 2, 28)));
4142         }
4143 
4144         {
4145             auto sysTime = SysTime(Date(-2000, 2, 29));
4146             sysTime.roll!"months"(-12);
4147             assert(sysTime == SysTime(Date(-2000, 2, 29)));
4148         }
4149 
4150         {
4151             auto sysTime = SysTime(Date(-1999, 7, 31));
4152             sysTime.roll!"months"(1);
4153             assert(sysTime == SysTime(Date(-1999, 8, 31)));
4154             sysTime.roll!"months"(1);
4155             assert(sysTime == SysTime(Date(-1999, 10, 1)));
4156         }
4157 
4158         {
4159             auto sysTime = SysTime(Date(-1998, 8, 31));
4160             sysTime.roll!"months"(13);
4161             assert(sysTime == SysTime(Date(-1998, 10, 1)));
4162             sysTime.roll!"months"(-13);
4163             assert(sysTime == SysTime(Date(-1998, 9, 1)));
4164         }
4165 
4166         {
4167             auto sysTime = SysTime(Date(-1997, 12, 31));
4168             sysTime.roll!"months"(13);
4169             assert(sysTime == SysTime(Date(-1997, 1, 31)));
4170             sysTime.roll!"months"(-13);
4171             assert(sysTime == SysTime(Date(-1997, 12, 31)));
4172         }
4173 
4174         {
4175             auto sysTime = SysTime(Date(-1997, 12, 31));
4176             sysTime.roll!"months"(14);
4177             assert(sysTime == SysTime(Date(-1997, 3, 3)));
4178             sysTime.roll!"months"(-14);
4179             assert(sysTime == SysTime(Date(-1997, 1, 3)));
4180         }
4181 
4182         {
4183             auto sysTime = SysTime(Date(-2002, 12, 31));
4184             sysTime.roll!"months"(14);
4185             assert(sysTime == SysTime(Date(-2002, 3, 3)));
4186             sysTime.roll!"months"(-14);
4187             assert(sysTime == SysTime(Date(-2002, 1, 3)));
4188         }
4189 
4190         {
4191             auto sysTime = SysTime(Date(-2001, 12, 31));
4192             sysTime.roll!"months"(14);
4193             assert(sysTime == SysTime(Date(-2001, 3, 3)));
4194             sysTime.roll!"months"(-14);
4195             assert(sysTime == SysTime(Date(-2001, 1, 3)));
4196         }
4197 
4198         {
4199             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
4200             sysTime.roll!"months"(-1);
4201             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 0, 0)));
4202             sysTime.roll!"months"(1);
4203             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
4204         }
4205 
4206         {
4207             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
4208             sysTime.roll!"months"(-1);
4209             assert(sysTime == SysTime(DateTime(1, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4210             sysTime.roll!"months"(1);
4211             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4212         }
4213 
4214         {
4215             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
4216             sysTime.roll!"months"(1);
4217             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
4218             sysTime.roll!"months"(-1);
4219             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
4220         }
4221 
4222         {
4223             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
4224             sysTime.roll!"months"(1);
4225             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4226             sysTime.roll!"months"(-1);
4227             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4228         }
4229 
4230         {
4231             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), hnsecs(5007));
4232             sysTime.roll!"months"(3);
4233             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), hnsecs(5007)));
4234             sysTime.roll!"months"(-4);
4235             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), hnsecs(5007)));
4236         }
4237 
4238         {
4239             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
4240             sysTime.roll!"months"(14);
4241             assert(sysTime == SysTime(DateTime(-2002, 3, 3, 7, 7, 7), hnsecs(422202)));
4242             sysTime.roll!"months"(-14);
4243             assert(sysTime == SysTime(DateTime(-2002, 1, 3, 7, 7, 7), hnsecs(422202)));
4244         }
4245 
4246         {
4247             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
4248             sysTime.roll!"months"(14);
4249             assert(sysTime == SysTime(DateTime(-2001, 3, 3, 7, 7, 7), hnsecs(422202)));
4250             sysTime.roll!"months"(-14);
4251             assert(sysTime == SysTime(DateTime(-2001, 1, 3, 7, 7, 7), hnsecs(422202)));
4252         }
4253 
4254         // Test Both
4255         {
4256             auto sysTime = SysTime(Date(1, 1, 1));
4257             sysTime.roll!"months"(-1);
4258             assert(sysTime == SysTime(Date(1, 12, 1)));
4259             sysTime.roll!"months"(1);
4260             assert(sysTime == SysTime(Date(1, 1, 1)));
4261         }
4262 
4263         {
4264             auto sysTime = SysTime(Date(4, 1, 1));
4265             sysTime.roll!"months"(-48);
4266             assert(sysTime == SysTime(Date(4, 1, 1)));
4267             sysTime.roll!"months"(48);
4268             assert(sysTime == SysTime(Date(4, 1, 1)));
4269         }
4270 
4271         {
4272             auto sysTime = SysTime(Date(4, 3, 31));
4273             sysTime.roll!"months"(-49);
4274             assert(sysTime == SysTime(Date(4, 3, 2)));
4275             sysTime.roll!"months"(49);
4276             assert(sysTime == SysTime(Date(4, 4, 2)));
4277         }
4278 
4279         {
4280             auto sysTime = SysTime(Date(4, 3, 31));
4281             sysTime.roll!"months"(-85);
4282             assert(sysTime == SysTime(Date(4, 3, 2)));
4283             sysTime.roll!"months"(85);
4284             assert(sysTime == SysTime(Date(4, 4, 2)));
4285         }
4286 
4287         {
4288             auto sysTime = SysTime(Date(-1, 1, 1));
4289             sysTime.roll!"months"(-1);
4290             assert(sysTime == SysTime(Date(-1, 12, 1)));
4291             sysTime.roll!"months"(1);
4292             assert(sysTime == SysTime(Date(-1, 1, 1)));
4293         }
4294 
4295         {
4296             auto sysTime = SysTime(Date(-4, 1, 1));
4297             sysTime.roll!"months"(-48);
4298             assert(sysTime == SysTime(Date(-4, 1, 1)));
4299             sysTime.roll!"months"(48);
4300             assert(sysTime == SysTime(Date(-4, 1, 1)));
4301         }
4302 
4303         {
4304             auto sysTime = SysTime(Date(-4, 3, 31));
4305             sysTime.roll!"months"(-49);
4306             assert(sysTime == SysTime(Date(-4, 3, 2)));
4307             sysTime.roll!"months"(49);
4308             assert(sysTime == SysTime(Date(-4, 4, 2)));
4309         }
4310 
4311         {
4312             auto sysTime = SysTime(Date(-4, 3, 31));
4313             sysTime.roll!"months"(-85);
4314             assert(sysTime == SysTime(Date(-4, 3, 2)));
4315             sysTime.roll!"months"(85);
4316             assert(sysTime == SysTime(Date(-4, 4, 2)));
4317         }
4318 
4319         {
4320             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
4321             sysTime.roll!"months"(-1);
4322             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 7, 9), hnsecs(17)));
4323             sysTime.roll!"months"(1);
4324             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
4325         }
4326 
4327         {
4328             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
4329             sysTime.roll!"months"(-85);
4330             assert(sysTime == SysTime(DateTime(4, 3, 2, 12, 11, 10), msecs(9)));
4331             sysTime.roll!"months"(85);
4332             assert(sysTime == SysTime(DateTime(4, 4, 2, 12, 11, 10), msecs(9)));
4333         }
4334 
4335         {
4336             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4337             sysTime.roll!"months"(85);
4338             assert(sysTime == SysTime(DateTime(-3, 5, 1, 12, 11, 10), msecs(9)));
4339             sysTime.roll!"months"(-85);
4340             assert(sysTime == SysTime(DateTime(-3, 4, 1, 12, 11, 10), msecs(9)));
4341         }
4342 
4343         {
4344             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4345             sysTime.roll!"months"(85).roll!"months"(-83);
4346             assert(sysTime == SysTime(DateTime(-3, 6, 1, 12, 11, 10), msecs(9)));
4347         }
4348 
4349         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4350         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4351         static assert(!__traits(compiles, cst.roll!"months"(4)));
4352         static assert(!__traits(compiles, ist.roll!"months"(4)));
4353 
4354         static void testScope(scope ref SysTime st) @safe
4355         {
4356             auto result = st.roll!"months"(42);
4357         }
4358     }
4359 
4360     // Test roll!"months"() with AllowDayOverflow.no
4361     @safe unittest
4362     {
4363         import core.time;
4364         // Test A.D.
4365         {
4366             auto sysTime = SysTime(Date(1999, 7, 6));
4367             sysTime.roll!"months"(3, AllowDayOverflow.no);
4368             assert(sysTime == SysTime(Date(1999, 10, 6)));
4369             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4370             assert(sysTime == SysTime(Date(1999, 6, 6)));
4371         }
4372 
4373         {
4374             auto sysTime = SysTime(Date(1999, 7, 6));
4375             sysTime.roll!"months"(6, AllowDayOverflow.no);
4376             assert(sysTime == SysTime(Date(1999, 1, 6)));
4377             sysTime.roll!"months"(-6, AllowDayOverflow.no);
4378             assert(sysTime == SysTime(Date(1999, 7, 6)));
4379         }
4380 
4381         {
4382             auto sysTime = SysTime(Date(1999, 7, 6));
4383             sysTime.roll!"months"(27, AllowDayOverflow.no);
4384             assert(sysTime == SysTime(Date(1999, 10, 6)));
4385             sysTime.roll!"months"(-28, AllowDayOverflow.no);
4386             assert(sysTime == SysTime(Date(1999, 6, 6)));
4387         }
4388 
4389         {
4390             auto sysTime = SysTime(Date(1999, 5, 31));
4391             sysTime.roll!"months"(1, AllowDayOverflow.no);
4392             assert(sysTime == SysTime(Date(1999, 6, 30)));
4393         }
4394 
4395         {
4396             auto sysTime = SysTime(Date(1999, 5, 31));
4397             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4398             assert(sysTime == SysTime(Date(1999, 4, 30)));
4399         }
4400 
4401         {
4402             auto sysTime = SysTime(Date(1999, 2, 28));
4403             sysTime.roll!"months"(12, AllowDayOverflow.no);
4404             assert(sysTime == SysTime(Date(1999, 2, 28)));
4405         }
4406 
4407         {
4408             auto sysTime = SysTime(Date(2000, 2, 29));
4409             sysTime.roll!"months"(12, AllowDayOverflow.no);
4410             assert(sysTime == SysTime(Date(2000, 2, 29)));
4411         }
4412 
4413         {
4414             auto sysTime = SysTime(Date(1999, 7, 31));
4415             sysTime.roll!"months"(1, AllowDayOverflow.no);
4416             assert(sysTime == SysTime(Date(1999, 8, 31)));
4417             sysTime.roll!"months"(1, AllowDayOverflow.no);
4418             assert(sysTime == SysTime(Date(1999, 9, 30)));
4419         }
4420 
4421         {
4422             auto sysTime = SysTime(Date(1998, 8, 31));
4423             sysTime.roll!"months"(13, AllowDayOverflow.no);
4424             assert(sysTime == SysTime(Date(1998, 9, 30)));
4425             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4426             assert(sysTime == SysTime(Date(1998, 8, 30)));
4427         }
4428 
4429         {
4430             auto sysTime = SysTime(Date(1997, 12, 31));
4431             sysTime.roll!"months"(13, AllowDayOverflow.no);
4432             assert(sysTime == SysTime(Date(1997, 1, 31)));
4433             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4434             assert(sysTime == SysTime(Date(1997, 12, 31)));
4435         }
4436 
4437         {
4438             auto sysTime = SysTime(Date(1997, 12, 31));
4439             sysTime.roll!"months"(14, AllowDayOverflow.no);
4440             assert(sysTime == SysTime(Date(1997, 2, 28)));
4441             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4442             assert(sysTime == SysTime(Date(1997, 12, 28)));
4443         }
4444 
4445         {
4446             auto sysTime = SysTime(Date(1998, 12, 31));
4447             sysTime.roll!"months"(14, AllowDayOverflow.no);
4448             assert(sysTime == SysTime(Date(1998, 2, 28)));
4449             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4450             assert(sysTime == SysTime(Date(1998, 12, 28)));
4451         }
4452 
4453         {
4454             auto sysTime = SysTime(Date(1999, 12, 31));
4455             sysTime.roll!"months"(14, AllowDayOverflow.no);
4456             assert(sysTime == SysTime(Date(1999, 2, 28)));
4457             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4458             assert(sysTime == SysTime(Date(1999, 12, 28)));
4459         }
4460 
4461         {
4462             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
4463             sysTime.roll!"months"(3, AllowDayOverflow.no);
4464             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
4465             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4466             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
4467         }
4468 
4469         {
4470             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
4471             sysTime.roll!"months"(14, AllowDayOverflow.no);
4472             assert(sysTime == SysTime(DateTime(1998, 2, 28, 7, 7, 7), hnsecs(422202)));
4473             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4474             assert(sysTime == SysTime(DateTime(1998, 12, 28, 7, 7, 7), hnsecs(422202)));
4475         }
4476 
4477         {
4478             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
4479             sysTime.roll!"months"(14, AllowDayOverflow.no);
4480             assert(sysTime == SysTime(DateTime(1999, 2, 28, 7, 7, 7), hnsecs(422202)));
4481             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4482             assert(sysTime == SysTime(DateTime(1999, 12, 28, 7, 7, 7), hnsecs(422202)));
4483         }
4484 
4485         // Test B.C.
4486         {
4487             auto sysTime = SysTime(Date(-1999, 7, 6));
4488             sysTime.roll!"months"(3, AllowDayOverflow.no);
4489             assert(sysTime == SysTime(Date(-1999, 10, 6)));
4490             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4491             assert(sysTime == SysTime(Date(-1999, 6, 6)));
4492         }
4493 
4494         {
4495             auto sysTime = SysTime(Date(-1999, 7, 6));
4496             sysTime.roll!"months"(6, AllowDayOverflow.no);
4497             assert(sysTime == SysTime(Date(-1999, 1, 6)));
4498             sysTime.roll!"months"(-6, AllowDayOverflow.no);
4499             assert(sysTime == SysTime(Date(-1999, 7, 6)));
4500         }
4501 
4502         {
4503             auto sysTime = SysTime(Date(-1999, 7, 6));
4504             sysTime.roll!"months"(-27, AllowDayOverflow.no);
4505             assert(sysTime == SysTime(Date(-1999, 4, 6)));
4506             sysTime.roll!"months"(28, AllowDayOverflow.no);
4507             assert(sysTime == SysTime(Date(-1999, 8, 6)));
4508         }
4509 
4510         {
4511             auto sysTime = SysTime(Date(-1999, 5, 31));
4512             sysTime.roll!"months"(1, AllowDayOverflow.no);
4513             assert(sysTime == SysTime(Date(-1999, 6, 30)));
4514         }
4515 
4516         {
4517             auto sysTime = SysTime(Date(-1999, 5, 31));
4518             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4519             assert(sysTime == SysTime(Date(-1999, 4, 30)));
4520         }
4521 
4522         {
4523             auto sysTime = SysTime(Date(-1999, 2, 28));
4524             sysTime.roll!"months"(-12, AllowDayOverflow.no);
4525             assert(sysTime == SysTime(Date(-1999, 2, 28)));
4526         }
4527 
4528         {
4529             auto sysTime = SysTime(Date(-2000, 2, 29));
4530             sysTime.roll!"months"(-12, AllowDayOverflow.no);
4531             assert(sysTime == SysTime(Date(-2000, 2, 29)));
4532         }
4533 
4534         {
4535             auto sysTime = SysTime(Date(-1999, 7, 31));
4536             sysTime.roll!"months"(1, AllowDayOverflow.no);
4537             assert(sysTime == SysTime(Date(-1999, 8, 31)));
4538             sysTime.roll!"months"(1, AllowDayOverflow.no);
4539             assert(sysTime == SysTime(Date(-1999, 9, 30)));
4540         }
4541 
4542         {
4543             auto sysTime = SysTime(Date(-1998, 8, 31));
4544             sysTime.roll!"months"(13, AllowDayOverflow.no);
4545             assert(sysTime == SysTime(Date(-1998, 9, 30)));
4546             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4547             assert(sysTime == SysTime(Date(-1998, 8, 30)));
4548         }
4549 
4550         {
4551             auto sysTime = SysTime(Date(-1997, 12, 31));
4552             sysTime.roll!"months"(13, AllowDayOverflow.no);
4553             assert(sysTime == SysTime(Date(-1997, 1, 31)));
4554             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4555             assert(sysTime == SysTime(Date(-1997, 12, 31)));
4556         }
4557 
4558         {
4559             auto sysTime = SysTime(Date(-1997, 12, 31));
4560             sysTime.roll!"months"(14, AllowDayOverflow.no);
4561             assert(sysTime == SysTime(Date(-1997, 2, 28)));
4562             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4563             assert(sysTime == SysTime(Date(-1997, 12, 28)));
4564         }
4565 
4566         {
4567             auto sysTime = SysTime(Date(-2002, 12, 31));
4568             sysTime.roll!"months"(14, AllowDayOverflow.no);
4569             assert(sysTime == SysTime(Date(-2002, 2, 28)));
4570             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4571             assert(sysTime == SysTime(Date(-2002, 12, 28)));
4572         }
4573 
4574         {
4575             auto sysTime = SysTime(Date(-2001, 12, 31));
4576             sysTime.roll!"months"(14, AllowDayOverflow.no);
4577             assert(sysTime == SysTime(Date(-2001, 2, 28)));
4578             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4579             assert(sysTime == SysTime(Date(-2001, 12, 28)));
4580         }
4581 
4582         {
4583             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
4584             sysTime.roll!"months"(3, AllowDayOverflow.no);
4585             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
4586             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4587             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
4588         }
4589 
4590         {
4591             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
4592             sysTime.roll!"months"(14, AllowDayOverflow.no);
4593             assert(sysTime == SysTime(DateTime(-2002, 2, 28, 7, 7, 7), hnsecs(422202)));
4594             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4595             assert(sysTime == SysTime(DateTime(-2002, 12, 28, 7, 7, 7), hnsecs(422202)));
4596         }
4597 
4598         {
4599             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
4600             sysTime.roll!"months"(14, AllowDayOverflow.no);
4601             assert(sysTime == SysTime(DateTime(-2001, 2, 28, 7, 7, 7), hnsecs(422202)));
4602             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4603             assert(sysTime == SysTime(DateTime(-2001, 12, 28, 7, 7, 7), hnsecs(422202)));
4604         }
4605 
4606         // Test Both
4607         {
4608             auto sysTime = SysTime(Date(1, 1, 1));
4609             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4610             assert(sysTime == SysTime(Date(1, 12, 1)));
4611             sysTime.roll!"months"(1, AllowDayOverflow.no);
4612             assert(sysTime == SysTime(Date(1, 1, 1)));
4613         }
4614 
4615         {
4616             auto sysTime = SysTime(Date(4, 1, 1));
4617             sysTime.roll!"months"(-48, AllowDayOverflow.no);
4618             assert(sysTime == SysTime(Date(4, 1, 1)));
4619             sysTime.roll!"months"(48, AllowDayOverflow.no);
4620             assert(sysTime == SysTime(Date(4, 1, 1)));
4621         }
4622 
4623         {
4624             auto sysTime = SysTime(Date(4, 3, 31));
4625             sysTime.roll!"months"(-49, AllowDayOverflow.no);
4626             assert(sysTime == SysTime(Date(4, 2, 29)));
4627             sysTime.roll!"months"(49, AllowDayOverflow.no);
4628             assert(sysTime == SysTime(Date(4, 3, 29)));
4629         }
4630 
4631         {
4632             auto sysTime = SysTime(Date(4, 3, 31));
4633             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4634             assert(sysTime == SysTime(Date(4, 2, 29)));
4635             sysTime.roll!"months"(85, AllowDayOverflow.no);
4636             assert(sysTime == SysTime(Date(4, 3, 29)));
4637         }
4638 
4639         {
4640             auto sysTime = SysTime(Date(-1, 1, 1));
4641             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4642             assert(sysTime == SysTime(Date(-1, 12, 1)));
4643             sysTime.roll!"months"(1, AllowDayOverflow.no);
4644             assert(sysTime == SysTime(Date(-1, 1, 1)));
4645         }
4646 
4647         {
4648             auto sysTime = SysTime(Date(-4, 1, 1));
4649             sysTime.roll!"months"(-48, AllowDayOverflow.no);
4650             assert(sysTime == SysTime(Date(-4, 1, 1)));
4651             sysTime.roll!"months"(48, AllowDayOverflow.no);
4652             assert(sysTime == SysTime(Date(-4, 1, 1)));
4653         }
4654 
4655         {
4656             auto sysTime = SysTime(Date(-4, 3, 31));
4657             sysTime.roll!"months"(-49, AllowDayOverflow.no);
4658             assert(sysTime == SysTime(Date(-4, 2, 29)));
4659             sysTime.roll!"months"(49, AllowDayOverflow.no);
4660             assert(sysTime == SysTime(Date(-4, 3, 29)));
4661         }
4662 
4663         {
4664             auto sysTime = SysTime(Date(-4, 3, 31));
4665             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4666             assert(sysTime == SysTime(Date(-4, 2, 29)));
4667             sysTime.roll!"months"(85, AllowDayOverflow.no);
4668             assert(sysTime == SysTime(Date(-4, 3, 29)));
4669         }
4670 
4671         {
4672             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
4673             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4674             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 0, 0)));
4675             sysTime.roll!"months"(1, AllowDayOverflow.no);
4676             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
4677         }
4678 
4679         {
4680             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
4681             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4682             assert(sysTime == SysTime(DateTime(1, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4683             sysTime.roll!"months"(1, AllowDayOverflow.no);
4684             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4685         }
4686 
4687         {
4688             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
4689             sysTime.roll!"months"(1, AllowDayOverflow.no);
4690             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
4691             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4692             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
4693         }
4694 
4695         {
4696             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
4697             sysTime.roll!"months"(1, AllowDayOverflow.no);
4698             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4699             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4700             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4701         }
4702 
4703         {
4704             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
4705             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4706             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 7, 9), hnsecs(17)));
4707             sysTime.roll!"months"(1, AllowDayOverflow.no);
4708             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
4709         }
4710 
4711         {
4712             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
4713             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4714             assert(sysTime == SysTime(DateTime(4, 2, 29, 12, 11, 10), msecs(9)));
4715             sysTime.roll!"months"(85, AllowDayOverflow.no);
4716             assert(sysTime == SysTime(DateTime(4, 3, 29, 12, 11, 10), msecs(9)));
4717         }
4718 
4719         {
4720             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4721             sysTime.roll!"months"(85, AllowDayOverflow.no);
4722             assert(sysTime == SysTime(DateTime(-3, 4, 30, 12, 11, 10), msecs(9)));
4723             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4724             assert(sysTime == SysTime(DateTime(-3, 3, 30, 12, 11, 10), msecs(9)));
4725         }
4726 
4727         {
4728             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4729             sysTime.roll!"months"(85, AllowDayOverflow.no).roll!"months"(-83, AllowDayOverflow.no);
4730             assert(sysTime == SysTime(DateTime(-3, 5, 30, 12, 11, 10), msecs(9)));
4731         }
4732     }
4733 
4734 
4735     /++
4736         Adds the given number of units to this $(LREF SysTime). A negative number
4737         will subtract.
4738 
4739         The difference between rolling and adding is that rolling does not
4740         affect larger units. For instance, rolling a $(LREF SysTime) one
4741         year's worth of days gets the exact same $(LREF SysTime).
4742 
4743         Accepted units are `"days"`, `"minutes"`, `"hours"`,
4744         `"minutes"`, `"seconds"`, `"msecs"`, `"usecs"`, and
4745         `"hnsecs"`.
4746 
4747         Note that when rolling msecs, usecs or hnsecs, they all add up to a
4748         second. So, for example, rolling 1000 msecs is exactly the same as
4749         rolling 100,000 usecs.
4750 
4751         Params:
4752             units = The units to add.
4753             value = The number of $(D_PARAM units) to add to this
4754                     $(LREF SysTime).
4755       +/
4756     ref SysTime roll(string units)(long value) @safe nothrow scope
4757         if (units == "days")
4758     {
4759         auto hnsecs = adjTime;
4760         auto gdays = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
4761 
4762         if (hnsecs < 0)
4763         {
4764             hnsecs += convert!("hours", "hnsecs")(24);
4765             --gdays;
4766         }
4767 
4768         auto date = Date(cast(int) gdays);
4769         date.roll!"days"(value);
4770         gdays = date.dayOfGregorianCal - 1;
4771 
4772         if (gdays < 0)
4773         {
4774             hnsecs -= convert!("hours", "hnsecs")(24);
4775             ++gdays;
4776         }
4777 
4778         immutable newDaysHNSecs = convert!("days", "hnsecs")(gdays);
4779         adjTime = newDaysHNSecs + hnsecs;
4780         return  this;
4781     }
4782 
4783     ///
4784     @safe unittest
4785     {
4786         import core.time : msecs, hnsecs;
4787         import std.datetime.date : DateTime;
4788 
4789         auto st1 = SysTime(DateTime(2010, 1, 1, 11, 23, 12));
4790         st1.roll!"days"(1);
4791         assert(st1 == SysTime(DateTime(2010, 1, 2, 11, 23, 12)));
4792         st1.roll!"days"(365);
4793         assert(st1 == SysTime(DateTime(2010, 1, 26, 11, 23, 12)));
4794         st1.roll!"days"(-32);
4795         assert(st1 == SysTime(DateTime(2010, 1, 25, 11, 23, 12)));
4796 
4797         auto st2 = SysTime(DateTime(2010, 7, 4, 12, 0, 0));
4798         st2.roll!"hours"(1);
4799         assert(st2 == SysTime(DateTime(2010, 7, 4, 13, 0, 0)));
4800 
4801         auto st3 = SysTime(DateTime(2010, 2, 12, 12, 0, 0));
4802         st3.roll!"hours"(-1);
4803         assert(st3 == SysTime(DateTime(2010, 2, 12, 11, 0, 0)));
4804 
4805         auto st4 = SysTime(DateTime(2009, 12, 31, 0, 0, 0));
4806         st4.roll!"minutes"(1);
4807         assert(st4 == SysTime(DateTime(2009, 12, 31, 0, 1, 0)));
4808 
4809         auto st5 = SysTime(DateTime(2010, 1, 1, 0, 0, 0));
4810         st5.roll!"minutes"(-1);
4811         assert(st5 == SysTime(DateTime(2010, 1, 1, 0, 59, 0)));
4812 
4813         auto st6 = SysTime(DateTime(2009, 12, 31, 0, 0, 0));
4814         st6.roll!"seconds"(1);
4815         assert(st6 == SysTime(DateTime(2009, 12, 31, 0, 0, 1)));
4816 
4817         auto st7 = SysTime(DateTime(2010, 1, 1, 0, 0, 0));
4818         st7.roll!"seconds"(-1);
4819         assert(st7 == SysTime(DateTime(2010, 1, 1, 0, 0, 59)));
4820 
4821         auto dt = DateTime(2010, 1, 1, 0, 0, 0);
4822         auto st8 = SysTime(dt);
4823         st8.roll!"msecs"(1);
4824         assert(st8 == SysTime(dt, msecs(1)));
4825 
4826         auto st9 = SysTime(dt);
4827         st9.roll!"msecs"(-1);
4828         assert(st9 == SysTime(dt, msecs(999)));
4829 
4830         auto st10 = SysTime(dt);
4831         st10.roll!"hnsecs"(1);
4832         assert(st10 == SysTime(dt, hnsecs(1)));
4833 
4834         auto st11 = SysTime(dt);
4835         st11.roll!"hnsecs"(-1);
4836         assert(st11 == SysTime(dt, hnsecs(9_999_999)));
4837     }
4838 
4839     @safe unittest
4840     {
4841         import core.time;
4842         // Test A.D.
4843         {
4844             auto sysTime = SysTime(Date(1999, 2, 28));
4845             sysTime.roll!"days"(1);
4846             assert(sysTime == SysTime(Date(1999, 2, 1)));
4847             sysTime.roll!"days"(-1);
4848             assert(sysTime == SysTime(Date(1999, 2, 28)));
4849         }
4850 
4851         {
4852             auto sysTime = SysTime(Date(2000, 2, 28));
4853             sysTime.roll!"days"(1);
4854             assert(sysTime == SysTime(Date(2000, 2, 29)));
4855             sysTime.roll!"days"(1);
4856             assert(sysTime == SysTime(Date(2000, 2, 1)));
4857             sysTime.roll!"days"(-1);
4858             assert(sysTime == SysTime(Date(2000, 2, 29)));
4859         }
4860 
4861         {
4862             auto sysTime = SysTime(Date(1999, 6, 30));
4863             sysTime.roll!"days"(1);
4864             assert(sysTime == SysTime(Date(1999, 6, 1)));
4865             sysTime.roll!"days"(-1);
4866             assert(sysTime == SysTime(Date(1999, 6, 30)));
4867         }
4868 
4869         {
4870             auto sysTime = SysTime(Date(1999, 7, 31));
4871             sysTime.roll!"days"(1);
4872             assert(sysTime == SysTime(Date(1999, 7, 1)));
4873             sysTime.roll!"days"(-1);
4874             assert(sysTime == SysTime(Date(1999, 7, 31)));
4875         }
4876 
4877         {
4878             auto sysTime = SysTime(Date(1999, 1, 1));
4879             sysTime.roll!"days"(-1);
4880             assert(sysTime == SysTime(Date(1999, 1, 31)));
4881             sysTime.roll!"days"(1);
4882             assert(sysTime == SysTime(Date(1999, 1, 1)));
4883         }
4884 
4885         {
4886             auto sysTime = SysTime(Date(1999, 7, 6));
4887             sysTime.roll!"days"(9);
4888             assert(sysTime == SysTime(Date(1999, 7, 15)));
4889             sysTime.roll!"days"(-11);
4890             assert(sysTime == SysTime(Date(1999, 7, 4)));
4891             sysTime.roll!"days"(30);
4892             assert(sysTime == SysTime(Date(1999, 7, 3)));
4893             sysTime.roll!"days"(-3);
4894             assert(sysTime == SysTime(Date(1999, 7, 31)));
4895         }
4896 
4897         {
4898             auto sysTime = SysTime(Date(1999, 7, 6));
4899             sysTime.roll!"days"(365);
4900             assert(sysTime == SysTime(Date(1999, 7, 30)));
4901             sysTime.roll!"days"(-365);
4902             assert(sysTime == SysTime(Date(1999, 7, 6)));
4903             sysTime.roll!"days"(366);
4904             assert(sysTime == SysTime(Date(1999, 7, 31)));
4905             sysTime.roll!"days"(730);
4906             assert(sysTime == SysTime(Date(1999, 7, 17)));
4907             sysTime.roll!"days"(-1096);
4908             assert(sysTime == SysTime(Date(1999, 7, 6)));
4909         }
4910 
4911         {
4912             auto sysTime = SysTime(Date(1999, 2, 6));
4913             sysTime.roll!"days"(365);
4914             assert(sysTime == SysTime(Date(1999, 2, 7)));
4915             sysTime.roll!"days"(-365);
4916             assert(sysTime == SysTime(Date(1999, 2, 6)));
4917             sysTime.roll!"days"(366);
4918             assert(sysTime == SysTime(Date(1999, 2, 8)));
4919             sysTime.roll!"days"(730);
4920             assert(sysTime == SysTime(Date(1999, 2, 10)));
4921             sysTime.roll!"days"(-1096);
4922             assert(sysTime == SysTime(Date(1999, 2, 6)));
4923         }
4924 
4925         {
4926             auto sysTime = SysTime(DateTime(1999, 2, 28, 7, 9, 2), usecs(234578));
4927             sysTime.roll!"days"(1);
4928             assert(sysTime == SysTime(DateTime(1999, 2, 1, 7, 9, 2), usecs(234578)));
4929             sysTime.roll!"days"(-1);
4930             assert(sysTime == SysTime(DateTime(1999, 2, 28, 7, 9, 2), usecs(234578)));
4931         }
4932 
4933         {
4934             auto sysTime = SysTime(DateTime(1999, 7, 6, 7, 9, 2), usecs(234578));
4935             sysTime.roll!"days"(9);
4936             assert(sysTime == SysTime(DateTime(1999, 7, 15, 7, 9, 2), usecs(234578)));
4937             sysTime.roll!"days"(-11);
4938             assert(sysTime == SysTime(DateTime(1999, 7, 4, 7, 9, 2), usecs(234578)));
4939             sysTime.roll!"days"(30);
4940             assert(sysTime == SysTime(DateTime(1999, 7, 3, 7, 9, 2), usecs(234578)));
4941             sysTime.roll!"days"(-3);
4942             assert(sysTime == SysTime(DateTime(1999, 7, 31, 7, 9, 2), usecs(234578)));
4943         }
4944 
4945         // Test B.C.
4946         {
4947             auto sysTime = SysTime(Date(-1999, 2, 28));
4948             sysTime.roll!"days"(1);
4949             assert(sysTime == SysTime(Date(-1999, 2, 1)));
4950             sysTime.roll!"days"(-1);
4951             assert(sysTime == SysTime(Date(-1999, 2, 28)));
4952         }
4953 
4954         {
4955             auto sysTime = SysTime(Date(-2000, 2, 28));
4956             sysTime.roll!"days"(1);
4957             assert(sysTime == SysTime(Date(-2000, 2, 29)));
4958             sysTime.roll!"days"(1);
4959             assert(sysTime == SysTime(Date(-2000, 2, 1)));
4960             sysTime.roll!"days"(-1);
4961             assert(sysTime == SysTime(Date(-2000, 2, 29)));
4962         }
4963 
4964         {
4965             auto sysTime = SysTime(Date(-1999, 6, 30));
4966             sysTime.roll!"days"(1);
4967             assert(sysTime == SysTime(Date(-1999, 6, 1)));
4968             sysTime.roll!"days"(-1);
4969             assert(sysTime == SysTime(Date(-1999, 6, 30)));
4970         }
4971 
4972         {
4973             auto sysTime = SysTime(Date(-1999, 7, 31));
4974             sysTime.roll!"days"(1);
4975             assert(sysTime == SysTime(Date(-1999, 7, 1)));
4976             sysTime.roll!"days"(-1);
4977             assert(sysTime == SysTime(Date(-1999, 7, 31)));
4978         }
4979 
4980         {
4981             auto sysTime = SysTime(Date(-1999, 1, 1));
4982             sysTime.roll!"days"(-1);
4983             assert(sysTime == SysTime(Date(-1999, 1, 31)));
4984             sysTime.roll!"days"(1);
4985             assert(sysTime == SysTime(Date(-1999, 1, 1)));
4986         }
4987 
4988         {
4989             auto sysTime = SysTime(Date(-1999, 7, 6));
4990             sysTime.roll!"days"(9);
4991             assert(sysTime == SysTime(Date(-1999, 7, 15)));
4992             sysTime.roll!"days"(-11);
4993             assert(sysTime == SysTime(Date(-1999, 7, 4)));
4994             sysTime.roll!"days"(30);
4995             assert(sysTime == SysTime(Date(-1999, 7, 3)));
4996             sysTime.roll!"days"(-3);
4997             assert(sysTime == SysTime(Date(-1999, 7, 31)));
4998         }
4999 
5000         {
5001             auto sysTime = SysTime(Date(-1999, 7, 6));
5002             sysTime.roll!"days"(365);
5003             assert(sysTime == SysTime(Date(-1999, 7, 30)));
5004             sysTime.roll!"days"(-365);
5005             assert(sysTime == SysTime(Date(-1999, 7, 6)));
5006             sysTime.roll!"days"(366);
5007             assert(sysTime == SysTime(Date(-1999, 7, 31)));
5008             sysTime.roll!"days"(730);
5009             assert(sysTime == SysTime(Date(-1999, 7, 17)));
5010             sysTime.roll!"days"(-1096);
5011             assert(sysTime == SysTime(Date(-1999, 7, 6)));
5012         }
5013 
5014         {
5015             auto sysTime = SysTime(DateTime(-1999, 2, 28, 7, 9, 2), usecs(234578));
5016             sysTime.roll!"days"(1);
5017             assert(sysTime == SysTime(DateTime(-1999, 2, 1, 7, 9, 2), usecs(234578)));
5018             sysTime.roll!"days"(-1);
5019             assert(sysTime == SysTime(DateTime(-1999, 2, 28, 7, 9, 2), usecs(234578)));
5020         }
5021 
5022         {
5023             auto sysTime = SysTime(DateTime(-1999, 7, 6, 7, 9, 2), usecs(234578));
5024             sysTime.roll!"days"(9);
5025             assert(sysTime == SysTime(DateTime(-1999, 7, 15, 7, 9, 2), usecs(234578)));
5026             sysTime.roll!"days"(-11);
5027             assert(sysTime == SysTime(DateTime(-1999, 7, 4, 7, 9, 2), usecs(234578)));
5028             sysTime.roll!"days"(30);
5029             assert(sysTime == SysTime(DateTime(-1999, 7, 3, 7, 9, 2), usecs(234578)));
5030             sysTime.roll!"days"(-3);
5031         }
5032 
5033         // Test Both
5034         {
5035             auto sysTime = SysTime(Date(1, 7, 6));
5036             sysTime.roll!"days"(-365);
5037             assert(sysTime == SysTime(Date(1, 7, 13)));
5038             sysTime.roll!"days"(365);
5039             assert(sysTime == SysTime(Date(1, 7, 6)));
5040             sysTime.roll!"days"(-731);
5041             assert(sysTime == SysTime(Date(1, 7, 19)));
5042             sysTime.roll!"days"(730);
5043             assert(sysTime == SysTime(Date(1, 7, 5)));
5044         }
5045 
5046         {
5047             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5048             sysTime.roll!"days"(-1);
5049             assert(sysTime == SysTime(DateTime(1, 1, 31, 0, 0, 0)));
5050             sysTime.roll!"days"(1);
5051             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5052         }
5053 
5054         {
5055             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
5056             sysTime.roll!"days"(-1);
5057             assert(sysTime == SysTime(DateTime(1, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
5058             sysTime.roll!"days"(1);
5059             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
5060         }
5061 
5062         {
5063             auto sysTime = SysTime(DateTime(0, 12, 31, 0, 0, 0));
5064             sysTime.roll!"days"(1);
5065             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
5066             sysTime.roll!"days"(-1);
5067             assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 0, 0)));
5068         }
5069 
5070         {
5071             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5072             sysTime.roll!"days"(1);
5073             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
5074             sysTime.roll!"days"(-1);
5075             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5076         }
5077 
5078         {
5079             auto sysTime = SysTime(DateTime(1, 7, 6, 13, 13, 9), msecs(22));
5080             sysTime.roll!"days"(-365);
5081             assert(sysTime == SysTime(DateTime(1, 7, 13, 13, 13, 9), msecs(22)));
5082             sysTime.roll!"days"(365);
5083             assert(sysTime == SysTime(DateTime(1, 7, 6, 13, 13, 9), msecs(22)));
5084             sysTime.roll!"days"(-731);
5085             assert(sysTime == SysTime(DateTime(1, 7, 19, 13, 13, 9), msecs(22)));
5086             sysTime.roll!"days"(730);
5087             assert(sysTime == SysTime(DateTime(1, 7, 5, 13, 13, 9), msecs(22)));
5088         }
5089 
5090         {
5091             auto sysTime = SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22));
5092             sysTime.roll!"days"(-365);
5093             assert(sysTime == SysTime(DateTime(0, 7, 13, 13, 13, 9), msecs(22)));
5094             sysTime.roll!"days"(365);
5095             assert(sysTime == SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22)));
5096             sysTime.roll!"days"(-731);
5097             assert(sysTime == SysTime(DateTime(0, 7, 19, 13, 13, 9), msecs(22)));
5098             sysTime.roll!"days"(730);
5099             assert(sysTime == SysTime(DateTime(0, 7, 5, 13, 13, 9), msecs(22)));
5100         }
5101 
5102         {
5103             auto sysTime = SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22));
5104             sysTime.roll!"days"(-365).roll!"days"(362).roll!"days"(-12).roll!"days"(730);
5105             assert(sysTime == SysTime(DateTime(0, 7, 8, 13, 13, 9), msecs(22)));
5106         }
5107 
5108         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5109         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5110         static assert(!__traits(compiles, cst.roll!"days"(4)));
5111         static assert(!__traits(compiles, ist.roll!"days"(4)));
5112 
5113         static void testScope(scope ref SysTime st) @safe
5114         {
5115             auto result = st.roll!"days"(42);
5116         }
5117     }
5118 
5119 
5120     // Shares documentation with "days" version.
5121     ref SysTime roll(string units)(long value) @safe nothrow scope
5122         if (units == "hours" || units == "minutes" || units == "seconds")
5123     {
5124         try
5125         {
5126             auto hnsecs = adjTime;
5127             auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
5128 
5129             if (hnsecs < 0)
5130             {
5131                 hnsecs += convert!("hours", "hnsecs")(24);
5132                 --days;
5133             }
5134 
5135             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
5136             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
5137             immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
5138 
5139             auto dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
5140                                           cast(int) minute, cast(int) second));
5141             dateTime.roll!units(value);
5142             --days;
5143 
5144             hnsecs += convert!("hours", "hnsecs")(dateTime.hour);
5145             hnsecs += convert!("minutes", "hnsecs")(dateTime.minute);
5146             hnsecs += convert!("seconds", "hnsecs")(dateTime.second);
5147 
5148             if (days < 0)
5149             {
5150                 hnsecs -= convert!("hours", "hnsecs")(24);
5151                 ++days;
5152             }
5153 
5154             immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
5155             adjTime = newDaysHNSecs + hnsecs;
5156             return this;
5157         }
5158         catch (Exception e)
5159             assert(0, "Either DateTime's constructor or TimeOfDay's constructor threw.");
5160     }
5161 
5162     // Test roll!"hours"().
5163     @safe unittest
5164     {
5165         import core.time;
5166         static void testST(SysTime orig, int hours, SysTime expected, size_t line = __LINE__) @safe
5167         {
5168             orig.roll!"hours"(hours);
5169             if (orig != expected)
5170                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5171         }
5172 
5173         // Test A.D.
5174         immutable d = msecs(45);
5175         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
5176         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5177         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
5178         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
5179         testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 15, 30, 33), d));
5180         testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 16, 30, 33), d));
5181         testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 17, 30, 33), d));
5182         testST(beforeAD, 6, SysTime(DateTime(1999, 7, 6, 18, 30, 33), d));
5183         testST(beforeAD, 7, SysTime(DateTime(1999, 7, 6, 19, 30, 33), d));
5184         testST(beforeAD, 8, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
5185         testST(beforeAD, 9, SysTime(DateTime(1999, 7, 6, 21, 30, 33), d));
5186         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
5187         testST(beforeAD, 11, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
5188         testST(beforeAD, 12, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
5189         testST(beforeAD, 13, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
5190         testST(beforeAD, 14, SysTime(DateTime(1999, 7, 6, 2, 30, 33), d));
5191         testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 3, 30, 33), d));
5192         testST(beforeAD, 16, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
5193         testST(beforeAD, 17, SysTime(DateTime(1999, 7, 6, 5, 30, 33), d));
5194         testST(beforeAD, 18, SysTime(DateTime(1999, 7, 6, 6, 30, 33), d));
5195         testST(beforeAD, 19, SysTime(DateTime(1999, 7, 6, 7, 30, 33), d));
5196         testST(beforeAD, 20, SysTime(DateTime(1999, 7, 6, 8, 30, 33), d));
5197         testST(beforeAD, 21, SysTime(DateTime(1999, 7, 6, 9, 30, 33), d));
5198         testST(beforeAD, 22, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
5199         testST(beforeAD, 23, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
5200         testST(beforeAD, 24, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5201         testST(beforeAD, 25, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
5202         testST(beforeAD, 50, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
5203         testST(beforeAD, 10_000, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
5204 
5205         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
5206         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
5207         testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 9, 30, 33), d));
5208         testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 8, 30, 33), d));
5209         testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 7, 30, 33), d));
5210         testST(beforeAD, -6, SysTime(DateTime(1999, 7, 6, 6, 30, 33), d));
5211         testST(beforeAD, -7, SysTime(DateTime(1999, 7, 6, 5, 30, 33), d));
5212         testST(beforeAD, -8, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
5213         testST(beforeAD, -9, SysTime(DateTime(1999, 7, 6, 3, 30, 33), d));
5214         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 2, 30, 33), d));
5215         testST(beforeAD, -11, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
5216         testST(beforeAD, -12, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
5217         testST(beforeAD, -13, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
5218         testST(beforeAD, -14, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
5219         testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 21, 30, 33), d));
5220         testST(beforeAD, -16, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
5221         testST(beforeAD, -17, SysTime(DateTime(1999, 7, 6, 19, 30, 33), d));
5222         testST(beforeAD, -18, SysTime(DateTime(1999, 7, 6, 18, 30, 33), d));
5223         testST(beforeAD, -19, SysTime(DateTime(1999, 7, 6, 17, 30, 33), d));
5224         testST(beforeAD, -20, SysTime(DateTime(1999, 7, 6, 16, 30, 33), d));
5225         testST(beforeAD, -21, SysTime(DateTime(1999, 7, 6, 15, 30, 33), d));
5226         testST(beforeAD, -22, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
5227         testST(beforeAD, -23, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
5228         testST(beforeAD, -24, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5229         testST(beforeAD, -25, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
5230         testST(beforeAD, -50, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
5231         testST(beforeAD, -10_000, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
5232 
5233         testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), 1, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
5234         testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), 0, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
5235         testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), -1, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
5236 
5237         testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), 1, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
5238         testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), 0, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
5239         testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), -1, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
5240 
5241         testST(SysTime(DateTime(1999, 7, 31, 23, 30, 33), d), 1, SysTime(DateTime(1999, 7, 31, 0, 30, 33), d));
5242         testST(SysTime(DateTime(1999, 8, 1, 0, 30, 33), d), -1, SysTime(DateTime(1999, 8, 1, 23, 30, 33), d));
5243 
5244         testST(SysTime(DateTime(1999, 12, 31, 23, 30, 33), d), 1, SysTime(DateTime(1999, 12, 31, 0, 30, 33), d));
5245         testST(SysTime(DateTime(2000, 1, 1, 0, 30, 33), d), -1, SysTime(DateTime(2000, 1, 1, 23, 30, 33), d));
5246 
5247         testST(SysTime(DateTime(1999, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(1999, 2, 28, 0, 30, 33), d));
5248         testST(SysTime(DateTime(1999, 3, 2, 0, 30, 33), d), -25, SysTime(DateTime(1999, 3, 2, 23, 30, 33), d));
5249 
5250         testST(SysTime(DateTime(2000, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(2000, 2, 28, 0, 30, 33), d));
5251         testST(SysTime(DateTime(2000, 3, 1, 0, 30, 33), d), -25, SysTime(DateTime(2000, 3, 1, 23, 30, 33), d));
5252 
5253         // Test B.C.
5254         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
5255         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5256         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
5257         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
5258         testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 15, 30, 33), d));
5259         testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 16, 30, 33), d));
5260         testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 17, 30, 33), d));
5261         testST(beforeBC, 6, SysTime(DateTime(-1999, 7, 6, 18, 30, 33), d));
5262         testST(beforeBC, 7, SysTime(DateTime(-1999, 7, 6, 19, 30, 33), d));
5263         testST(beforeBC, 8, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
5264         testST(beforeBC, 9, SysTime(DateTime(-1999, 7, 6, 21, 30, 33), d));
5265         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
5266         testST(beforeBC, 11, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
5267         testST(beforeBC, 12, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
5268         testST(beforeBC, 13, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
5269         testST(beforeBC, 14, SysTime(DateTime(-1999, 7, 6, 2, 30, 33), d));
5270         testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 3, 30, 33), d));
5271         testST(beforeBC, 16, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
5272         testST(beforeBC, 17, SysTime(DateTime(-1999, 7, 6, 5, 30, 33), d));
5273         testST(beforeBC, 18, SysTime(DateTime(-1999, 7, 6, 6, 30, 33), d));
5274         testST(beforeBC, 19, SysTime(DateTime(-1999, 7, 6, 7, 30, 33), d));
5275         testST(beforeBC, 20, SysTime(DateTime(-1999, 7, 6, 8, 30, 33), d));
5276         testST(beforeBC, 21, SysTime(DateTime(-1999, 7, 6, 9, 30, 33), d));
5277         testST(beforeBC, 22, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
5278         testST(beforeBC, 23, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
5279         testST(beforeBC, 24, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5280         testST(beforeBC, 25, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
5281         testST(beforeBC, 50, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
5282         testST(beforeBC, 10_000, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
5283 
5284         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
5285         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
5286         testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 9, 30, 33), d));
5287         testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 8, 30, 33), d));
5288         testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 7, 30, 33), d));
5289         testST(beforeBC, -6, SysTime(DateTime(-1999, 7, 6, 6, 30, 33), d));
5290         testST(beforeBC, -7, SysTime(DateTime(-1999, 7, 6, 5, 30, 33), d));
5291         testST(beforeBC, -8, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
5292         testST(beforeBC, -9, SysTime(DateTime(-1999, 7, 6, 3, 30, 33), d));
5293         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 2, 30, 33), d));
5294         testST(beforeBC, -11, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
5295         testST(beforeBC, -12, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
5296         testST(beforeBC, -13, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
5297         testST(beforeBC, -14, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
5298         testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 21, 30, 33), d));
5299         testST(beforeBC, -16, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
5300         testST(beforeBC, -17, SysTime(DateTime(-1999, 7, 6, 19, 30, 33), d));
5301         testST(beforeBC, -18, SysTime(DateTime(-1999, 7, 6, 18, 30, 33), d));
5302         testST(beforeBC, -19, SysTime(DateTime(-1999, 7, 6, 17, 30, 33), d));
5303         testST(beforeBC, -20, SysTime(DateTime(-1999, 7, 6, 16, 30, 33), d));
5304         testST(beforeBC, -21, SysTime(DateTime(-1999, 7, 6, 15, 30, 33), d));
5305         testST(beforeBC, -22, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
5306         testST(beforeBC, -23, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
5307         testST(beforeBC, -24, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5308         testST(beforeBC, -25, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
5309         testST(beforeBC, -50, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
5310         testST(beforeBC, -10_000, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
5311 
5312         testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
5313         testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
5314         testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
5315 
5316         testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
5317         testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
5318         testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
5319 
5320         testST(SysTime(DateTime(-1999, 7, 31, 23, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 31, 0, 30, 33), d));
5321         testST(SysTime(DateTime(-1999, 8, 1, 0, 30, 33), d), -1, SysTime(DateTime(-1999, 8, 1, 23, 30, 33), d));
5322 
5323         testST(SysTime(DateTime(-2001, 12, 31, 23, 30, 33), d), 1, SysTime(DateTime(-2001, 12, 31, 0, 30, 33), d));
5324         testST(SysTime(DateTime(-2000, 1, 1, 0, 30, 33), d), -1, SysTime(DateTime(-2000, 1, 1, 23, 30, 33), d));
5325 
5326         testST(SysTime(DateTime(-2001, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(-2001, 2, 28, 0, 30, 33), d));
5327         testST(SysTime(DateTime(-2001, 3, 2, 0, 30, 33), d), -25, SysTime(DateTime(-2001, 3, 2, 23, 30, 33), d));
5328 
5329         testST(SysTime(DateTime(-2000, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(-2000, 2, 28, 0, 30, 33), d));
5330         testST(SysTime(DateTime(-2000, 3, 1, 0, 30, 33), d), -25, SysTime(DateTime(-2000, 3, 1, 23, 30, 33), d));
5331 
5332         // Test Both
5333         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 17_546, SysTime(DateTime(-1, 1, 1, 13, 30, 33), d));
5334         testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -17_546, SysTime(DateTime(1, 1, 1, 11, 30, 33), d));
5335 
5336         {
5337             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5338             sysTime.roll!"hours"(-1);
5339             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 0, 0)));
5340             sysTime.roll!"hours"(1);
5341             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5342         }
5343 
5344         {
5345             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999));
5346             sysTime.roll!"hours"(-1);
5347             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
5348             sysTime.roll!"hours"(1);
5349             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999)));
5350         }
5351 
5352         {
5353             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 0, 0));
5354             sysTime.roll!"hours"(1);
5355             assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 0, 0)));
5356             sysTime.roll!"hours"(-1);
5357             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 0)));
5358         }
5359 
5360         {
5361             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5362             sysTime.roll!"hours"(1);
5363             assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 59, 59), hnsecs(9_999_999)));
5364             sysTime.roll!"hours"(-1);
5365             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5366         }
5367 
5368         {
5369             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5370             sysTime.roll!"hours"(1).roll!"hours"(-67);
5371             assert(sysTime == SysTime(DateTime(0, 12, 31, 5, 59, 59), hnsecs(9_999_999)));
5372         }
5373 
5374         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5375         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5376         static assert(!__traits(compiles, cst.roll!"hours"(4)));
5377         static assert(!__traits(compiles, ist.roll!"hours"(4)));
5378 
5379         static void testScope(scope ref SysTime st) @safe
5380         {
5381             auto result = st.roll!"hours"(42);
5382         }
5383     }
5384 
5385     // Test roll!"minutes"().
5386     @safe unittest
5387     {
5388         import core.time;
5389         static void testST(SysTime orig, int minutes, SysTime expected, size_t line = __LINE__) @safe
5390         {
5391             orig.roll!"minutes"(minutes);
5392             if (orig != expected)
5393                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5394         }
5395 
5396         // Test A.D.
5397         immutable d = usecs(7203);
5398         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
5399         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5400         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
5401         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 32, 33), d));
5402         testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 12, 33, 33), d));
5403         testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 12, 34, 33), d));
5404         testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 12, 35, 33), d));
5405         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 40, 33), d));
5406         testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
5407         testST(beforeAD, 29, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5408         testST(beforeAD, 30, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5409         testST(beforeAD, 45, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
5410         testST(beforeAD, 60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5411         testST(beforeAD, 75, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
5412         testST(beforeAD, 90, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5413         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 10, 33), d));
5414 
5415         testST(beforeAD, 689, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5416         testST(beforeAD, 690, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5417         testST(beforeAD, 691, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5418         testST(beforeAD, 960, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5419         testST(beforeAD, 1439, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
5420         testST(beforeAD, 1440, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5421         testST(beforeAD, 1441, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
5422         testST(beforeAD, 2880, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5423 
5424         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
5425         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 28, 33), d));
5426         testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 12, 27, 33), d));
5427         testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 12, 26, 33), d));
5428         testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 12, 25, 33), d));
5429         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 20, 33), d));
5430         testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
5431         testST(beforeAD, -29, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5432         testST(beforeAD, -30, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5433         testST(beforeAD, -45, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
5434         testST(beforeAD, -60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5435         testST(beforeAD, -75, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
5436         testST(beforeAD, -90, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5437         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 50, 33), d));
5438 
5439         testST(beforeAD, -749, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5440         testST(beforeAD, -750, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5441         testST(beforeAD, -751, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5442         testST(beforeAD, -960, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5443         testST(beforeAD, -1439, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
5444         testST(beforeAD, -1440, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5445         testST(beforeAD, -1441, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
5446         testST(beforeAD, -2880, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5447 
5448         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), 1, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5449         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), 0, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5450         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), -1, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5451 
5452         testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), 1, SysTime(DateTime(1999, 7, 6, 11, 0, 33), d));
5453         testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), 0, SysTime(DateTime(1999, 7, 6, 11, 59, 33), d));
5454         testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), -1, SysTime(DateTime(1999, 7, 6, 11, 58, 33), d));
5455 
5456         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), 1, SysTime(DateTime(1999, 7, 6, 0, 1, 33), d));
5457         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), 0, SysTime(DateTime(1999, 7, 6, 0, 0, 33), d));
5458         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), -1, SysTime(DateTime(1999, 7, 6, 0, 59, 33), d));
5459 
5460         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), 1, SysTime(DateTime(1999, 7, 5, 23, 0, 33), d));
5461         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), 0, SysTime(DateTime(1999, 7, 5, 23, 59, 33), d));
5462         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), -1, SysTime(DateTime(1999, 7, 5, 23, 58, 33), d));
5463 
5464         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), 1, SysTime(DateTime(1998, 12, 31, 23, 0, 33), d));
5465         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), 0, SysTime(DateTime(1998, 12, 31, 23, 59, 33), d));
5466         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), -1, SysTime(DateTime(1998, 12, 31, 23, 58, 33), d));
5467 
5468         // Test B.C.
5469         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
5470         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5471         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
5472         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 32, 33), d));
5473         testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 12, 33, 33), d));
5474         testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 12, 34, 33), d));
5475         testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 12, 35, 33), d));
5476         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 40, 33), d));
5477         testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
5478         testST(beforeBC, 29, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5479         testST(beforeBC, 30, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5480         testST(beforeBC, 45, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
5481         testST(beforeBC, 60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5482         testST(beforeBC, 75, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
5483         testST(beforeBC, 90, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5484         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 10, 33), d));
5485 
5486         testST(beforeBC, 689, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5487         testST(beforeBC, 690, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5488         testST(beforeBC, 691, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5489         testST(beforeBC, 960, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5490         testST(beforeBC, 1439, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
5491         testST(beforeBC, 1440, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5492         testST(beforeBC, 1441, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
5493         testST(beforeBC, 2880, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5494 
5495         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
5496         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 28, 33), d));
5497         testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 12, 27, 33), d));
5498         testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 12, 26, 33), d));
5499         testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 12, 25, 33), d));
5500         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 20, 33), d));
5501         testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
5502         testST(beforeBC, -29, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5503         testST(beforeBC, -30, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5504         testST(beforeBC, -45, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
5505         testST(beforeBC, -60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5506         testST(beforeBC, -75, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
5507         testST(beforeBC, -90, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5508         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 50, 33), d));
5509 
5510         testST(beforeBC, -749, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5511         testST(beforeBC, -750, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5512         testST(beforeBC, -751, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5513         testST(beforeBC, -960, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5514         testST(beforeBC, -1439, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
5515         testST(beforeBC, -1440, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5516         testST(beforeBC, -1441, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
5517         testST(beforeBC, -2880, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5518 
5519         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5520         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5521         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5522 
5523         testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 11, 0, 33), d));
5524         testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d));
5525         testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 11, 58, 33), d));
5526 
5527         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 1, 33), d));
5528         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d));
5529         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 0, 59, 33), d));
5530 
5531         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), 1, SysTime(DateTime(-1999, 7, 5, 23, 0, 33), d));
5532         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), 0, SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d));
5533         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), -1, SysTime(DateTime(-1999, 7, 5, 23, 58, 33), d));
5534 
5535         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), 1, SysTime(DateTime(-2000, 12, 31, 23, 0, 33), d));
5536         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), 0, SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d));
5537         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), -1, SysTime(DateTime(-2000, 12, 31, 23, 58, 33), d));
5538 
5539         // Test Both
5540         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), -1, SysTime(DateTime(1, 1, 1, 0, 59, 0)));
5541         testST(SysTime(DateTime(0, 12, 31, 23, 59, 0)), 1, SysTime(DateTime(0, 12, 31, 23, 0, 0)));
5542 
5543         testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), -1, SysTime(DateTime(0, 1, 1, 0, 59, 0)));
5544         testST(SysTime(DateTime(-1, 12, 31, 23, 59, 0)), 1, SysTime(DateTime(-1, 12, 31, 23, 0, 0)));
5545 
5546         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 1_052_760, SysTime(DateTime(-1, 1, 1, 11, 30, 33), d));
5547         testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -1_052_760, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5548 
5549         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 1_052_782, SysTime(DateTime(-1, 1, 1, 11, 52, 33), d));
5550         testST(SysTime(DateTime(1, 1, 1, 13, 52, 33), d), -1_052_782, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5551 
5552         {
5553             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5554             sysTime.roll!"minutes"(-1);
5555             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 0)));
5556             sysTime.roll!"minutes"(1);
5557             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5558         }
5559 
5560         {
5561             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999));
5562             sysTime.roll!"minutes"(-1);
5563             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999)));
5564             sysTime.roll!"minutes"(1);
5565             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999)));
5566         }
5567 
5568         {
5569             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 0));
5570             sysTime.roll!"minutes"(1);
5571             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 0)));
5572             sysTime.roll!"minutes"(-1);
5573             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0)));
5574         }
5575 
5576         {
5577             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5578             sysTime.roll!"minutes"(1);
5579             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 59), hnsecs(9_999_999)));
5580             sysTime.roll!"minutes"(-1);
5581             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5582         }
5583 
5584         {
5585             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5586             sysTime.roll!"minutes"(1).roll!"minutes"(-79);
5587             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 41, 59), hnsecs(9_999_999)));
5588         }
5589 
5590         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5591         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5592         static assert(!__traits(compiles, cst.roll!"minutes"(4)));
5593         static assert(!__traits(compiles, ist.roll!"minutes"(4)));
5594 
5595         static void testScope(scope ref SysTime st) @safe
5596         {
5597             auto result = st.roll!"minutes"(42);
5598         }
5599     }
5600 
5601     // Test roll!"seconds"().
5602     @safe unittest
5603     {
5604         import core.time;
5605         static void testST(SysTime orig, int seconds, SysTime expected, size_t line = __LINE__) @safe
5606         {
5607             orig.roll!"seconds"(seconds);
5608             if (orig != expected)
5609                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5610         }
5611 
5612         // Test A.D.
5613         immutable d = msecs(274);
5614         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
5615         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5616         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5617         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 35), d));
5618         testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 12, 30, 36), d));
5619         testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 12, 30, 37), d));
5620         testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 12, 30, 38), d));
5621         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 43), d));
5622         testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 12, 30, 48), d));
5623         testST(beforeAD, 26, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5624         testST(beforeAD, 27, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5625         testST(beforeAD, 30, SysTime(DateTime(1999, 7, 6, 12, 30, 3), d));
5626         testST(beforeAD, 59, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5627         testST(beforeAD, 60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5628         testST(beforeAD, 61, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5629 
5630         testST(beforeAD, 1766, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5631         testST(beforeAD, 1767, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5632         testST(beforeAD, 1768, SysTime(DateTime(1999, 7, 6, 12, 30, 1), d));
5633         testST(beforeAD, 2007, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5634         testST(beforeAD, 3599, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5635         testST(beforeAD, 3600, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5636         testST(beforeAD, 3601, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5637         testST(beforeAD, 7200, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5638 
5639         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5640         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 31), d));
5641         testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 12, 30, 30), d));
5642         testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 12, 30, 29), d));
5643         testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 12, 30, 28), d));
5644         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 23), d));
5645         testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 12, 30, 18), d));
5646         testST(beforeAD, -33, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5647         testST(beforeAD, -34, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5648         testST(beforeAD, -35, SysTime(DateTime(1999, 7, 6, 12, 30, 58), d));
5649         testST(beforeAD, -59, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5650         testST(beforeAD, -60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5651         testST(beforeAD, -61, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5652 
5653         testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), 1, SysTime(DateTime(1999, 7, 6, 12, 30, 1), d));
5654         testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), 0, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5655         testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), -1, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5656 
5657         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), 1, SysTime(DateTime(1999, 7, 6, 12, 0, 1), d));
5658         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), 0, SysTime(DateTime(1999, 7, 6, 12, 0, 0), d));
5659         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), -1, SysTime(DateTime(1999, 7, 6, 12, 0, 59), d));
5660 
5661         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), 1, SysTime(DateTime(1999, 7, 6, 0, 0, 1), d));
5662         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), 0, SysTime(DateTime(1999, 7, 6, 0, 0, 0), d));
5663         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), -1, SysTime(DateTime(1999, 7, 6, 0, 0, 59), d));
5664 
5665         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), 1, SysTime(DateTime(1999, 7, 5, 23, 59, 0), d));
5666         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), 0, SysTime(DateTime(1999, 7, 5, 23, 59, 59), d));
5667         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), -1, SysTime(DateTime(1999, 7, 5, 23, 59, 58), d));
5668 
5669         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(1998, 12, 31, 23, 59, 0), d));
5670         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), 0, SysTime(DateTime(1998, 12, 31, 23, 59, 59), d));
5671         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), -1, SysTime(DateTime(1998, 12, 31, 23, 59, 58), d));
5672 
5673         // Test B.C.
5674         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
5675         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5676         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5677         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 35), d));
5678         testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 12, 30, 36), d));
5679         testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 12, 30, 37), d));
5680         testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 12, 30, 38), d));
5681         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 43), d));
5682         testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 12, 30, 48), d));
5683         testST(beforeBC, 26, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5684         testST(beforeBC, 27, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5685         testST(beforeBC, 30, SysTime(DateTime(-1999, 7, 6, 12, 30, 3), d));
5686         testST(beforeBC, 59, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5687         testST(beforeBC, 60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5688         testST(beforeBC, 61, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5689 
5690         testST(beforeBC, 1766, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5691         testST(beforeBC, 1767, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5692         testST(beforeBC, 1768, SysTime(DateTime(-1999, 7, 6, 12, 30, 1), d));
5693         testST(beforeBC, 2007, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5694         testST(beforeBC, 3599, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5695         testST(beforeBC, 3600, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5696         testST(beforeBC, 3601, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5697         testST(beforeBC, 7200, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5698 
5699         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5700         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 31), d));
5701         testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 12, 30, 30), d));
5702         testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 12, 30, 29), d));
5703         testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 12, 30, 28), d));
5704         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 23), d));
5705         testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 12, 30, 18), d));
5706         testST(beforeBC, -33, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5707         testST(beforeBC, -34, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5708         testST(beforeBC, -35, SysTime(DateTime(-1999, 7, 6, 12, 30, 58), d));
5709         testST(beforeBC, -59, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5710         testST(beforeBC, -60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5711         testST(beforeBC, -61, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5712 
5713         testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 1), d));
5714         testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5715         testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5716 
5717         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 0, 1), d));
5718         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d));
5719         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 0, 59), d));
5720 
5721         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 0, 1), d));
5722         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d));
5723         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 0, 0, 59), d));
5724 
5725         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), 1, SysTime(DateTime(-1999, 7, 5, 23, 59, 0), d));
5726         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), 0, SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d));
5727         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), -1, SysTime(DateTime(-1999, 7, 5, 23, 59, 58), d));
5728 
5729         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(-2000, 12, 31, 23, 59, 0), d));
5730         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), 0, SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d));
5731         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), -1, SysTime(DateTime(-2000, 12, 31, 23, 59, 58), d));
5732 
5733         // Test Both
5734         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), d), -1, SysTime(DateTime(1, 1, 1, 0, 0, 59), d));
5735         testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(0, 12, 31, 23, 59, 0), d));
5736 
5737         testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), d), -1, SysTime(DateTime(0, 1, 1, 0, 0, 59), d));
5738         testST(SysTime(DateTime(-1, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(-1, 12, 31, 23, 59, 0), d));
5739 
5740         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 63_165_600L, SysTime(DateTime(-1, 1, 1, 11, 30, 33), d));
5741         testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -63_165_600L, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5742 
5743         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 63_165_617L, SysTime(DateTime(-1, 1, 1, 11, 30, 50), d));
5744         testST(SysTime(DateTime(1, 1, 1, 13, 30, 50), d), -63_165_617L, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5745 
5746         {
5747             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5748             sysTime.roll!"seconds"(-1);
5749             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59)));
5750             sysTime.roll!"seconds"(1);
5751             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5752         }
5753 
5754         {
5755             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999));
5756             sysTime.roll!"seconds"(-1);
5757             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999)));
5758             sysTime.roll!"seconds"(1);
5759             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
5760         }
5761 
5762         {
5763             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59));
5764             sysTime.roll!"seconds"(1);
5765             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0)));
5766             sysTime.roll!"seconds"(-1);
5767             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59)));
5768         }
5769 
5770         {
5771             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5772             sysTime.roll!"seconds"(1);
5773             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0), hnsecs(9_999_999)));
5774             sysTime.roll!"seconds"(-1);
5775             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5776         }
5777 
5778         {
5779             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5780             sysTime.roll!"seconds"(1).roll!"seconds"(-102);
5781             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 18), hnsecs(9_999_999)));
5782         }
5783 
5784         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5785         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5786         static assert(!__traits(compiles, cst.roll!"seconds"(4)));
5787         static assert(!__traits(compiles, ist.roll!"seconds"(4)));
5788 
5789         static void testScope(scope ref SysTime st) @safe
5790         {
5791             auto result = st.roll!"seconds"(42);
5792         }
5793     }
5794 
5795 
5796     // Shares documentation with "days" version.
5797     ref SysTime roll(string units)(long value) @safe nothrow scope
5798         if (units == "msecs" || units == "usecs" || units == "hnsecs")
5799     {
5800         auto hnsecs = adjTime;
5801         immutable days = splitUnitsFromHNSecs!"days"(hnsecs);
5802         immutable negative = hnsecs < 0;
5803 
5804         if (negative)
5805             hnsecs += convert!("hours", "hnsecs")(24);
5806 
5807         immutable seconds = splitUnitsFromHNSecs!"seconds"(hnsecs);
5808         hnsecs += convert!(units, "hnsecs")(value);
5809         hnsecs %= convert!("seconds", "hnsecs")(1);
5810 
5811         if (hnsecs < 0)
5812             hnsecs += convert!("seconds", "hnsecs")(1);
5813         hnsecs += convert!("seconds", "hnsecs")(seconds);
5814 
5815         if (negative)
5816             hnsecs -= convert!("hours", "hnsecs")(24);
5817 
5818         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
5819         adjTime = newDaysHNSecs + hnsecs;
5820         return this;
5821     }
5822 
5823 
5824     // Test roll!"msecs"().
5825     @safe unittest
5826     {
5827         import core.time;
5828         static void testST(SysTime orig, int milliseconds, SysTime expected, size_t line = __LINE__) @safe
5829         {
5830             orig.roll!"msecs"(milliseconds);
5831             if (orig != expected)
5832                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5833         }
5834 
5835         // Test A.D.
5836         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274));
5837         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5838         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(275)));
5839         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(276)));
5840         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(284)));
5841         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(374)));
5842         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5843         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5844         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5845         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(275)));
5846         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5847         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5848         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5849         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(1)));
5850         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5851         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5852 
5853         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(273)));
5854         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(272)));
5855         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(264)));
5856         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(174)));
5857         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5858         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5859         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5860         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(273)));
5861         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5862         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5863         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5864         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5865         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5866 
5867         // Test B.C.
5868         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274));
5869         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5870         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(275)));
5871         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(276)));
5872         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(284)));
5873         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(374)));
5874         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5875         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5876         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5877         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(275)));
5878         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5879         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5880         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5881         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(1)));
5882         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5883         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5884 
5885         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(273)));
5886         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(272)));
5887         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(264)));
5888         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(174)));
5889         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5890         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5891         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5892         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(273)));
5893         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5894         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5895         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5896         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5897         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5898 
5899         // Test Both
5900         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5901         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(1)));
5902         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5903         testST(beforeBoth1, -1, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(999)));
5904         testST(beforeBoth1, -2, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(998)));
5905         testST(beforeBoth1, -1000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5906         testST(beforeBoth1, -2000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5907         testST(beforeBoth1, -2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(445)));
5908 
5909         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5910         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_989_999)));
5911         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5912         testST(beforeBoth2, 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9999)));
5913         testST(beforeBoth2, 2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19_999)));
5914         testST(beforeBoth2, 1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5915         testST(beforeBoth2, 2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5916         testST(beforeBoth2, 2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(5_549_999)));
5917 
5918         {
5919             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5920             st.roll!"msecs"(1202).roll!"msecs"(-703);
5921             assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(4_989_999)));
5922         }
5923 
5924         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5925         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5926         static assert(!__traits(compiles, cst.roll!"msecs"(4)));
5927         static assert(!__traits(compiles, ist.roll!"msecs"(4)));
5928 
5929         static void testScope(scope ref SysTime st) @safe
5930         {
5931             auto result = st.roll!"msecs"(42);
5932         }
5933     }
5934 
5935     // Test roll!"usecs"().
5936     @safe unittest
5937     {
5938         import core.time;
5939         static void testST(SysTime orig, long microseconds, SysTime expected, size_t line = __LINE__) @safe
5940         {
5941             orig.roll!"usecs"(microseconds);
5942             if (orig != expected)
5943                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5944         }
5945 
5946         // Test A.D.
5947         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274));
5948         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5949         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(275)));
5950         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(276)));
5951         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(284)));
5952         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(374)));
5953         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999)));
5954         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1000)));
5955         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1274)));
5956         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1275)));
5957         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(2274)));
5958         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(26_999)));
5959         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(27_000)));
5960         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(27_001)));
5961         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(766_999)));
5962         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(767_000)));
5963         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5964         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5965         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5966 
5967         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(273)));
5968         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(272)));
5969         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(264)));
5970         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(174)));
5971         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5972         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_999)));
5973         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_274)));
5974         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_273)));
5975         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(998_274)));
5976         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(967_000)));
5977         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(966_999)));
5978         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(167_000)));
5979         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(166_999)));
5980         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5981         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5982         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5983 
5984         // Test B.C.
5985         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274));
5986         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
5987         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(275)));
5988         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(276)));
5989         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(284)));
5990         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(374)));
5991         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999)));
5992         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1000)));
5993         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1274)));
5994         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1275)));
5995         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(2274)));
5996         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(26_999)));
5997         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(27_000)));
5998         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(27_001)));
5999         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(766_999)));
6000         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(767_000)));
6001         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6002         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6003         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6004 
6005         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(273)));
6006         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(272)));
6007         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(264)));
6008         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(174)));
6009         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
6010         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_999)));
6011         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_274)));
6012         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_273)));
6013         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(998_274)));
6014         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(967_000)));
6015         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(966_999)));
6016         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(167_000)));
6017         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(166_999)));
6018         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6019         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6020         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6021 
6022         // Test Both
6023         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
6024         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(1)));
6025         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6026         testST(beforeBoth1, -1, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_999)));
6027         testST(beforeBoth1, -2, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_998)));
6028         testST(beforeBoth1, -1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_000)));
6029         testST(beforeBoth1, -2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(998_000)));
6030         testST(beforeBoth1, -2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(997_445)));
6031         testST(beforeBoth1, -1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6032         testST(beforeBoth1, -2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6033         testST(beforeBoth1, -2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(666_667)));
6034 
6035         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6036         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_989)));
6037         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6038         testST(beforeBoth2, 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9)));
6039         testST(beforeBoth2, 2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19)));
6040         testST(beforeBoth2, 1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9999)));
6041         testST(beforeBoth2, 2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19_999)));
6042         testST(beforeBoth2, 2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(25_549)));
6043         testST(beforeBoth2, 1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6044         testST(beforeBoth2, 2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6045         testST(beforeBoth2, 2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(3_333_329)));
6046 
6047         {
6048             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6049             st.roll!"usecs"(9_020_027);
6050             assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(200_269)));
6051         }
6052 
6053         {
6054             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6055             st.roll!"usecs"(9_020_027).roll!"usecs"(-70_034);
6056             assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_499_929)));
6057         }
6058 
6059         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6060         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6061         static assert(!__traits(compiles, cst.roll!"usecs"(4)));
6062         static assert(!__traits(compiles, ist.roll!"usecs"(4)));
6063 
6064         static void testScope(scope ref SysTime st) @safe
6065         {
6066             auto result = st.roll!"usecs"(42);
6067         }
6068     }
6069 
6070     // Test roll!"hnsecs"().
6071     @safe unittest
6072     {
6073         import core.time;
6074         static void testST(SysTime orig, long hnsecs, SysTime expected, size_t line = __LINE__) @safe
6075         {
6076             orig.roll!"hnsecs"(hnsecs);
6077             if (orig != expected)
6078                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
6079         }
6080 
6081         // Test A.D.
6082         auto dtAD = DateTime(1999, 7, 6, 12, 30, 33);
6083         auto beforeAD = SysTime(dtAD, hnsecs(274));
6084         testST(beforeAD, 0, SysTime(dtAD, hnsecs(274)));
6085         testST(beforeAD, 1, SysTime(dtAD, hnsecs(275)));
6086         testST(beforeAD, 2, SysTime(dtAD, hnsecs(276)));
6087         testST(beforeAD, 10, SysTime(dtAD, hnsecs(284)));
6088         testST(beforeAD, 100, SysTime(dtAD, hnsecs(374)));
6089         testST(beforeAD, 725, SysTime(dtAD, hnsecs(999)));
6090         testST(beforeAD, 726, SysTime(dtAD, hnsecs(1000)));
6091         testST(beforeAD, 1000, SysTime(dtAD, hnsecs(1274)));
6092         testST(beforeAD, 1001, SysTime(dtAD, hnsecs(1275)));
6093         testST(beforeAD, 2000, SysTime(dtAD, hnsecs(2274)));
6094         testST(beforeAD, 26_725, SysTime(dtAD, hnsecs(26_999)));
6095         testST(beforeAD, 26_726, SysTime(dtAD, hnsecs(27_000)));
6096         testST(beforeAD, 26_727, SysTime(dtAD, hnsecs(27_001)));
6097         testST(beforeAD, 1_766_725, SysTime(dtAD, hnsecs(1_766_999)));
6098         testST(beforeAD, 1_766_726, SysTime(dtAD, hnsecs(1_767_000)));
6099         testST(beforeAD, 1_000_000, SysTime(dtAD, hnsecs(1_000_274)));
6100         testST(beforeAD, 60_000_000L, SysTime(dtAD, hnsecs(274)));
6101         testST(beforeAD, 3_600_000_000L, SysTime(dtAD, hnsecs(274)));
6102         testST(beforeAD, 600_000_000L, SysTime(dtAD, hnsecs(274)));
6103         testST(beforeAD, 36_000_000_000L, SysTime(dtAD, hnsecs(274)));
6104 
6105         testST(beforeAD, -1, SysTime(dtAD, hnsecs(273)));
6106         testST(beforeAD, -2, SysTime(dtAD, hnsecs(272)));
6107         testST(beforeAD, -10, SysTime(dtAD, hnsecs(264)));
6108         testST(beforeAD, -100, SysTime(dtAD, hnsecs(174)));
6109         testST(beforeAD, -274, SysTime(dtAD));
6110         testST(beforeAD, -275, SysTime(dtAD, hnsecs(9_999_999)));
6111         testST(beforeAD, -1000, SysTime(dtAD, hnsecs(9_999_274)));
6112         testST(beforeAD, -1001, SysTime(dtAD, hnsecs(9_999_273)));
6113         testST(beforeAD, -2000, SysTime(dtAD, hnsecs(9_998_274)));
6114         testST(beforeAD, -33_274, SysTime(dtAD, hnsecs(9_967_000)));
6115         testST(beforeAD, -33_275, SysTime(dtAD, hnsecs(9_966_999)));
6116         testST(beforeAD, -1_833_274, SysTime(dtAD, hnsecs(8_167_000)));
6117         testST(beforeAD, -1_833_275, SysTime(dtAD, hnsecs(8_166_999)));
6118         testST(beforeAD, -1_000_000, SysTime(dtAD, hnsecs(9_000_274)));
6119         testST(beforeAD, -60_000_000L, SysTime(dtAD, hnsecs(274)));
6120         testST(beforeAD, -3_600_000_000L, SysTime(dtAD, hnsecs(274)));
6121         testST(beforeAD, -600_000_000L, SysTime(dtAD, hnsecs(274)));
6122         testST(beforeAD, -36_000_000_000L, SysTime(dtAD, hnsecs(274)));
6123 
6124         // Test B.C.
6125         auto dtBC = DateTime(-1999, 7, 6, 12, 30, 33);
6126         auto beforeBC = SysTime(dtBC, hnsecs(274));
6127         testST(beforeBC, 0, SysTime(dtBC, hnsecs(274)));
6128         testST(beforeBC, 1, SysTime(dtBC, hnsecs(275)));
6129         testST(beforeBC, 2, SysTime(dtBC, hnsecs(276)));
6130         testST(beforeBC, 10, SysTime(dtBC, hnsecs(284)));
6131         testST(beforeBC, 100, SysTime(dtBC, hnsecs(374)));
6132         testST(beforeBC, 725, SysTime(dtBC, hnsecs(999)));
6133         testST(beforeBC, 726, SysTime(dtBC, hnsecs(1000)));
6134         testST(beforeBC, 1000, SysTime(dtBC, hnsecs(1274)));
6135         testST(beforeBC, 1001, SysTime(dtBC, hnsecs(1275)));
6136         testST(beforeBC, 2000, SysTime(dtBC, hnsecs(2274)));
6137         testST(beforeBC, 26_725, SysTime(dtBC, hnsecs(26_999)));
6138         testST(beforeBC, 26_726, SysTime(dtBC, hnsecs(27_000)));
6139         testST(beforeBC, 26_727, SysTime(dtBC, hnsecs(27_001)));
6140         testST(beforeBC, 1_766_725, SysTime(dtBC, hnsecs(1_766_999)));
6141         testST(beforeBC, 1_766_726, SysTime(dtBC, hnsecs(1_767_000)));
6142         testST(beforeBC, 1_000_000, SysTime(dtBC, hnsecs(1_000_274)));
6143         testST(beforeBC, 60_000_000L, SysTime(dtBC, hnsecs(274)));
6144         testST(beforeBC, 3_600_000_000L, SysTime(dtBC, hnsecs(274)));
6145         testST(beforeBC, 600_000_000L, SysTime(dtBC, hnsecs(274)));
6146         testST(beforeBC, 36_000_000_000L, SysTime(dtBC, hnsecs(274)));
6147 
6148         testST(beforeBC, -1, SysTime(dtBC, hnsecs(273)));
6149         testST(beforeBC, -2, SysTime(dtBC, hnsecs(272)));
6150         testST(beforeBC, -10, SysTime(dtBC, hnsecs(264)));
6151         testST(beforeBC, -100, SysTime(dtBC, hnsecs(174)));
6152         testST(beforeBC, -274, SysTime(dtBC));
6153         testST(beforeBC, -275, SysTime(dtBC, hnsecs(9_999_999)));
6154         testST(beforeBC, -1000, SysTime(dtBC, hnsecs(9_999_274)));
6155         testST(beforeBC, -1001, SysTime(dtBC, hnsecs(9_999_273)));
6156         testST(beforeBC, -2000, SysTime(dtBC, hnsecs(9_998_274)));
6157         testST(beforeBC, -33_274, SysTime(dtBC, hnsecs(9_967_000)));
6158         testST(beforeBC, -33_275, SysTime(dtBC, hnsecs(9_966_999)));
6159         testST(beforeBC, -1_833_274, SysTime(dtBC, hnsecs(8_167_000)));
6160         testST(beforeBC, -1_833_275, SysTime(dtBC, hnsecs(8_166_999)));
6161         testST(beforeBC, -1_000_000, SysTime(dtBC, hnsecs(9_000_274)));
6162         testST(beforeBC, -60_000_000L, SysTime(dtBC, hnsecs(274)));
6163         testST(beforeBC, -3_600_000_000L, SysTime(dtBC, hnsecs(274)));
6164         testST(beforeBC, -600_000_000L, SysTime(dtBC, hnsecs(274)));
6165         testST(beforeBC, -36_000_000_000L, SysTime(dtBC, hnsecs(274)));
6166 
6167         // Test Both
6168         auto dtBoth1 = DateTime(1, 1, 1, 0, 0, 0);
6169         auto beforeBoth1 = SysTime(dtBoth1);
6170         testST(beforeBoth1, 1, SysTime(dtBoth1, hnsecs(1)));
6171         testST(beforeBoth1, 0, SysTime(dtBoth1));
6172         testST(beforeBoth1, -1, SysTime(dtBoth1, hnsecs(9_999_999)));
6173         testST(beforeBoth1, -2, SysTime(dtBoth1, hnsecs(9_999_998)));
6174         testST(beforeBoth1, -1000, SysTime(dtBoth1, hnsecs(9_999_000)));
6175         testST(beforeBoth1, -2000, SysTime(dtBoth1, hnsecs(9_998_000)));
6176         testST(beforeBoth1, -2555, SysTime(dtBoth1, hnsecs(9_997_445)));
6177         testST(beforeBoth1, -1_000_000, SysTime(dtBoth1, hnsecs(9_000_000)));
6178         testST(beforeBoth1, -2_000_000, SysTime(dtBoth1, hnsecs(8_000_000)));
6179         testST(beforeBoth1, -2_333_333, SysTime(dtBoth1, hnsecs(7_666_667)));
6180         testST(beforeBoth1, -10_000_000, SysTime(dtBoth1));
6181         testST(beforeBoth1, -20_000_000, SysTime(dtBoth1));
6182         testST(beforeBoth1, -20_888_888, SysTime(dtBoth1, hnsecs(9_111_112)));
6183 
6184         auto dtBoth2 = DateTime(0, 12, 31, 23, 59, 59);
6185         auto beforeBoth2 = SysTime(dtBoth2, hnsecs(9_999_999));
6186         testST(beforeBoth2, -1, SysTime(dtBoth2, hnsecs(9_999_998)));
6187         testST(beforeBoth2, 0, SysTime(dtBoth2, hnsecs(9_999_999)));
6188         testST(beforeBoth2, 1, SysTime(dtBoth2));
6189         testST(beforeBoth2, 2, SysTime(dtBoth2, hnsecs(1)));
6190         testST(beforeBoth2, 1000, SysTime(dtBoth2, hnsecs(999)));
6191         testST(beforeBoth2, 2000, SysTime(dtBoth2, hnsecs(1999)));
6192         testST(beforeBoth2, 2555, SysTime(dtBoth2, hnsecs(2554)));
6193         testST(beforeBoth2, 1_000_000, SysTime(dtBoth2, hnsecs(999_999)));
6194         testST(beforeBoth2, 2_000_000, SysTime(dtBoth2, hnsecs(1_999_999)));
6195         testST(beforeBoth2, 2_333_333, SysTime(dtBoth2, hnsecs(2_333_332)));
6196         testST(beforeBoth2, 10_000_000, SysTime(dtBoth2, hnsecs(9_999_999)));
6197         testST(beforeBoth2, 20_000_000, SysTime(dtBoth2, hnsecs(9_999_999)));
6198         testST(beforeBoth2, 20_888_888, SysTime(dtBoth2, hnsecs(888_887)));
6199 
6200         {
6201             auto st = SysTime(dtBoth2, hnsecs(9_999_999));
6202             st.roll!"hnsecs"(70_777_222).roll!"hnsecs"(-222_555_292);
6203             assert(st == SysTime(dtBoth2, hnsecs(8_221_929)));
6204         }
6205 
6206         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6207         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6208         static assert(!__traits(compiles, cst.roll!"hnsecs"(4)));
6209         static assert(!__traits(compiles, ist.roll!"hnsecs"(4)));
6210 
6211         static void testScope(scope ref SysTime st) @safe
6212         {
6213             auto result = st.roll!"hnsecs"(42);
6214         }
6215     }
6216 
6217 
6218     /++
6219         Gives the result of adding or subtracting a $(REF Duration, core,time)
6220         from this $(LREF SysTime).
6221 
6222         The legal types of arithmetic for $(LREF SysTime) using this operator
6223         are
6224 
6225         $(BOOKTABLE,
6226         $(TR $(TD SysTime) $(TD +) $(TD Duration) $(TD -->) $(TD SysTime))
6227         $(TR $(TD SysTime) $(TD -) $(TD Duration) $(TD -->) $(TD SysTime))
6228         )
6229 
6230         Params:
6231             duration = The $(REF Duration, core,time) to add to or subtract from
6232                        this $(LREF SysTime).
6233       +/
6234     SysTime opBinary(string op)(Duration duration) @safe const pure nothrow scope
6235         if (op == "+" || op == "-")
6236     {
6237         SysTime retval = SysTime(this._stdTime, this._timezone);
6238         immutable hnsecs = duration.total!"hnsecs";
6239         mixin("retval._stdTime " ~ op ~ "= hnsecs;");
6240         return retval;
6241     }
6242 
6243     ///
6244     @safe unittest
6245     {
6246         import core.time : hours, seconds;
6247         import std.datetime.date : DateTime;
6248 
6249         assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + seconds(1) ==
6250                SysTime(DateTime(2016, 1, 1, 0, 0, 0)));
6251 
6252         assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + hours(1) ==
6253                SysTime(DateTime(2016, 1, 1, 0, 59, 59)));
6254 
6255         assert(SysTime(DateTime(2016, 1, 1, 0, 0, 0)) - seconds(1) ==
6256                SysTime(DateTime(2015, 12, 31, 23, 59, 59)));
6257 
6258         assert(SysTime(DateTime(2016, 1, 1, 0, 59, 59)) - hours(1) ==
6259                SysTime(DateTime(2015, 12, 31, 23, 59, 59)));
6260     }
6261 
6262     @safe unittest
6263     {
6264         import core.time;
6265         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_678));
6266 
6267         assert(st + dur!"weeks"(7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33), hnsecs(2_345_678)));
6268         assert(st + dur!"weeks"(-7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33), hnsecs(2_345_678)));
6269         assert(st + dur!"days"(7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33), hnsecs(2_345_678)));
6270         assert(st + dur!"days"(-7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33), hnsecs(2_345_678)));
6271         assert(st + dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33), hnsecs(2_345_678)));
6272         assert(st + dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33), hnsecs(2_345_678)));
6273         assert(st + dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33), hnsecs(2_345_678)));
6274         assert(st + dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33), hnsecs(2_345_678)));
6275         assert(st + dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40), hnsecs(2_345_678)));
6276         assert(st + dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26), hnsecs(2_345_678)));
6277         assert(st + dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_415_678)));
6278         assert(st + dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_275_678)));
6279         assert(st + dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748)));
6280         assert(st + dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608)));
6281         assert(st + dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_685)));
6282         assert(st + dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_671)));
6283 
6284         assert(st - dur!"weeks"(-7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33), hnsecs(2_345_678)));
6285         assert(st - dur!"weeks"(7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33), hnsecs(2_345_678)));
6286         assert(st - dur!"days"(-7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33), hnsecs(2_345_678)));
6287         assert(st - dur!"days"(7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33), hnsecs(2_345_678)));
6288         assert(st - dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33), hnsecs(2_345_678)));
6289         assert(st - dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33), hnsecs(2_345_678)));
6290         assert(st - dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33), hnsecs(2_345_678)));
6291         assert(st - dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33), hnsecs(2_345_678)));
6292         assert(st - dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40), hnsecs(2_345_678)));
6293         assert(st - dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26), hnsecs(2_345_678)));
6294         assert(st - dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_415_678)));
6295         assert(st - dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_275_678)));
6296         assert(st - dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748)));
6297         assert(st - dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608)));
6298         assert(st - dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_685)));
6299         assert(st - dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_671)));
6300 
6301         static void testST(SysTime orig, long hnsecs, SysTime expected, size_t line = __LINE__) @safe
6302         {
6303             auto result = orig + dur!"hnsecs"(hnsecs);
6304             if (result != expected)
6305                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", result, expected), __FILE__, line);
6306         }
6307 
6308         // Test A.D.
6309         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274));
6310         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274)));
6311         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(275)));
6312         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(276)));
6313         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(284)));
6314         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(374)));
6315         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(999)));
6316         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6317         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6318         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6319         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6320         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6321         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6322         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6323         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6324         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6325         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6326         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), hnsecs(274)));
6327         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), hnsecs(274)));
6328         testST(beforeAD, 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), hnsecs(274)));
6329         testST(beforeAD, 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), hnsecs(274)));
6330 
6331         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(273)));
6332         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(272)));
6333         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(264)));
6334         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(174)));
6335         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
6336         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6337         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6338         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6339         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6340         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6341         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6342         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6343         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6344         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6345         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), hnsecs(274)));
6346         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), hnsecs(274)));
6347         testST(beforeAD, -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), hnsecs(274)));
6348         testST(beforeAD, -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), hnsecs(274)));
6349 
6350         // Test B.C.
6351         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274));
6352         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274)));
6353         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(275)));
6354         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(276)));
6355         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(284)));
6356         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(374)));
6357         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(999)));
6358         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6359         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6360         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6361         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6362         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6363         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6364         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6365         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6366         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6367         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6368         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), hnsecs(274)));
6369         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), hnsecs(274)));
6370         testST(beforeBC, 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), hnsecs(274)));
6371         testST(beforeBC, 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), hnsecs(274)));
6372 
6373         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(273)));
6374         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(272)));
6375         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(264)));
6376         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(174)));
6377         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
6378         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6379         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6380         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6381         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6382         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6383         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6384         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6385         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6386         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6387         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), hnsecs(274)));
6388         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), hnsecs(274)));
6389         testST(beforeBC, -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), hnsecs(274)));
6390         testST(beforeBC, -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), hnsecs(274)));
6391 
6392         // Test Both
6393         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
6394         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6395         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6396         testST(beforeBoth1, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6397         testST(beforeBoth1, -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6398         testST(beforeBoth1, -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_000)));
6399         testST(beforeBoth1, -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_998_000)));
6400         testST(beforeBoth1, -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_997_445)));
6401         testST(beforeBoth1, -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_000_000)));
6402         testST(beforeBoth1, -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(8_000_000)));
6403         testST(beforeBoth1, -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(7_666_667)));
6404         testST(beforeBoth1, -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
6405         testST(beforeBoth1, -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58)));
6406         testST(beforeBoth1, -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), hnsecs(9_111_112)));
6407 
6408         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6409         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6410         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6411         testST(beforeBoth2, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6412         testST(beforeBoth2, 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6413         testST(beforeBoth2, 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999)));
6414         testST(beforeBoth2, 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1999)));
6415         testST(beforeBoth2, 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2554)));
6416         testST(beforeBoth2, 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999_999)));
6417         testST(beforeBoth2, 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1_999_999)));
6418         testST(beforeBoth2, 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2_333_332)));
6419         testST(beforeBoth2, 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6420         testST(beforeBoth2, 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), hnsecs(9_999_999)));
6421         testST(beforeBoth2, 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), hnsecs(888_887)));
6422 
6423         auto duration = dur!"seconds"(12);
6424         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6425         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6426         assert(cst + duration == SysTime(DateTime(1999, 7, 6, 12, 30, 45)));
6427         assert(ist + duration == SysTime(DateTime(1999, 7, 6, 12, 30, 45)));
6428         assert(cst - duration == SysTime(DateTime(1999, 7, 6, 12, 30, 21)));
6429         assert(ist - duration == SysTime(DateTime(1999, 7, 6, 12, 30, 21)));
6430 
6431         static void testScope(scope ref SysTime st, scope ref Duration d) @safe
6432         {
6433             auto result = st + d;
6434         }
6435     }
6436 
6437 
6438     /++
6439         Gives the result of adding or subtracting a $(REF Duration, core,time) from
6440         this $(LREF SysTime), as well as assigning the result to this
6441         $(LREF SysTime).
6442 
6443         The legal types of arithmetic for $(LREF SysTime) using this operator are
6444 
6445         $(BOOKTABLE,
6446         $(TR $(TD SysTime) $(TD +) $(TD Duration) $(TD -->) $(TD SysTime))
6447         $(TR $(TD SysTime) $(TD -) $(TD Duration) $(TD -->) $(TD SysTime))
6448         )
6449 
6450         Params:
6451             duration = The $(REF Duration, core,time) to add to or subtract from
6452                        this $(LREF SysTime).
6453       +/
6454     ref SysTime opOpAssign(string op)(Duration duration) @safe pure nothrow scope
6455         if (op == "+" || op == "-")
6456     {
6457         immutable hnsecs = duration.total!"hnsecs";
6458         mixin("_stdTime " ~ op ~ "= hnsecs;");
6459         return this;
6460     }
6461 
6462     @safe unittest
6463     {
6464         import core.time;
6465         auto before = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6466         assert(before + dur!"weeks"(7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33)));
6467         assert(before + dur!"weeks"(-7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33)));
6468         assert(before + dur!"days"(7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33)));
6469         assert(before + dur!"days"(-7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33)));
6470 
6471         assert(before + dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33)));
6472         assert(before + dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33)));
6473         assert(before + dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33)));
6474         assert(before + dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33)));
6475         assert(before + dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40)));
6476         assert(before + dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26)));
6477         assert(before + dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(7)));
6478         assert(before + dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), msecs(993)));
6479         assert(before + dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(7)));
6480         assert(before + dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), usecs(999_993)));
6481         assert(before + dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(7)));
6482         assert(before + dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_993)));
6483 
6484         assert(before - dur!"weeks"(-7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33)));
6485         assert(before - dur!"weeks"(7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33)));
6486         assert(before - dur!"days"(-7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33)));
6487         assert(before - dur!"days"(7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33)));
6488 
6489         assert(before - dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33)));
6490         assert(before - dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33)));
6491         assert(before - dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33)));
6492         assert(before - dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33)));
6493         assert(before - dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40)));
6494         assert(before - dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26)));
6495         assert(before - dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(7)));
6496         assert(before - dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), msecs(993)));
6497         assert(before - dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(7)));
6498         assert(before - dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), usecs(999_993)));
6499         assert(before - dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(7)));
6500         assert(before - dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_993)));
6501 
6502         static void testST(SysTime orig, long hnsecs, SysTime expected, size_t line = __LINE__) @safe
6503         {
6504             auto r = orig += dur!"hnsecs"(hnsecs);
6505             if (orig != expected)
6506                 throw new AssertError(format("Failed 1. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
6507             if (r != expected)
6508                 throw new AssertError(format("Failed 2. actual [%s] != expected [%s]", r, expected), __FILE__, line);
6509         }
6510 
6511         // Test A.D.
6512         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274));
6513         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274)));
6514         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(275)));
6515         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(276)));
6516         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(284)));
6517         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(374)));
6518         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(999)));
6519         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6520         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6521         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6522         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6523         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6524         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6525         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6526         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6527         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6528         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6529         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), hnsecs(274)));
6530         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), hnsecs(274)));
6531         testST(beforeAD, 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), hnsecs(274)));
6532         testST(beforeAD, 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), hnsecs(274)));
6533 
6534         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(273)));
6535         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(272)));
6536         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(264)));
6537         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(174)));
6538         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
6539         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6540         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6541         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6542         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6543         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6544         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6545         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6546         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6547         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6548         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), hnsecs(274)));
6549         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), hnsecs(274)));
6550         testST(beforeAD, -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), hnsecs(274)));
6551         testST(beforeAD, -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), hnsecs(274)));
6552 
6553         // Test B.C.
6554         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274));
6555         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274)));
6556         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(275)));
6557         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(276)));
6558         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(284)));
6559         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(374)));
6560         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(999)));
6561         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6562         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6563         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6564         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6565         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6566         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6567         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6568         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6569         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6570         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6571         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), hnsecs(274)));
6572         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), hnsecs(274)));
6573         testST(beforeBC, 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), hnsecs(274)));
6574         testST(beforeBC, 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), hnsecs(274)));
6575 
6576         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(273)));
6577         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(272)));
6578         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(264)));
6579         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(174)));
6580         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
6581         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6582         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6583         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6584         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6585         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6586         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6587         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6588         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6589         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6590         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), hnsecs(274)));
6591         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), hnsecs(274)));
6592         testST(beforeBC, -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), hnsecs(274)));
6593         testST(beforeBC, -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), hnsecs(274)));
6594 
6595         // Test Both
6596         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
6597         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6598         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6599         testST(beforeBoth1, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6600         testST(beforeBoth1, -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6601         testST(beforeBoth1, -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_000)));
6602         testST(beforeBoth1, -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_998_000)));
6603         testST(beforeBoth1, -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_997_445)));
6604         testST(beforeBoth1, -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_000_000)));
6605         testST(beforeBoth1, -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(8_000_000)));
6606         testST(beforeBoth1, -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(7_666_667)));
6607         testST(beforeBoth1, -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
6608         testST(beforeBoth1, -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58)));
6609         testST(beforeBoth1, -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), hnsecs(9_111_112)));
6610 
6611         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6612         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6613         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6614         testST(beforeBoth2, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6615         testST(beforeBoth2, 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6616         testST(beforeBoth2, 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999)));
6617         testST(beforeBoth2, 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1999)));
6618         testST(beforeBoth2, 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2554)));
6619         testST(beforeBoth2, 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999_999)));
6620         testST(beforeBoth2, 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1_999_999)));
6621         testST(beforeBoth2, 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2_333_332)));
6622         testST(beforeBoth2, 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6623         testST(beforeBoth2, 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), hnsecs(9_999_999)));
6624         testST(beforeBoth2, 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), hnsecs(888_887)));
6625 
6626         {
6627             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6628             (st += dur!"hnsecs"(52)) += dur!"seconds"(-907);
6629             assert(st == SysTime(DateTime(0, 12, 31, 23, 44, 53), hnsecs(51)));
6630         }
6631 
6632         auto duration = dur!"seconds"(12);
6633         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6634         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6635         static assert(!__traits(compiles, cst += duration));
6636         static assert(!__traits(compiles, ist += duration));
6637         static assert(!__traits(compiles, cst -= duration));
6638         static assert(!__traits(compiles, ist -= duration));
6639 
6640         static void testScope(scope ref SysTime st, scope ref Duration d) @safe
6641         {
6642             auto result1 = st += d;
6643             auto result2 = st -= d;
6644         }
6645     }
6646 
6647 
6648     /++
6649         Gives the difference between two $(LREF SysTime)s.
6650 
6651         The legal types of arithmetic for $(LREF SysTime) using this operator
6652         are
6653 
6654         $(BOOKTABLE,
6655         $(TR $(TD SysTime) $(TD -) $(TD SysTime) $(TD -->) $(TD duration))
6656         )
6657       +/
6658     Duration opBinary(string op)(SysTime rhs) @safe const pure nothrow scope
6659         if (op == "-")
6660     {
6661         return dur!"hnsecs"(_stdTime - rhs._stdTime);
6662     }
6663 
6664     @safe unittest
6665     {
6666         import core.time;
6667         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1998, 7, 6, 12, 30, 33)) ==
6668                dur!"seconds"(31_536_000));
6669         assert(SysTime(DateTime(1998, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6670                dur!"seconds"(-31_536_000));
6671 
6672         assert(SysTime(DateTime(1999, 8, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6673                dur!"seconds"(26_78_400));
6674         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 8, 6, 12, 30, 33)) ==
6675                dur!"seconds"(-26_78_400));
6676 
6677         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 5, 12, 30, 33)) ==
6678                dur!"seconds"(86_400));
6679         assert(SysTime(DateTime(1999, 7, 5, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6680                dur!"seconds"(-86_400));
6681 
6682         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 11, 30, 33)) ==
6683                dur!"seconds"(3600));
6684         assert(SysTime(DateTime(1999, 7, 6, 11, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6685                dur!"seconds"(-3600));
6686 
6687         assert(SysTime(DateTime(1999, 7, 6, 12, 31, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6688                dur!"seconds"(60));
6689         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 31, 33)) ==
6690                dur!"seconds"(-60));
6691 
6692         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 34)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6693                dur!"seconds"(1));
6694         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 34)) ==
6695                dur!"seconds"(-1));
6696 
6697         {
6698             auto dt = DateTime(1999, 7, 6, 12, 30, 33);
6699             assert(SysTime(dt, msecs(532)) - SysTime(dt) == msecs(532));
6700             assert(SysTime(dt) - SysTime(dt, msecs(532)) == msecs(-532));
6701 
6702             assert(SysTime(dt, usecs(333_347)) - SysTime(dt) == usecs(333_347));
6703             assert(SysTime(dt) - SysTime(dt, usecs(333_347)) == usecs(-333_347));
6704 
6705             assert(SysTime(dt, hnsecs(1_234_567)) - SysTime(dt) == hnsecs(1_234_567));
6706             assert(SysTime(dt) - SysTime(dt, hnsecs(1_234_567)) == hnsecs(-1_234_567));
6707         }
6708 
6709         assert(SysTime(DateTime(1, 1, 1, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) == dur!"seconds"(45033));
6710         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(1, 1, 1, 12, 30, 33)) == dur!"seconds"(-45033));
6711         assert(SysTime(DateTime(0, 12, 31, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) == dur!"seconds"(-41367));
6712         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 12, 30, 33)) == dur!"seconds"(41367));
6713 
6714         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)) ==
6715                dur!"hnsecs"(1));
6716         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) ==
6717                dur!"hnsecs"(-1));
6718 
6719         version (Posix)
6720         {
6721             import std.datetime.timezone : PosixTimeZone;
6722             immutable tz = PosixTimeZone.getTimeZone("America/Los_Angeles");
6723         }
6724         else version (Windows)
6725         {
6726             import std.datetime.timezone : WindowsTimeZone;
6727             immutable tz = WindowsTimeZone.getTimeZone("Pacific Standard Time");
6728         }
6729 
6730         {
6731             auto dt = DateTime(2011, 1, 13, 8, 17, 2);
6732             auto d = msecs(296);
6733             assert(SysTime(dt, d, tz) - SysTime(dt, d, tz) == Duration.zero);
6734             assert(SysTime(dt, d, tz) - SysTime(dt, d, UTC()) == hours(8));
6735             assert(SysTime(dt, d, UTC()) - SysTime(dt, d, tz) == hours(-8));
6736         }
6737 
6738         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6739         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6740         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6741         assert(st - st == Duration.zero);
6742         assert(cst - st == Duration.zero);
6743         assert(ist - st == Duration.zero);
6744 
6745         assert(st - cst == Duration.zero);
6746         assert(cst - cst == Duration.zero);
6747         assert(ist - cst == Duration.zero);
6748 
6749         assert(st - ist == Duration.zero);
6750         assert(cst - ist == Duration.zero);
6751         assert(ist - ist == Duration.zero);
6752 
6753         static void testScope(scope ref SysTime left, scope ref SysTime right) @safe
6754         {
6755             auto result = left - right;
6756         }
6757     }
6758 
6759 
6760     /++
6761         Returns the difference between the two $(LREF SysTime)s in months.
6762 
6763         To get the difference in years, subtract the year property
6764         of two $(LREF SysTime)s. To get the difference in days or weeks,
6765         subtract the $(LREF SysTime)s themselves and use the
6766         $(REF Duration, core,time) that results. Because converting between
6767         months and smaller units requires a specific date (which
6768         $(REF Duration, core,time)s don't have), getting the difference in
6769         months requires some math using both the year and month properties, so
6770         this is a convenience function for getting the difference in months.
6771 
6772         Note that the number of days in the months or how far into the month
6773         either date is is irrelevant. It is the difference in the month property
6774         combined with the difference in years * 12. So, for instance,
6775         December 31st and January 1st are one month apart just as December 1st
6776         and January 31st are one month apart.
6777 
6778         Params:
6779             rhs = The $(LREF SysTime) to subtract from this one.
6780       +/
6781     int diffMonths(scope SysTime rhs) @safe const nothrow scope
6782     {
6783         return (cast(Date) this).diffMonths(cast(Date) rhs);
6784     }
6785 
6786     ///
6787     @safe unittest
6788     {
6789         import core.time;
6790         import std.datetime.date : Date;
6791 
6792         assert(SysTime(Date(1999, 2, 1)).diffMonths(
6793                    SysTime(Date(1999, 1, 31))) == 1);
6794 
6795         assert(SysTime(Date(1999, 1, 31)).diffMonths(
6796                    SysTime(Date(1999, 2, 1))) == -1);
6797 
6798         assert(SysTime(Date(1999, 3, 1)).diffMonths(
6799                    SysTime(Date(1999, 1, 1))) == 2);
6800 
6801         assert(SysTime(Date(1999, 1, 1)).diffMonths(
6802                    SysTime(Date(1999, 3, 31))) == -2);
6803     }
6804 
6805     @safe unittest
6806     {
6807         import core.time;
6808         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6809         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6810         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6811         assert(st.diffMonths(st) == 0);
6812         assert(cst.diffMonths(st) == 0);
6813         assert(ist.diffMonths(st) == 0);
6814 
6815         assert(st.diffMonths(cst) == 0);
6816         assert(cst.diffMonths(cst) == 0);
6817         assert(ist.diffMonths(cst) == 0);
6818 
6819         assert(st.diffMonths(ist) == 0);
6820         assert(cst.diffMonths(ist) == 0);
6821         assert(ist.diffMonths(ist) == 0);
6822 
6823         static void testScope(scope ref SysTime left, scope ref SysTime right) @safe
6824         {
6825             auto result = left.diffMonths(right);
6826         }
6827     }
6828 
6829 
6830     /++
6831         Whether this $(LREF SysTime) is in a leap year.
6832      +/
6833     @property bool isLeapYear() @safe const nothrow scope
6834     {
6835         return (cast(Date) this).isLeapYear;
6836     }
6837 
6838     @safe unittest
6839     {
6840         import core.time;
6841         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6842         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6843         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6844         assert(!st.isLeapYear);
6845         assert(!cst.isLeapYear);
6846         assert(!ist.isLeapYear);
6847 
6848         static void testScope(scope ref SysTime st) @safe
6849         {
6850             auto result = st.isLeapYear;
6851         }
6852     }
6853 
6854 
6855     /++
6856         Day of the week this $(LREF SysTime) is on.
6857       +/
6858     @property DayOfWeek dayOfWeek() @safe const nothrow scope
6859     {
6860         return getDayOfWeek(dayOfGregorianCal);
6861     }
6862 
6863     @safe unittest
6864     {
6865         import core.time;
6866         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6867         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6868         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6869         assert(st.dayOfWeek == DayOfWeek.tue);
6870         assert(cst.dayOfWeek == DayOfWeek.tue);
6871         assert(ist.dayOfWeek == DayOfWeek.tue);
6872 
6873         static void testScope(scope ref SysTime st) @safe
6874         {
6875             auto result = st.dayOfWeek;
6876         }
6877     }
6878 
6879 
6880     /++
6881         Day of the year this $(LREF SysTime) is on.
6882       +/
6883     @property ushort dayOfYear() @safe const nothrow scope
6884     {
6885         return (cast(Date) this).dayOfYear;
6886     }
6887 
6888     ///
6889     @safe unittest
6890     {
6891         import core.time;
6892         import std.datetime.date : DateTime;
6893 
6894         assert(SysTime(DateTime(1999, 1, 1, 12, 22, 7)).dayOfYear == 1);
6895         assert(SysTime(DateTime(1999, 12, 31, 7, 2, 59)).dayOfYear == 365);
6896         assert(SysTime(DateTime(2000, 12, 31, 21, 20, 0)).dayOfYear == 366);
6897     }
6898 
6899     @safe unittest
6900     {
6901         import core.time;
6902         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6903         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6904         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6905         assert(st.dayOfYear == 187);
6906         assert(cst.dayOfYear == 187);
6907         assert(ist.dayOfYear == 187);
6908 
6909         static void testScope(scope ref SysTime st) @safe
6910         {
6911             auto result = st.dayOfYear;
6912         }
6913     }
6914 
6915 
6916     /++
6917         Day of the year.
6918 
6919         Params:
6920             day = The day of the year to set which day of the year this
6921                   $(LREF SysTime) is on.
6922       +/
6923     @property void dayOfYear(int day) @safe scope
6924     {
6925         immutable hnsecs = adjTime;
6926         immutable days = convert!("hnsecs", "days")(hnsecs);
6927         immutable theRest = hnsecs - convert!("days", "hnsecs")(days);
6928 
6929         auto date = Date(cast(int) days);
6930         date.dayOfYear = day;
6931 
6932         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
6933 
6934         adjTime = newDaysHNSecs + theRest;
6935     }
6936 
6937     @safe unittest
6938     {
6939         import core.time;
6940         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6941         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6942         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6943         st.dayOfYear = 12;
6944         assert(st.dayOfYear == 12);
6945         static assert(!__traits(compiles, cst.dayOfYear = 12));
6946         static assert(!__traits(compiles, ist.dayOfYear = 12));
6947 
6948         static void testScope(scope ref SysTime st) @safe
6949         {
6950             st.dayOfYear = 42;
6951         }
6952     }
6953 
6954 
6955     /++
6956         The Xth day of the Gregorian Calendar that this $(LREF SysTime) is on.
6957      +/
6958     @property int dayOfGregorianCal() @safe const nothrow scope
6959     {
6960         immutable adjustedTime = adjTime;
6961 
6962         // We have to add one because 0 would be midnight, January 1st, 1 A.D.,
6963         // which would be the 1st day of the Gregorian Calendar, not the 0th. So,
6964         // simply casting to days is one day off.
6965         if (adjustedTime > 0)
6966             return cast(int) getUnitsFromHNSecs!"days"(adjustedTime) + 1;
6967 
6968         long hnsecs = adjustedTime;
6969         immutable days = cast(int) splitUnitsFromHNSecs!"days"(hnsecs);
6970 
6971         return hnsecs == 0 ? days + 1 : days;
6972     }
6973 
6974     ///
6975     @safe unittest
6976     {
6977         import core.time;
6978         import std.datetime.date : DateTime;
6979 
6980         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1);
6981         assert(SysTime(DateTime(1, 12, 31, 23, 59, 59)).dayOfGregorianCal == 365);
6982         assert(SysTime(DateTime(2, 1, 1, 2, 2, 2)).dayOfGregorianCal == 366);
6983 
6984         assert(SysTime(DateTime(0, 12, 31, 7, 7, 7)).dayOfGregorianCal == 0);
6985         assert(SysTime(DateTime(0, 1, 1, 19, 30, 0)).dayOfGregorianCal == -365);
6986         assert(SysTime(DateTime(-1, 12, 31, 4, 7, 0)).dayOfGregorianCal == -366);
6987 
6988         assert(SysTime(DateTime(2000, 1, 1, 9, 30, 20)).dayOfGregorianCal == 730_120);
6989         assert(SysTime(DateTime(2010, 12, 31, 15, 45, 50)).dayOfGregorianCal == 734_137);
6990     }
6991 
6992     @safe unittest
6993     {
6994         import core.time;
6995         // Test A.D.
6996         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1);
6997         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)).dayOfGregorianCal == 1);
6998         assert(SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == 1);
6999 
7000         assert(SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1);
7001         assert(SysTime(DateTime(1, 1, 2, 12, 2, 9), msecs(212)).dayOfGregorianCal == 2);
7002         assert(SysTime(DateTime(1, 2, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 32);
7003         assert(SysTime(DateTime(2, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 366);
7004         assert(SysTime(DateTime(3, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 731);
7005         assert(SysTime(DateTime(4, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1096);
7006         assert(SysTime(DateTime(5, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1462);
7007         assert(SysTime(DateTime(50, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 17_898);
7008         assert(SysTime(DateTime(97, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 35_065);
7009         assert(SysTime(DateTime(100, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 36_160);
7010         assert(SysTime(DateTime(101, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 36_525);
7011         assert(SysTime(DateTime(105, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 37_986);
7012         assert(SysTime(DateTime(200, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 72_684);
7013         assert(SysTime(DateTime(201, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 73_049);
7014         assert(SysTime(DateTime(300, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 109_208);
7015         assert(SysTime(DateTime(301, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 109_573);
7016         assert(SysTime(DateTime(400, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 145_732);
7017         assert(SysTime(DateTime(401, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 146_098);
7018         assert(SysTime(DateTime(500, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 182_257);
7019         assert(SysTime(DateTime(501, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 182_622);
7020         assert(SysTime(DateTime(1000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 364_878);
7021         assert(SysTime(DateTime(1001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 365_243);
7022         assert(SysTime(DateTime(1600, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 584_023);
7023         assert(SysTime(DateTime(1601, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 584_389);
7024         assert(SysTime(DateTime(1900, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 693_596);
7025         assert(SysTime(DateTime(1901, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 693_961);
7026         assert(SysTime(DateTime(1945, 11, 12, 12, 2, 9), msecs(212)).dayOfGregorianCal == 710_347);
7027         assert(SysTime(DateTime(1999, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 729_755);
7028         assert(SysTime(DateTime(2000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 730_120);
7029         assert(SysTime(DateTime(2001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 730_486);
7030 
7031         assert(SysTime(DateTime(2010, 1, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_773);
7032         assert(SysTime(DateTime(2010, 1, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_803);
7033         assert(SysTime(DateTime(2010, 2, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_804);
7034         assert(SysTime(DateTime(2010, 2, 28, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_831);
7035         assert(SysTime(DateTime(2010, 3, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_832);
7036         assert(SysTime(DateTime(2010, 3, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_862);
7037         assert(SysTime(DateTime(2010, 4, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_863);
7038         assert(SysTime(DateTime(2010, 4, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_892);
7039         assert(SysTime(DateTime(2010, 5, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_893);
7040         assert(SysTime(DateTime(2010, 5, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_923);
7041         assert(SysTime(DateTime(2010, 6, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_924);
7042         assert(SysTime(DateTime(2010, 6, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_953);
7043         assert(SysTime(DateTime(2010, 7, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_954);
7044         assert(SysTime(DateTime(2010, 7, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_984);
7045         assert(SysTime(DateTime(2010, 8, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_985);
7046         assert(SysTime(DateTime(2010, 8, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_015);
7047         assert(SysTime(DateTime(2010, 9, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_016);
7048         assert(SysTime(DateTime(2010, 9, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_045);
7049         assert(SysTime(DateTime(2010, 10, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_046);
7050         assert(SysTime(DateTime(2010, 10, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_076);
7051         assert(SysTime(DateTime(2010, 11, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_077);
7052         assert(SysTime(DateTime(2010, 11, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_106);
7053         assert(SysTime(DateTime(2010, 12, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_107);
7054         assert(SysTime(DateTime(2010, 12, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_137);
7055 
7056         assert(SysTime(DateTime(2012, 2, 1, 0, 0, 0)).dayOfGregorianCal == 734_534);
7057         assert(SysTime(DateTime(2012, 2, 28, 0, 0, 0)).dayOfGregorianCal == 734_561);
7058         assert(SysTime(DateTime(2012, 2, 29, 0, 0, 0)).dayOfGregorianCal == 734_562);
7059         assert(SysTime(DateTime(2012, 3, 1, 0, 0, 0)).dayOfGregorianCal == 734_563);
7060 
7061         // Test B.C.
7062         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == 0);
7063         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)).dayOfGregorianCal == 0);
7064         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59)).dayOfGregorianCal == 0);
7065         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0), hnsecs(1)).dayOfGregorianCal == 0);
7066         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0)).dayOfGregorianCal == 0);
7067 
7068         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == -366);
7069         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59), hnsecs(9_999_998)).dayOfGregorianCal == -366);
7070         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59)).dayOfGregorianCal == -366);
7071         assert(SysTime(DateTime(-1, 12, 31, 0, 0, 0)).dayOfGregorianCal == -366);
7072 
7073         assert(SysTime(DateTime(0, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == 0);
7074         assert(SysTime(DateTime(0, 12, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1);
7075         assert(SysTime(DateTime(0, 12, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -30);
7076         assert(SysTime(DateTime(0, 11, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -31);
7077 
7078         assert(SysTime(DateTime(-1, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -366);
7079         assert(SysTime(DateTime(-1, 12, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -367);
7080         assert(SysTime(DateTime(-1, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730);
7081         assert(SysTime(DateTime(-2, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -731);
7082         assert(SysTime(DateTime(-2, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1095);
7083         assert(SysTime(DateTime(-3, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1096);
7084         assert(SysTime(DateTime(-3, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1460);
7085         assert(SysTime(DateTime(-4, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1461);
7086         assert(SysTime(DateTime(-4, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1826);
7087         assert(SysTime(DateTime(-5, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1827);
7088         assert(SysTime(DateTime(-5, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -2191);
7089         assert(SysTime(DateTime(-9, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -3652);
7090 
7091         assert(SysTime(DateTime(-49, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -18_262);
7092         assert(SysTime(DateTime(-50, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -18_627);
7093         assert(SysTime(DateTime(-97, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -35_794);
7094         assert(SysTime(DateTime(-99, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_160);
7095         assert(SysTime(DateTime(-99, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_524);
7096         assert(SysTime(DateTime(-100, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_889);
7097         assert(SysTime(DateTime(-101, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -37_254);
7098         assert(SysTime(DateTime(-105, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -38_715);
7099         assert(SysTime(DateTime(-200, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -73_413);
7100         assert(SysTime(DateTime(-201, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -73_778);
7101         assert(SysTime(DateTime(-300, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -109_937);
7102         assert(SysTime(DateTime(-301, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -110_302);
7103         assert(SysTime(DateTime(-400, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_097);
7104         assert(SysTime(DateTime(-400, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_462);
7105         assert(SysTime(DateTime(-401, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_827);
7106         assert(SysTime(DateTime(-499, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -182_621);
7107         assert(SysTime(DateTime(-500, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -182_986);
7108         assert(SysTime(DateTime(-501, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -183_351);
7109         assert(SysTime(DateTime(-1000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -365_607);
7110         assert(SysTime(DateTime(-1001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -365_972);
7111         assert(SysTime(DateTime(-1599, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_387);
7112         assert(SysTime(DateTime(-1600, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_388);
7113         assert(SysTime(DateTime(-1600, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_753);
7114         assert(SysTime(DateTime(-1601, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -585_118);
7115         assert(SysTime(DateTime(-1900, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -694_325);
7116         assert(SysTime(DateTime(-1901, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -694_690);
7117         assert(SysTime(DateTime(-1999, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_484);
7118         assert(SysTime(DateTime(-2000, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_485);
7119         assert(SysTime(DateTime(-2000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_850);
7120         assert(SysTime(DateTime(-2001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -731_215);
7121 
7122         assert(SysTime(DateTime(-2010, 1, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_502);
7123         assert(SysTime(DateTime(-2010, 1, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_472);
7124         assert(SysTime(DateTime(-2010, 2, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_471);
7125         assert(SysTime(DateTime(-2010, 2, 28, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_444);
7126         assert(SysTime(DateTime(-2010, 3, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_443);
7127         assert(SysTime(DateTime(-2010, 3, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_413);
7128         assert(SysTime(DateTime(-2010, 4, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_412);
7129         assert(SysTime(DateTime(-2010, 4, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_383);
7130         assert(SysTime(DateTime(-2010, 5, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_382);
7131         assert(SysTime(DateTime(-2010, 5, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_352);
7132         assert(SysTime(DateTime(-2010, 6, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_351);
7133         assert(SysTime(DateTime(-2010, 6, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_322);
7134         assert(SysTime(DateTime(-2010, 7, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_321);
7135         assert(SysTime(DateTime(-2010, 7, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_291);
7136         assert(SysTime(DateTime(-2010, 8, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_290);
7137         assert(SysTime(DateTime(-2010, 8, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_260);
7138         assert(SysTime(DateTime(-2010, 9, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_259);
7139         assert(SysTime(DateTime(-2010, 9, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_230);
7140         assert(SysTime(DateTime(-2010, 10, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_229);
7141         assert(SysTime(DateTime(-2010, 10, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_199);
7142         assert(SysTime(DateTime(-2010, 11, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_198);
7143         assert(SysTime(DateTime(-2010, 11, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_169);
7144         assert(SysTime(DateTime(-2010, 12, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_168);
7145         assert(SysTime(DateTime(-2010, 12, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_138);
7146 
7147         assert(SysTime(DateTime(-2012, 2, 1, 0, 0, 0)).dayOfGregorianCal == -735_202);
7148         assert(SysTime(DateTime(-2012, 2, 28, 0, 0, 0)).dayOfGregorianCal == -735_175);
7149         assert(SysTime(DateTime(-2012, 2, 29, 0, 0, 0)).dayOfGregorianCal == -735_174);
7150         assert(SysTime(DateTime(-2012, 3, 1, 0, 0, 0)).dayOfGregorianCal == -735_173);
7151 
7152         // Start of Hebrew Calendar
7153         assert(SysTime(DateTime(-3760, 9, 7, 0, 0, 0)).dayOfGregorianCal == -1_373_427);
7154 
7155         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7156         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7157         assert(cst.dayOfGregorianCal == 729_941);
7158         assert(ist.dayOfGregorianCal == 729_941);
7159 
7160         static void testScope(scope ref SysTime st) @safe
7161         {
7162             auto result = st.dayOfGregorianCal;
7163         }
7164     }
7165 
7166 
7167     // Test that the logic for the day of the Gregorian Calendar is consistent
7168     // between Date and SysTime.
7169     @safe unittest
7170     {
7171         import core.time;
7172         void test(Date date, SysTime st, size_t line = __LINE__)
7173         {
7174             if (date.dayOfGregorianCal != st.dayOfGregorianCal)
7175             {
7176                 throw new AssertError(format("Date [%s] SysTime [%s]", date.dayOfGregorianCal, st.dayOfGregorianCal),
7177                                       __FILE__, line);
7178             }
7179         }
7180 
7181         // Test A.D.
7182         test(Date(1, 1, 1), SysTime(DateTime(1, 1, 1, 0, 0, 0)));
7183         test(Date(1, 1, 2), SysTime(DateTime(1, 1, 2, 0, 0, 0), hnsecs(500)));
7184         test(Date(1, 2, 1), SysTime(DateTime(1, 2, 1, 0, 0, 0), hnsecs(50_000)));
7185         test(Date(2, 1, 1), SysTime(DateTime(2, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7186         test(Date(3, 1, 1), SysTime(DateTime(3, 1, 1, 12, 13, 14)));
7187         test(Date(4, 1, 1), SysTime(DateTime(4, 1, 1, 12, 13, 14), hnsecs(500)));
7188         test(Date(5, 1, 1), SysTime(DateTime(5, 1, 1, 12, 13, 14), hnsecs(50_000)));
7189         test(Date(50, 1, 1), SysTime(DateTime(50, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7190         test(Date(97, 1, 1), SysTime(DateTime(97, 1, 1, 23, 59, 59)));
7191         test(Date(100, 1, 1), SysTime(DateTime(100, 1, 1, 23, 59, 59), hnsecs(500)));
7192         test(Date(101, 1, 1), SysTime(DateTime(101, 1, 1, 23, 59, 59), hnsecs(50_000)));
7193         test(Date(105, 1, 1), SysTime(DateTime(105, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7194         test(Date(200, 1, 1), SysTime(DateTime(200, 1, 1, 0, 0, 0)));
7195         test(Date(201, 1, 1), SysTime(DateTime(201, 1, 1, 0, 0, 0), hnsecs(500)));
7196         test(Date(300, 1, 1), SysTime(DateTime(300, 1, 1, 0, 0, 0), hnsecs(50_000)));
7197         test(Date(301, 1, 1), SysTime(DateTime(301, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7198         test(Date(400, 1, 1), SysTime(DateTime(400, 1, 1, 12, 13, 14)));
7199         test(Date(401, 1, 1), SysTime(DateTime(401, 1, 1, 12, 13, 14), hnsecs(500)));
7200         test(Date(500, 1, 1), SysTime(DateTime(500, 1, 1, 12, 13, 14), hnsecs(50_000)));
7201         test(Date(501, 1, 1), SysTime(DateTime(501, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7202         test(Date(1000, 1, 1), SysTime(DateTime(1000, 1, 1, 23, 59, 59)));
7203         test(Date(1001, 1, 1), SysTime(DateTime(1001, 1, 1, 23, 59, 59), hnsecs(500)));
7204         test(Date(1600, 1, 1), SysTime(DateTime(1600, 1, 1, 23, 59, 59), hnsecs(50_000)));
7205         test(Date(1601, 1, 1), SysTime(DateTime(1601, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7206         test(Date(1900, 1, 1), SysTime(DateTime(1900, 1, 1, 0, 0, 0)));
7207         test(Date(1901, 1, 1), SysTime(DateTime(1901, 1, 1, 0, 0, 0), hnsecs(500)));
7208         test(Date(1945, 11, 12), SysTime(DateTime(1945, 11, 12, 0, 0, 0), hnsecs(50_000)));
7209         test(Date(1999, 1, 1), SysTime(DateTime(1999, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7210         test(Date(1999, 7, 6), SysTime(DateTime(1999, 7, 6, 12, 13, 14)));
7211         test(Date(2000, 1, 1), SysTime(DateTime(2000, 1, 1, 12, 13, 14), hnsecs(500)));
7212         test(Date(2001, 1, 1), SysTime(DateTime(2001, 1, 1, 12, 13, 14), hnsecs(50_000)));
7213 
7214         test(Date(2010, 1, 1), SysTime(DateTime(2010, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7215         test(Date(2010, 1, 31), SysTime(DateTime(2010, 1, 31, 23, 0, 0)));
7216         test(Date(2010, 2, 1), SysTime(DateTime(2010, 2, 1, 23, 59, 59), hnsecs(500)));
7217         test(Date(2010, 2, 28), SysTime(DateTime(2010, 2, 28, 23, 59, 59), hnsecs(50_000)));
7218         test(Date(2010, 3, 1), SysTime(DateTime(2010, 3, 1, 23, 59, 59), hnsecs(9_999_999)));
7219         test(Date(2010, 3, 31), SysTime(DateTime(2010, 3, 31, 0, 0, 0)));
7220         test(Date(2010, 4, 1), SysTime(DateTime(2010, 4, 1, 0, 0, 0), hnsecs(500)));
7221         test(Date(2010, 4, 30), SysTime(DateTime(2010, 4, 30, 0, 0, 0), hnsecs(50_000)));
7222         test(Date(2010, 5, 1), SysTime(DateTime(2010, 5, 1, 0, 0, 0), hnsecs(9_999_999)));
7223         test(Date(2010, 5, 31), SysTime(DateTime(2010, 5, 31, 12, 13, 14)));
7224         test(Date(2010, 6, 1), SysTime(DateTime(2010, 6, 1, 12, 13, 14), hnsecs(500)));
7225         test(Date(2010, 6, 30), SysTime(DateTime(2010, 6, 30, 12, 13, 14), hnsecs(50_000)));
7226         test(Date(2010, 7, 1), SysTime(DateTime(2010, 7, 1, 12, 13, 14), hnsecs(9_999_999)));
7227         test(Date(2010, 7, 31), SysTime(DateTime(2010, 7, 31, 23, 59, 59)));
7228         test(Date(2010, 8, 1), SysTime(DateTime(2010, 8, 1, 23, 59, 59), hnsecs(500)));
7229         test(Date(2010, 8, 31), SysTime(DateTime(2010, 8, 31, 23, 59, 59), hnsecs(50_000)));
7230         test(Date(2010, 9, 1), SysTime(DateTime(2010, 9, 1, 23, 59, 59), hnsecs(9_999_999)));
7231         test(Date(2010, 9, 30), SysTime(DateTime(2010, 9, 30, 12, 0, 0)));
7232         test(Date(2010, 10, 1), SysTime(DateTime(2010, 10, 1, 0, 12, 0), hnsecs(500)));
7233         test(Date(2010, 10, 31), SysTime(DateTime(2010, 10, 31, 0, 0, 12), hnsecs(50_000)));
7234         test(Date(2010, 11, 1), SysTime(DateTime(2010, 11, 1, 23, 0, 0), hnsecs(9_999_999)));
7235         test(Date(2010, 11, 30), SysTime(DateTime(2010, 11, 30, 0, 59, 0)));
7236         test(Date(2010, 12, 1), SysTime(DateTime(2010, 12, 1, 0, 0, 59), hnsecs(500)));
7237         test(Date(2010, 12, 31), SysTime(DateTime(2010, 12, 31, 0, 59, 59), hnsecs(50_000)));
7238 
7239         test(Date(2012, 2, 1), SysTime(DateTime(2012, 2, 1, 23, 0, 59), hnsecs(9_999_999)));
7240         test(Date(2012, 2, 28), SysTime(DateTime(2012, 2, 28, 23, 59, 0)));
7241         test(Date(2012, 2, 29), SysTime(DateTime(2012, 2, 29, 7, 7, 7), hnsecs(7)));
7242         test(Date(2012, 3, 1), SysTime(DateTime(2012, 3, 1, 7, 7, 7), hnsecs(7)));
7243 
7244         // Test B.C.
7245         test(Date(0, 12, 31), SysTime(DateTime(0, 12, 31, 0, 0, 0)));
7246         test(Date(0, 12, 30), SysTime(DateTime(0, 12, 30, 0, 0, 0), hnsecs(500)));
7247         test(Date(0, 12, 1), SysTime(DateTime(0, 12, 1, 0, 0, 0), hnsecs(50_000)));
7248         test(Date(0, 11, 30), SysTime(DateTime(0, 11, 30, 0, 0, 0), hnsecs(9_999_999)));
7249 
7250         test(Date(-1, 12, 31), SysTime(DateTime(-1, 12, 31, 12, 13, 14)));
7251         test(Date(-1, 12, 30), SysTime(DateTime(-1, 12, 30, 12, 13, 14), hnsecs(500)));
7252         test(Date(-1, 1, 1), SysTime(DateTime(-1, 1, 1, 12, 13, 14), hnsecs(50_000)));
7253         test(Date(-2, 12, 31), SysTime(DateTime(-2, 12, 31, 12, 13, 14), hnsecs(9_999_999)));
7254         test(Date(-2, 1, 1), SysTime(DateTime(-2, 1, 1, 23, 59, 59)));
7255         test(Date(-3, 12, 31), SysTime(DateTime(-3, 12, 31, 23, 59, 59), hnsecs(500)));
7256         test(Date(-3, 1, 1), SysTime(DateTime(-3, 1, 1, 23, 59, 59), hnsecs(50_000)));
7257         test(Date(-4, 12, 31), SysTime(DateTime(-4, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7258         test(Date(-4, 1, 1), SysTime(DateTime(-4, 1, 1, 0, 0, 0)));
7259         test(Date(-5, 12, 31), SysTime(DateTime(-5, 12, 31, 0, 0, 0), hnsecs(500)));
7260         test(Date(-5, 1, 1), SysTime(DateTime(-5, 1, 1, 0, 0, 0), hnsecs(50_000)));
7261         test(Date(-9, 1, 1), SysTime(DateTime(-9, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7262 
7263         test(Date(-49, 1, 1), SysTime(DateTime(-49, 1, 1, 12, 13, 14)));
7264         test(Date(-50, 1, 1), SysTime(DateTime(-50, 1, 1, 12, 13, 14), hnsecs(500)));
7265         test(Date(-97, 1, 1), SysTime(DateTime(-97, 1, 1, 12, 13, 14), hnsecs(50_000)));
7266         test(Date(-99, 12, 31), SysTime(DateTime(-99, 12, 31, 12, 13, 14), hnsecs(9_999_999)));
7267         test(Date(-99, 1, 1), SysTime(DateTime(-99, 1, 1, 23, 59, 59)));
7268         test(Date(-100, 1, 1), SysTime(DateTime(-100, 1, 1, 23, 59, 59), hnsecs(500)));
7269         test(Date(-101, 1, 1), SysTime(DateTime(-101, 1, 1, 23, 59, 59), hnsecs(50_000)));
7270         test(Date(-105, 1, 1), SysTime(DateTime(-105, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7271         test(Date(-200, 1, 1), SysTime(DateTime(-200, 1, 1, 0, 0, 0)));
7272         test(Date(-201, 1, 1), SysTime(DateTime(-201, 1, 1, 0, 0, 0), hnsecs(500)));
7273         test(Date(-300, 1, 1), SysTime(DateTime(-300, 1, 1, 0, 0, 0), hnsecs(50_000)));
7274         test(Date(-301, 1, 1), SysTime(DateTime(-301, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7275         test(Date(-400, 12, 31), SysTime(DateTime(-400, 12, 31, 12, 13, 14)));
7276         test(Date(-400, 1, 1), SysTime(DateTime(-400, 1, 1, 12, 13, 14), hnsecs(500)));
7277         test(Date(-401, 1, 1), SysTime(DateTime(-401, 1, 1, 12, 13, 14), hnsecs(50_000)));
7278         test(Date(-499, 1, 1), SysTime(DateTime(-499, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7279         test(Date(-500, 1, 1), SysTime(DateTime(-500, 1, 1, 23, 59, 59)));
7280         test(Date(-501, 1, 1), SysTime(DateTime(-501, 1, 1, 23, 59, 59), hnsecs(500)));
7281         test(Date(-1000, 1, 1), SysTime(DateTime(-1000, 1, 1, 23, 59, 59), hnsecs(50_000)));
7282         test(Date(-1001, 1, 1), SysTime(DateTime(-1001, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7283         test(Date(-1599, 1, 1), SysTime(DateTime(-1599, 1, 1, 0, 0, 0)));
7284         test(Date(-1600, 12, 31), SysTime(DateTime(-1600, 12, 31, 0, 0, 0), hnsecs(500)));
7285         test(Date(-1600, 1, 1), SysTime(DateTime(-1600, 1, 1, 0, 0, 0), hnsecs(50_000)));
7286         test(Date(-1601, 1, 1), SysTime(DateTime(-1601, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7287         test(Date(-1900, 1, 1), SysTime(DateTime(-1900, 1, 1, 12, 13, 14)));
7288         test(Date(-1901, 1, 1), SysTime(DateTime(-1901, 1, 1, 12, 13, 14), hnsecs(500)));
7289         test(Date(-1999, 1, 1), SysTime(DateTime(-1999, 1, 1, 12, 13, 14), hnsecs(50_000)));
7290         test(Date(-1999, 7, 6), SysTime(DateTime(-1999, 7, 6, 12, 13, 14), hnsecs(9_999_999)));
7291         test(Date(-2000, 12, 31), SysTime(DateTime(-2000, 12, 31, 23, 59, 59)));
7292         test(Date(-2000, 1, 1), SysTime(DateTime(-2000, 1, 1, 23, 59, 59), hnsecs(500)));
7293         test(Date(-2001, 1, 1), SysTime(DateTime(-2001, 1, 1, 23, 59, 59), hnsecs(50_000)));
7294 
7295         test(Date(-2010, 1, 1), SysTime(DateTime(-2010, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7296         test(Date(-2010, 1, 31), SysTime(DateTime(-2010, 1, 31, 0, 0, 0)));
7297         test(Date(-2010, 2, 1), SysTime(DateTime(-2010, 2, 1, 0, 0, 0), hnsecs(500)));
7298         test(Date(-2010, 2, 28), SysTime(DateTime(-2010, 2, 28, 0, 0, 0), hnsecs(50_000)));
7299         test(Date(-2010, 3, 1), SysTime(DateTime(-2010, 3, 1, 0, 0, 0), hnsecs(9_999_999)));
7300         test(Date(-2010, 3, 31), SysTime(DateTime(-2010, 3, 31, 12, 13, 14)));
7301         test(Date(-2010, 4, 1), SysTime(DateTime(-2010, 4, 1, 12, 13, 14), hnsecs(500)));
7302         test(Date(-2010, 4, 30), SysTime(DateTime(-2010, 4, 30, 12, 13, 14), hnsecs(50_000)));
7303         test(Date(-2010, 5, 1), SysTime(DateTime(-2010, 5, 1, 12, 13, 14), hnsecs(9_999_999)));
7304         test(Date(-2010, 5, 31), SysTime(DateTime(-2010, 5, 31, 23, 59, 59)));
7305         test(Date(-2010, 6, 1), SysTime(DateTime(-2010, 6, 1, 23, 59, 59), hnsecs(500)));
7306         test(Date(-2010, 6, 30), SysTime(DateTime(-2010, 6, 30, 23, 59, 59), hnsecs(50_000)));
7307         test(Date(-2010, 7, 1), SysTime(DateTime(-2010, 7, 1, 23, 59, 59), hnsecs(9_999_999)));
7308         test(Date(-2010, 7, 31), SysTime(DateTime(-2010, 7, 31, 0, 0, 0)));
7309         test(Date(-2010, 8, 1), SysTime(DateTime(-2010, 8, 1, 0, 0, 0), hnsecs(500)));
7310         test(Date(-2010, 8, 31), SysTime(DateTime(-2010, 8, 31, 0, 0, 0), hnsecs(50_000)));
7311         test(Date(-2010, 9, 1), SysTime(DateTime(-2010, 9, 1, 0, 0, 0), hnsecs(9_999_999)));
7312         test(Date(-2010, 9, 30), SysTime(DateTime(-2010, 9, 30, 12, 0, 0)));
7313         test(Date(-2010, 10, 1), SysTime(DateTime(-2010, 10, 1, 0, 12, 0), hnsecs(500)));
7314         test(Date(-2010, 10, 31), SysTime(DateTime(-2010, 10, 31, 0, 0, 12), hnsecs(50_000)));
7315         test(Date(-2010, 11, 1), SysTime(DateTime(-2010, 11, 1, 23, 0, 0), hnsecs(9_999_999)));
7316         test(Date(-2010, 11, 30), SysTime(DateTime(-2010, 11, 30, 0, 59, 0)));
7317         test(Date(-2010, 12, 1), SysTime(DateTime(-2010, 12, 1, 0, 0, 59), hnsecs(500)));
7318         test(Date(-2010, 12, 31), SysTime(DateTime(-2010, 12, 31, 0, 59, 59), hnsecs(50_000)));
7319 
7320         test(Date(-2012, 2, 1), SysTime(DateTime(-2012, 2, 1, 23, 0, 59), hnsecs(9_999_999)));
7321         test(Date(-2012, 2, 28), SysTime(DateTime(-2012, 2, 28, 23, 59, 0)));
7322         test(Date(-2012, 2, 29), SysTime(DateTime(-2012, 2, 29, 7, 7, 7), hnsecs(7)));
7323         test(Date(-2012, 3, 1), SysTime(DateTime(-2012, 3, 1, 7, 7, 7), hnsecs(7)));
7324 
7325         test(Date(-3760, 9, 7), SysTime(DateTime(-3760, 9, 7, 0, 0, 0)));
7326     }
7327 
7328 
7329     /++
7330         The Xth day of the Gregorian Calendar that this $(LREF SysTime) is on.
7331         Setting this property does not affect the time portion of $(LREF SysTime).
7332 
7333         Params:
7334             days = The day of the Gregorian Calendar to set this $(LREF SysTime)
7335                    to.
7336      +/
7337     @property void dayOfGregorianCal(int days) @safe nothrow scope
7338     {
7339         auto hnsecs = adjTime;
7340         hnsecs = removeUnitsFromHNSecs!"days"(hnsecs);
7341 
7342         if (hnsecs < 0)
7343             hnsecs += convert!("hours", "hnsecs")(24);
7344 
7345         if (--days < 0)
7346         {
7347             hnsecs -= convert!("hours", "hnsecs")(24);
7348             ++days;
7349         }
7350 
7351         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
7352 
7353         adjTime = newDaysHNSecs + hnsecs;
7354     }
7355 
7356     ///
7357     @safe unittest
7358     {
7359         import core.time;
7360         import std.datetime.date : DateTime;
7361 
7362         auto st = SysTime(DateTime(0, 1, 1, 12, 0, 0));
7363         st.dayOfGregorianCal = 1;
7364         assert(st == SysTime(DateTime(1, 1, 1, 12, 0, 0)));
7365 
7366         st.dayOfGregorianCal = 365;
7367         assert(st == SysTime(DateTime(1, 12, 31, 12, 0, 0)));
7368 
7369         st.dayOfGregorianCal = 366;
7370         assert(st == SysTime(DateTime(2, 1, 1, 12, 0, 0)));
7371 
7372         st.dayOfGregorianCal = 0;
7373         assert(st == SysTime(DateTime(0, 12, 31, 12, 0, 0)));
7374 
7375         st.dayOfGregorianCal = -365;
7376         assert(st == SysTime(DateTime(-0, 1, 1, 12, 0, 0)));
7377 
7378         st.dayOfGregorianCal = -366;
7379         assert(st == SysTime(DateTime(-1, 12, 31, 12, 0, 0)));
7380 
7381         st.dayOfGregorianCal = 730_120;
7382         assert(st == SysTime(DateTime(2000, 1, 1, 12, 0, 0)));
7383 
7384         st.dayOfGregorianCal = 734_137;
7385         assert(st == SysTime(DateTime(2010, 12, 31, 12, 0, 0)));
7386     }
7387 
7388     @safe unittest
7389     {
7390         import core.time;
7391         void testST(SysTime orig, int day, SysTime expected, size_t line = __LINE__) @safe
7392         {
7393             orig.dayOfGregorianCal = day;
7394             if (orig != expected)
7395                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
7396         }
7397 
7398         // Test A.D.
7399         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
7400         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
7401         testST(SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)), 1,
7402                SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7403 
7404         // Test B.C.
7405         testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0)));
7406         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)), 0,
7407                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7408         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(1)), 0,
7409                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1)));
7410         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
7411 
7412         // Test Both.
7413         testST(SysTime(DateTime(-512, 7, 20, 0, 0, 0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
7414         testST(SysTime(DateTime(-513, 6, 6, 0, 0, 0), hnsecs(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
7415         testST(SysTime(DateTime(-511, 5, 7, 23, 59, 59), hnsecs(9_999_999)), 1,
7416                SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7417 
7418         testST(SysTime(DateTime(1607, 4, 8, 0, 0, 0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0)));
7419         testST(SysTime(DateTime(1500, 3, 9, 23, 59, 59), hnsecs(9_999_999)), 0,
7420                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7421         testST(SysTime(DateTime(999, 2, 10, 23, 59, 59), hnsecs(1)), 0,
7422                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1)));
7423         testST(SysTime(DateTime(2007, 12, 11, 23, 59, 59)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
7424 
7425 
7426         auto st = SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212));
7427 
7428         void testST2(int day, SysTime expected, size_t line = __LINE__) @safe
7429         {
7430             st.dayOfGregorianCal = day;
7431             if (st != expected)
7432                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", st, expected), __FILE__, line);
7433         }
7434 
7435         // Test A.D.
7436         testST2(1, SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212)));
7437         testST2(2, SysTime(DateTime(1, 1, 2, 12, 2, 9), msecs(212)));
7438         testST2(32, SysTime(DateTime(1, 2, 1, 12, 2, 9), msecs(212)));
7439         testST2(366, SysTime(DateTime(2, 1, 1, 12, 2, 9), msecs(212)));
7440         testST2(731, SysTime(DateTime(3, 1, 1, 12, 2, 9), msecs(212)));
7441         testST2(1096, SysTime(DateTime(4, 1, 1, 12, 2, 9), msecs(212)));
7442         testST2(1462, SysTime(DateTime(5, 1, 1, 12, 2, 9), msecs(212)));
7443         testST2(17_898, SysTime(DateTime(50, 1, 1, 12, 2, 9), msecs(212)));
7444         testST2(35_065, SysTime(DateTime(97, 1, 1, 12, 2, 9), msecs(212)));
7445         testST2(36_160, SysTime(DateTime(100, 1, 1, 12, 2, 9), msecs(212)));
7446         testST2(36_525, SysTime(DateTime(101, 1, 1, 12, 2, 9), msecs(212)));
7447         testST2(37_986, SysTime(DateTime(105, 1, 1, 12, 2, 9), msecs(212)));
7448         testST2(72_684, SysTime(DateTime(200, 1, 1, 12, 2, 9), msecs(212)));
7449         testST2(73_049, SysTime(DateTime(201, 1, 1, 12, 2, 9), msecs(212)));
7450         testST2(109_208, SysTime(DateTime(300, 1, 1, 12, 2, 9), msecs(212)));
7451         testST2(109_573, SysTime(DateTime(301, 1, 1, 12, 2, 9), msecs(212)));
7452         testST2(145_732, SysTime(DateTime(400, 1, 1, 12, 2, 9), msecs(212)));
7453         testST2(146_098, SysTime(DateTime(401, 1, 1, 12, 2, 9), msecs(212)));
7454         testST2(182_257, SysTime(DateTime(500, 1, 1, 12, 2, 9), msecs(212)));
7455         testST2(182_622, SysTime(DateTime(501, 1, 1, 12, 2, 9), msecs(212)));
7456         testST2(364_878, SysTime(DateTime(1000, 1, 1, 12, 2, 9), msecs(212)));
7457         testST2(365_243, SysTime(DateTime(1001, 1, 1, 12, 2, 9), msecs(212)));
7458         testST2(584_023, SysTime(DateTime(1600, 1, 1, 12, 2, 9), msecs(212)));
7459         testST2(584_389, SysTime(DateTime(1601, 1, 1, 12, 2, 9), msecs(212)));
7460         testST2(693_596, SysTime(DateTime(1900, 1, 1, 12, 2, 9), msecs(212)));
7461         testST2(693_961, SysTime(DateTime(1901, 1, 1, 12, 2, 9), msecs(212)));
7462         testST2(729_755, SysTime(DateTime(1999, 1, 1, 12, 2, 9), msecs(212)));
7463         testST2(730_120, SysTime(DateTime(2000, 1, 1, 12, 2, 9), msecs(212)));
7464         testST2(730_486, SysTime(DateTime(2001, 1, 1, 12, 2, 9), msecs(212)));
7465 
7466         testST2(733_773, SysTime(DateTime(2010, 1, 1, 12, 2, 9), msecs(212)));
7467         testST2(733_803, SysTime(DateTime(2010, 1, 31, 12, 2, 9), msecs(212)));
7468         testST2(733_804, SysTime(DateTime(2010, 2, 1, 12, 2, 9), msecs(212)));
7469         testST2(733_831, SysTime(DateTime(2010, 2, 28, 12, 2, 9), msecs(212)));
7470         testST2(733_832, SysTime(DateTime(2010, 3, 1, 12, 2, 9), msecs(212)));
7471         testST2(733_862, SysTime(DateTime(2010, 3, 31, 12, 2, 9), msecs(212)));
7472         testST2(733_863, SysTime(DateTime(2010, 4, 1, 12, 2, 9), msecs(212)));
7473         testST2(733_892, SysTime(DateTime(2010, 4, 30, 12, 2, 9), msecs(212)));
7474         testST2(733_893, SysTime(DateTime(2010, 5, 1, 12, 2, 9), msecs(212)));
7475         testST2(733_923, SysTime(DateTime(2010, 5, 31, 12, 2, 9), msecs(212)));
7476         testST2(733_924, SysTime(DateTime(2010, 6, 1, 12, 2, 9), msecs(212)));
7477         testST2(733_953, SysTime(DateTime(2010, 6, 30, 12, 2, 9), msecs(212)));
7478         testST2(733_954, SysTime(DateTime(2010, 7, 1, 12, 2, 9), msecs(212)));
7479         testST2(733_984, SysTime(DateTime(2010, 7, 31, 12, 2, 9), msecs(212)));
7480         testST2(733_985, SysTime(DateTime(2010, 8, 1, 12, 2, 9), msecs(212)));
7481         testST2(734_015, SysTime(DateTime(2010, 8, 31, 12, 2, 9), msecs(212)));
7482         testST2(734_016, SysTime(DateTime(2010, 9, 1, 12, 2, 9), msecs(212)));
7483         testST2(734_045, SysTime(DateTime(2010, 9, 30, 12, 2, 9), msecs(212)));
7484         testST2(734_046, SysTime(DateTime(2010, 10, 1, 12, 2, 9), msecs(212)));
7485         testST2(734_076, SysTime(DateTime(2010, 10, 31, 12, 2, 9), msecs(212)));
7486         testST2(734_077, SysTime(DateTime(2010, 11, 1, 12, 2, 9), msecs(212)));
7487         testST2(734_106, SysTime(DateTime(2010, 11, 30, 12, 2, 9), msecs(212)));
7488         testST2(734_107, SysTime(DateTime(2010, 12, 1, 12, 2, 9), msecs(212)));
7489         testST2(734_137, SysTime(DateTime(2010, 12, 31, 12, 2, 9), msecs(212)));
7490 
7491         testST2(734_534, SysTime(DateTime(2012, 2, 1, 12, 2, 9), msecs(212)));
7492         testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), msecs(212)));
7493         testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), msecs(212)));
7494         testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), msecs(212)));
7495 
7496         testST2(734_534,  SysTime(DateTime(2012, 2, 1, 12, 2, 9), msecs(212)));
7497 
7498         testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), msecs(212)));
7499         testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), msecs(212)));
7500         testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), msecs(212)));
7501 
7502         // Test B.C.
7503         testST2(0, SysTime(DateTime(0, 12, 31, 12, 2, 9), msecs(212)));
7504         testST2(-1, SysTime(DateTime(0, 12, 30, 12, 2, 9), msecs(212)));
7505         testST2(-30, SysTime(DateTime(0, 12, 1, 12, 2, 9), msecs(212)));
7506         testST2(-31, SysTime(DateTime(0, 11, 30, 12, 2, 9), msecs(212)));
7507 
7508         testST2(-366, SysTime(DateTime(-1, 12, 31, 12, 2, 9), msecs(212)));
7509         testST2(-367, SysTime(DateTime(-1, 12, 30, 12, 2, 9), msecs(212)));
7510         testST2(-730, SysTime(DateTime(-1, 1, 1, 12, 2, 9), msecs(212)));
7511         testST2(-731, SysTime(DateTime(-2, 12, 31, 12, 2, 9), msecs(212)));
7512         testST2(-1095, SysTime(DateTime(-2, 1, 1, 12, 2, 9), msecs(212)));
7513         testST2(-1096, SysTime(DateTime(-3, 12, 31, 12, 2, 9), msecs(212)));
7514         testST2(-1460, SysTime(DateTime(-3, 1, 1, 12, 2, 9), msecs(212)));
7515         testST2(-1461, SysTime(DateTime(-4, 12, 31, 12, 2, 9), msecs(212)));
7516         testST2(-1826, SysTime(DateTime(-4, 1, 1, 12, 2, 9), msecs(212)));
7517         testST2(-1827, SysTime(DateTime(-5, 12, 31, 12, 2, 9), msecs(212)));
7518         testST2(-2191, SysTime(DateTime(-5, 1, 1, 12, 2, 9), msecs(212)));
7519         testST2(-3652, SysTime(DateTime(-9, 1, 1, 12, 2, 9), msecs(212)));
7520 
7521         testST2(-18_262, SysTime(DateTime(-49, 1, 1, 12, 2, 9), msecs(212)));
7522         testST2(-18_627, SysTime(DateTime(-50, 1, 1, 12, 2, 9), msecs(212)));
7523         testST2(-35_794, SysTime(DateTime(-97, 1, 1, 12, 2, 9), msecs(212)));
7524         testST2(-36_160, SysTime(DateTime(-99, 12, 31, 12, 2, 9), msecs(212)));
7525         testST2(-36_524, SysTime(DateTime(-99, 1, 1, 12, 2, 9), msecs(212)));
7526         testST2(-36_889, SysTime(DateTime(-100, 1, 1, 12, 2, 9), msecs(212)));
7527         testST2(-37_254, SysTime(DateTime(-101, 1, 1, 12, 2, 9), msecs(212)));
7528         testST2(-38_715, SysTime(DateTime(-105, 1, 1, 12, 2, 9), msecs(212)));
7529         testST2(-73_413, SysTime(DateTime(-200, 1, 1, 12, 2, 9), msecs(212)));
7530         testST2(-73_778, SysTime(DateTime(-201, 1, 1, 12, 2, 9), msecs(212)));
7531         testST2(-109_937, SysTime(DateTime(-300, 1, 1, 12, 2, 9), msecs(212)));
7532         testST2(-110_302, SysTime(DateTime(-301, 1, 1, 12, 2, 9), msecs(212)));
7533         testST2(-146_097, SysTime(DateTime(-400, 12, 31, 12, 2, 9), msecs(212)));
7534         testST2(-146_462, SysTime(DateTime(-400, 1, 1, 12, 2, 9), msecs(212)));
7535         testST2(-146_827, SysTime(DateTime(-401, 1, 1, 12, 2, 9), msecs(212)));
7536         testST2(-182_621, SysTime(DateTime(-499, 1, 1, 12, 2, 9), msecs(212)));
7537         testST2(-182_986, SysTime(DateTime(-500, 1, 1, 12, 2, 9), msecs(212)));
7538         testST2(-183_351, SysTime(DateTime(-501, 1, 1, 12, 2, 9), msecs(212)));
7539         testST2(-365_607, SysTime(DateTime(-1000, 1, 1, 12, 2, 9), msecs(212)));
7540         testST2(-365_972, SysTime(DateTime(-1001, 1, 1, 12, 2, 9), msecs(212)));
7541         testST2(-584_387, SysTime(DateTime(-1599, 1, 1, 12, 2, 9), msecs(212)));
7542         testST2(-584_388, SysTime(DateTime(-1600, 12, 31, 12, 2, 9), msecs(212)));
7543         testST2(-584_753, SysTime(DateTime(-1600, 1, 1, 12, 2, 9), msecs(212)));
7544         testST2(-585_118, SysTime(DateTime(-1601, 1, 1, 12, 2, 9), msecs(212)));
7545         testST2(-694_325, SysTime(DateTime(-1900, 1, 1, 12, 2, 9), msecs(212)));
7546         testST2(-694_690, SysTime(DateTime(-1901, 1, 1, 12, 2, 9), msecs(212)));
7547         testST2(-730_484, SysTime(DateTime(-1999, 1, 1, 12, 2, 9), msecs(212)));
7548         testST2(-730_485, SysTime(DateTime(-2000, 12, 31, 12, 2, 9), msecs(212)));
7549         testST2(-730_850, SysTime(DateTime(-2000, 1, 1, 12, 2, 9), msecs(212)));
7550         testST2(-731_215, SysTime(DateTime(-2001, 1, 1, 12, 2, 9), msecs(212)));
7551 
7552         testST2(-734_502, SysTime(DateTime(-2010, 1, 1, 12, 2, 9), msecs(212)));
7553         testST2(-734_472, SysTime(DateTime(-2010, 1, 31, 12, 2, 9), msecs(212)));
7554         testST2(-734_471, SysTime(DateTime(-2010, 2, 1, 12, 2, 9), msecs(212)));
7555         testST2(-734_444, SysTime(DateTime(-2010, 2, 28, 12, 2, 9), msecs(212)));
7556         testST2(-734_443, SysTime(DateTime(-2010, 3, 1, 12, 2, 9), msecs(212)));
7557         testST2(-734_413, SysTime(DateTime(-2010, 3, 31, 12, 2, 9), msecs(212)));
7558         testST2(-734_412, SysTime(DateTime(-2010, 4, 1, 12, 2, 9), msecs(212)));
7559         testST2(-734_383, SysTime(DateTime(-2010, 4, 30, 12, 2, 9), msecs(212)));
7560         testST2(-734_382, SysTime(DateTime(-2010, 5, 1, 12, 2, 9), msecs(212)));
7561         testST2(-734_352, SysTime(DateTime(-2010, 5, 31, 12, 2, 9), msecs(212)));
7562         testST2(-734_351, SysTime(DateTime(-2010, 6, 1, 12, 2, 9), msecs(212)));
7563         testST2(-734_322, SysTime(DateTime(-2010, 6, 30, 12, 2, 9), msecs(212)));
7564         testST2(-734_321, SysTime(DateTime(-2010, 7, 1, 12, 2, 9), msecs(212)));
7565         testST2(-734_291, SysTime(DateTime(-2010, 7, 31, 12, 2, 9), msecs(212)));
7566         testST2(-734_290, SysTime(DateTime(-2010, 8, 1, 12, 2, 9), msecs(212)));
7567         testST2(-734_260, SysTime(DateTime(-2010, 8, 31, 12, 2, 9), msecs(212)));
7568         testST2(-734_259, SysTime(DateTime(-2010, 9, 1, 12, 2, 9), msecs(212)));
7569         testST2(-734_230, SysTime(DateTime(-2010, 9, 30, 12, 2, 9), msecs(212)));
7570         testST2(-734_229, SysTime(DateTime(-2010, 10, 1, 12, 2, 9), msecs(212)));
7571         testST2(-734_199, SysTime(DateTime(-2010, 10, 31, 12, 2, 9), msecs(212)));
7572         testST2(-734_198, SysTime(DateTime(-2010, 11, 1, 12, 2, 9), msecs(212)));
7573         testST2(-734_169, SysTime(DateTime(-2010, 11, 30, 12, 2, 9), msecs(212)));
7574         testST2(-734_168, SysTime(DateTime(-2010, 12, 1, 12, 2, 9), msecs(212)));
7575         testST2(-734_138, SysTime(DateTime(-2010, 12, 31, 12, 2, 9), msecs(212)));
7576 
7577         testST2(-735_202, SysTime(DateTime(-2012, 2, 1, 12, 2, 9), msecs(212)));
7578         testST2(-735_175, SysTime(DateTime(-2012, 2, 28, 12, 2, 9), msecs(212)));
7579         testST2(-735_174, SysTime(DateTime(-2012, 2, 29, 12, 2, 9), msecs(212)));
7580         testST2(-735_173, SysTime(DateTime(-2012, 3, 1, 12, 2, 9), msecs(212)));
7581 
7582         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7583         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7584         static assert(!__traits(compiles, cst.dayOfGregorianCal = 7));
7585         static assert(!__traits(compiles, ist.dayOfGregorianCal = 7));
7586 
7587         static void testScope(scope ref SysTime st) @safe
7588         {
7589             st.dayOfGregorianCal = 42;
7590         }
7591     }
7592 
7593 
7594     /++
7595         The ISO 8601 week of the year that this $(LREF SysTime) is in.
7596 
7597         See_Also:
7598             $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date).
7599       +/
7600     @property ubyte isoWeek() @safe const nothrow scope
7601     {
7602         return (cast(Date) this).isoWeek;
7603     }
7604 
7605     ///
7606     @safe unittest
7607     {
7608         import core.time;
7609         import std.datetime.date : Date;
7610 
7611         auto st = SysTime(Date(1999, 7, 6));
7612         const cst = SysTime(Date(2010, 5, 1));
7613         immutable ist = SysTime(Date(2015, 10, 10));
7614 
7615         assert(st.isoWeek == 27);
7616         assert(cst.isoWeek == 17);
7617         assert(ist.isoWeek == 41);
7618     }
7619 
7620     @safe unittest
7621     {
7622         static void testScope(scope ref SysTime st) @safe
7623         {
7624             auto result = st.isoWeek;
7625         }
7626     }
7627 
7628 
7629     /++
7630         $(LREF SysTime) for the last day in the month that this Date is in.
7631         The time portion of endOfMonth is always 23:59:59.9999999.
7632       +/
7633     @property SysTime endOfMonth() @safe const nothrow scope
7634     {
7635         immutable hnsecs = adjTime;
7636         immutable days = getUnitsFromHNSecs!"days"(hnsecs);
7637 
7638         auto date = Date(cast(int) days + 1).endOfMonth;
7639         auto newDays = date.dayOfGregorianCal - 1;
7640         long theTimeHNSecs;
7641 
7642         if (newDays < 0)
7643         {
7644             theTimeHNSecs = -1;
7645             ++newDays;
7646         }
7647         else
7648             theTimeHNSecs = convert!("days", "hnsecs")(1) - 1;
7649 
7650         immutable newDaysHNSecs = convert!("days", "hnsecs")(newDays);
7651 
7652         auto retval = SysTime(this._stdTime, this._timezone);
7653         retval.adjTime = newDaysHNSecs + theTimeHNSecs;
7654 
7655         return retval;
7656     }
7657 
7658     ///
7659     @safe unittest
7660     {
7661         import core.time : msecs, usecs, hnsecs;
7662         import std.datetime.date : DateTime;
7663 
7664         assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).endOfMonth ==
7665                SysTime(DateTime(1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7666 
7667         assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0), msecs(24)).endOfMonth ==
7668                SysTime(DateTime(1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7669 
7670         assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27), usecs(5203)).endOfMonth ==
7671                SysTime(DateTime(2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7672 
7673         assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9), hnsecs(12345)).endOfMonth ==
7674                SysTime(DateTime(2000, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7675     }
7676 
7677     @safe unittest
7678     {
7679         import core.time;
7680         // Test A.D.
7681         assert(SysTime(Date(1999, 1, 1)).endOfMonth == SysTime(DateTime(1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7682         assert(SysTime(Date(1999, 2, 1)).endOfMonth == SysTime(DateTime(1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7683         assert(SysTime(Date(2000, 2, 1)).endOfMonth == SysTime(DateTime(2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7684         assert(SysTime(Date(1999, 3, 1)).endOfMonth == SysTime(DateTime(1999, 3, 31, 23, 59, 59), hnsecs(9_999_999)));
7685         assert(SysTime(Date(1999, 4, 1)).endOfMonth == SysTime(DateTime(1999, 4, 30, 23, 59, 59), hnsecs(9_999_999)));
7686         assert(SysTime(Date(1999, 5, 1)).endOfMonth == SysTime(DateTime(1999, 5, 31, 23, 59, 59), hnsecs(9_999_999)));
7687         assert(SysTime(Date(1999, 6, 1)).endOfMonth == SysTime(DateTime(1999, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7688         assert(SysTime(Date(1999, 7, 1)).endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7689         assert(SysTime(Date(1999, 8, 1)).endOfMonth == SysTime(DateTime(1999, 8, 31, 23, 59, 59), hnsecs(9_999_999)));
7690         assert(SysTime(Date(1999, 9, 1)).endOfMonth == SysTime(DateTime(1999, 9, 30, 23, 59, 59), hnsecs(9_999_999)));
7691         assert(SysTime(Date(1999, 10, 1)).endOfMonth == SysTime(DateTime(1999, 10, 31, 23, 59, 59), hnsecs(9_999_999)));
7692         assert(SysTime(Date(1999, 11, 1)).endOfMonth == SysTime(DateTime(1999, 11, 30, 23, 59, 59), hnsecs(9_999_999)));
7693         assert(SysTime(Date(1999, 12, 1)).endOfMonth == SysTime(DateTime(1999, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7694 
7695         // Test B.C.
7696         assert(SysTime(Date(-1999, 1, 1)).endOfMonth == SysTime(DateTime(-1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7697         assert(SysTime(Date(-1999, 2, 1)).endOfMonth == SysTime(DateTime(-1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7698         assert(SysTime(Date(-2000, 2, 1)).endOfMonth == SysTime(DateTime(-2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7699         assert(SysTime(Date(-1999, 3, 1)).endOfMonth == SysTime(DateTime(-1999, 3, 31, 23, 59, 59), hnsecs(9_999_999)));
7700         assert(SysTime(Date(-1999, 4, 1)).endOfMonth == SysTime(DateTime(-1999, 4, 30, 23, 59, 59), hnsecs(9_999_999)));
7701         assert(SysTime(Date(-1999, 5, 1)).endOfMonth == SysTime(DateTime(-1999, 5, 31, 23, 59, 59), hnsecs(9_999_999)));
7702         assert(SysTime(Date(-1999, 6, 1)).endOfMonth == SysTime(DateTime(-1999, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7703         assert(SysTime(Date(-1999, 7, 1)).endOfMonth == SysTime(DateTime(-1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7704         assert(SysTime(Date(-1999, 8, 1)).endOfMonth == SysTime(DateTime(-1999, 8, 31, 23, 59, 59), hnsecs(9_999_999)));
7705         assert(SysTime(Date(-1999, 9, 1)).endOfMonth == SysTime(DateTime(-1999, 9, 30, 23, 59, 59), hnsecs(9_999_999)));
7706         assert(SysTime(Date(-1999, 10, 1)).endOfMonth ==
7707                SysTime(DateTime(-1999, 10, 31, 23, 59, 59), hnsecs(9_999_999)));
7708         assert(SysTime(Date(-1999, 11, 1)).endOfMonth ==
7709                SysTime(DateTime(-1999, 11, 30, 23, 59, 59), hnsecs(9_999_999)));
7710         assert(SysTime(Date(-1999, 12, 1)).endOfMonth ==
7711                SysTime(DateTime(-1999, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7712 
7713         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7714         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7715         assert(cst.endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7716         assert(ist.endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7717 
7718         static void testScope(scope ref SysTime st) @safe
7719         {
7720             auto result = st.endOfMonth;
7721         }
7722     }
7723 
7724 
7725     /++
7726         The last day in the month that this $(LREF SysTime) is in.
7727       +/
7728     @property ubyte daysInMonth() @safe const nothrow scope
7729     {
7730         return Date(dayOfGregorianCal).daysInMonth;
7731     }
7732 
7733     ///
7734     @safe unittest
7735     {
7736         import core.time;
7737         import std.datetime.date : DateTime;
7738 
7739         assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).daysInMonth == 31);
7740         assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0)).daysInMonth == 28);
7741         assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27)).daysInMonth == 29);
7742         assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9)).daysInMonth == 30);
7743     }
7744 
7745     @safe unittest
7746     {
7747         import core.time;
7748         // Test A.D.
7749         assert(SysTime(DateTime(1999, 1, 1, 12, 1, 13)).daysInMonth == 31);
7750         assert(SysTime(DateTime(1999, 2, 1, 17, 13, 12)).daysInMonth == 28);
7751         assert(SysTime(DateTime(2000, 2, 1, 13, 2, 12)).daysInMonth == 29);
7752         assert(SysTime(DateTime(1999, 3, 1, 12, 13, 12)).daysInMonth == 31);
7753         assert(SysTime(DateTime(1999, 4, 1, 12, 6, 13)).daysInMonth == 30);
7754         assert(SysTime(DateTime(1999, 5, 1, 15, 13, 12)).daysInMonth == 31);
7755         assert(SysTime(DateTime(1999, 6, 1, 13, 7, 12)).daysInMonth == 30);
7756         assert(SysTime(DateTime(1999, 7, 1, 12, 13, 17)).daysInMonth == 31);
7757         assert(SysTime(DateTime(1999, 8, 1, 12, 3, 13)).daysInMonth == 31);
7758         assert(SysTime(DateTime(1999, 9, 1, 12, 13, 12)).daysInMonth == 30);
7759         assert(SysTime(DateTime(1999, 10, 1, 13, 19, 12)).daysInMonth == 31);
7760         assert(SysTime(DateTime(1999, 11, 1, 12, 13, 17)).daysInMonth == 30);
7761         assert(SysTime(DateTime(1999, 12, 1, 12, 52, 13)).daysInMonth == 31);
7762 
7763         // Test B.C.
7764         assert(SysTime(DateTime(-1999, 1, 1, 12, 1, 13)).daysInMonth == 31);
7765         assert(SysTime(DateTime(-1999, 2, 1, 7, 13, 12)).daysInMonth == 28);
7766         assert(SysTime(DateTime(-2000, 2, 1, 13, 2, 12)).daysInMonth == 29);
7767         assert(SysTime(DateTime(-1999, 3, 1, 12, 13, 12)).daysInMonth == 31);
7768         assert(SysTime(DateTime(-1999, 4, 1, 12, 6, 13)).daysInMonth == 30);
7769         assert(SysTime(DateTime(-1999, 5, 1, 5, 13, 12)).daysInMonth == 31);
7770         assert(SysTime(DateTime(-1999, 6, 1, 13, 7, 12)).daysInMonth == 30);
7771         assert(SysTime(DateTime(-1999, 7, 1, 12, 13, 17)).daysInMonth == 31);
7772         assert(SysTime(DateTime(-1999, 8, 1, 12, 3, 13)).daysInMonth == 31);
7773         assert(SysTime(DateTime(-1999, 9, 1, 12, 13, 12)).daysInMonth == 30);
7774         assert(SysTime(DateTime(-1999, 10, 1, 13, 19, 12)).daysInMonth == 31);
7775         assert(SysTime(DateTime(-1999, 11, 1, 12, 13, 17)).daysInMonth == 30);
7776         assert(SysTime(DateTime(-1999, 12, 1, 12, 52, 13)).daysInMonth == 31);
7777 
7778         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7779         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7780         assert(cst.daysInMonth == 31);
7781         assert(ist.daysInMonth == 31);
7782 
7783         static void testScope(scope ref SysTime st) @safe
7784         {
7785             auto result = st.daysInMonth;
7786         }
7787     }
7788 
7789 
7790     /++
7791         Whether the current year is a date in A.D.
7792       +/
7793     @property bool isAD() @safe const nothrow scope
7794     {
7795         return adjTime >= 0;
7796     }
7797 
7798     ///
7799     @safe unittest
7800     {
7801         import core.time;
7802         import std.datetime.date : DateTime;
7803 
7804         assert(SysTime(DateTime(1, 1, 1, 12, 7, 0)).isAD);
7805         assert(SysTime(DateTime(2010, 12, 31, 0, 0, 0)).isAD);
7806         assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD);
7807         assert(!SysTime(DateTime(-2010, 1, 1, 2, 2, 2)).isAD);
7808     }
7809 
7810     @safe unittest
7811     {
7812         import core.time;
7813         assert(SysTime(DateTime(2010, 7, 4, 12, 0, 9)).isAD);
7814         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).isAD);
7815         assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD);
7816         assert(!SysTime(DateTime(0, 1, 1, 23, 59, 59)).isAD);
7817         assert(!SysTime(DateTime(-1, 1, 1, 23 ,59 ,59)).isAD);
7818         assert(!SysTime(DateTime(-2010, 7, 4, 12, 2, 2)).isAD);
7819 
7820         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7821         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7822         assert(cst.isAD);
7823         assert(ist.isAD);
7824 
7825         static void testScope(scope ref SysTime st) @safe
7826         {
7827             auto result = st.isAD;
7828         }
7829     }
7830 
7831 
7832     /++
7833         The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day)
7834         for this $(LREF SysTime) at the given time. For example,
7835         prior to noon, 1996-03-31 would be the Julian day number 2_450_173, so
7836         this function returns 2_450_173, while from noon onward, the Julian
7837         day number would be 2_450_174, so this function returns 2_450_174.
7838       +/
7839     @property long julianDay() @safe const nothrow scope
7840     {
7841         immutable jd = dayOfGregorianCal + 1_721_425;
7842         return hour < 12 ? jd - 1 : jd;
7843     }
7844 
7845     @safe unittest
7846     {
7847         import core.time;
7848         assert(SysTime(DateTime(-4713, 11, 24, 0, 0, 0)).julianDay == -1);
7849         assert(SysTime(DateTime(-4713, 11, 24, 12, 0, 0)).julianDay == 0);
7850 
7851         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0)).julianDay == 1_721_424);
7852         assert(SysTime(DateTime(0, 12, 31, 12, 0, 0)).julianDay == 1_721_425);
7853 
7854         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).julianDay == 1_721_425);
7855         assert(SysTime(DateTime(1, 1, 1, 12, 0, 0)).julianDay == 1_721_426);
7856 
7857         assert(SysTime(DateTime(1582, 10, 15, 0, 0, 0)).julianDay == 2_299_160);
7858         assert(SysTime(DateTime(1582, 10, 15, 12, 0, 0)).julianDay == 2_299_161);
7859 
7860         assert(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).julianDay == 2_400_000);
7861         assert(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).julianDay == 2_400_001);
7862 
7863         assert(SysTime(DateTime(1982, 1, 4, 0, 0, 0)).julianDay == 2_444_973);
7864         assert(SysTime(DateTime(1982, 1, 4, 12, 0, 0)).julianDay == 2_444_974);
7865 
7866         assert(SysTime(DateTime(1996, 3, 31, 0, 0, 0)).julianDay == 2_450_173);
7867         assert(SysTime(DateTime(1996, 3, 31, 12, 0, 0)).julianDay == 2_450_174);
7868 
7869         assert(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).julianDay == 2_455_432);
7870         assert(SysTime(DateTime(2010, 8, 24, 12, 0, 0)).julianDay == 2_455_433);
7871 
7872         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7873         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7874         assert(cst.julianDay == 2_451_366);
7875         assert(ist.julianDay == 2_451_366);
7876 
7877         static void testScope(scope ref SysTime st) @safe
7878         {
7879             auto result = st.julianDay;
7880         }
7881     }
7882 
7883 
7884     /++
7885         The modified $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for
7886         any time on this date (since, the modified Julian day changes at
7887         midnight).
7888       +/
7889     @property long modJulianDay() @safe const nothrow scope
7890     {
7891         return dayOfGregorianCal + 1_721_425 - 2_400_001;
7892     }
7893 
7894     @safe unittest
7895     {
7896         import core.time;
7897         assert(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).modJulianDay == 0);
7898         assert(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).modJulianDay == 0);
7899 
7900         assert(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).modJulianDay == 55_432);
7901         assert(SysTime(DateTime(2010, 8, 24, 12, 0, 0)).modJulianDay == 55_432);
7902 
7903         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7904         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7905         assert(cst.modJulianDay == 51_365);
7906         assert(ist.modJulianDay == 51_365);
7907 
7908         static void testScope(scope ref SysTime st) @safe
7909         {
7910             auto result = st.modJulianDay;
7911         }
7912     }
7913 
7914 
7915     /++
7916         Returns a $(REF Date,std,datetime,date) equivalent to this $(LREF SysTime).
7917       +/
7918     Date opCast(T)() @safe const nothrow scope
7919         if (is(immutable T == immutable Date))
7920     {
7921         return Date(dayOfGregorianCal);
7922     }
7923 
7924     @safe unittest
7925     {
7926         import core.time;
7927         assert(cast(Date) SysTime(Date(1999, 7, 6)) == Date(1999, 7, 6));
7928         assert(cast(Date) SysTime(Date(2000, 12, 31)) == Date(2000, 12, 31));
7929         assert(cast(Date) SysTime(Date(2001, 1, 1)) == Date(2001, 1, 1));
7930 
7931         assert(cast(Date) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == Date(1999, 7, 6));
7932         assert(cast(Date) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == Date(2000, 12, 31));
7933         assert(cast(Date) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == Date(2001, 1, 1));
7934 
7935         assert(cast(Date) SysTime(Date(-1999, 7, 6)) == Date(-1999, 7, 6));
7936         assert(cast(Date) SysTime(Date(-2000, 12, 31)) == Date(-2000, 12, 31));
7937         assert(cast(Date) SysTime(Date(-2001, 1, 1)) == Date(-2001, 1, 1));
7938 
7939         assert(cast(Date) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == Date(-1999, 7, 6));
7940         assert(cast(Date) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == Date(-2000, 12, 31));
7941         assert(cast(Date) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == Date(-2001, 1, 1));
7942 
7943         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7944         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7945         assert(cast(Date) cst != Date.init);
7946         assert(cast(Date) ist != Date.init);
7947 
7948         static void testScope(scope ref SysTime st) @safe
7949         {
7950             auto result = cast(Date) st;
7951         }
7952     }
7953 
7954 
7955     /++
7956         Returns a $(REF DateTime,std,datetime,date) equivalent to this
7957         $(LREF SysTime).
7958       +/
7959     DateTime opCast(T)() @safe const nothrow scope
7960         if (is(immutable T == immutable DateTime))
7961     {
7962         try
7963         {
7964             auto hnsecs = adjTime;
7965             auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
7966 
7967             if (hnsecs < 0)
7968             {
7969                 hnsecs += convert!("hours", "hnsecs")(24);
7970                 --days;
7971             }
7972 
7973             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
7974             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
7975             immutable second = getUnitsFromHNSecs!"seconds"(hnsecs);
7976 
7977             return DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour, cast(int) minute, cast(int) second));
7978         }
7979         catch (Exception e)
7980             assert(0, "Either DateTime's constructor or TimeOfDay's constructor threw.");
7981     }
7982 
7983     @safe unittest
7984     {
7985         import core.time;
7986         assert(cast(DateTime) SysTime(DateTime(1, 1, 6, 7, 12, 22)) == DateTime(1, 1, 6, 7, 12, 22));
7987         assert(cast(DateTime) SysTime(DateTime(1, 1, 6, 7, 12, 22), msecs(22)) == DateTime(1, 1, 6, 7, 12, 22));
7988         assert(cast(DateTime) SysTime(Date(1999, 7, 6)) == DateTime(1999, 7, 6, 0, 0, 0));
7989         assert(cast(DateTime) SysTime(Date(2000, 12, 31)) == DateTime(2000, 12, 31, 0, 0, 0));
7990         assert(cast(DateTime) SysTime(Date(2001, 1, 1)) == DateTime(2001, 1, 1, 0, 0, 0));
7991 
7992         assert(cast(DateTime) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == DateTime(1999, 7, 6, 12, 10, 9));
7993         assert(cast(DateTime) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == DateTime(2000, 12, 31, 13, 11, 10));
7994         assert(cast(DateTime) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == DateTime(2001, 1, 1, 14, 12, 11));
7995 
7996         assert(cast(DateTime) SysTime(DateTime(-1, 1, 6, 7, 12, 22)) == DateTime(-1, 1, 6, 7, 12, 22));
7997         assert(cast(DateTime) SysTime(DateTime(-1, 1, 6, 7, 12, 22), msecs(22)) == DateTime(-1, 1, 6, 7, 12, 22));
7998         assert(cast(DateTime) SysTime(Date(-1999, 7, 6)) == DateTime(-1999, 7, 6, 0, 0, 0));
7999         assert(cast(DateTime) SysTime(Date(-2000, 12, 31)) == DateTime(-2000, 12, 31, 0, 0, 0));
8000         assert(cast(DateTime) SysTime(Date(-2001, 1, 1)) == DateTime(-2001, 1, 1, 0, 0, 0));
8001 
8002         assert(cast(DateTime) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == DateTime(-1999, 7, 6, 12, 10, 9));
8003         assert(cast(DateTime) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == DateTime(-2000, 12, 31, 13, 11, 10));
8004         assert(cast(DateTime) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == DateTime(-2001, 1, 1, 14, 12, 11));
8005 
8006         assert(cast(DateTime) SysTime(DateTime(2011, 1, 13, 8, 17, 2), msecs(296), LocalTime()) ==
8007                DateTime(2011, 1, 13, 8, 17, 2));
8008 
8009         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8010         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8011         assert(cast(DateTime) cst != DateTime.init);
8012         assert(cast(DateTime) ist != DateTime.init);
8013 
8014         static void testScope(scope ref SysTime st) @safe
8015         {
8016             auto result = cast(DateTime) st;
8017         }
8018     }
8019 
8020 
8021     /++
8022         Returns a $(REF TimeOfDay,std,datetime,date) equivalent to this
8023         $(LREF SysTime).
8024       +/
8025     TimeOfDay opCast(T)() @safe const nothrow scope
8026         if (is(immutable T == immutable TimeOfDay))
8027     {
8028         try
8029         {
8030             auto hnsecs = adjTime;
8031             hnsecs = removeUnitsFromHNSecs!"days"(hnsecs);
8032 
8033             if (hnsecs < 0)
8034                 hnsecs += convert!("hours", "hnsecs")(24);
8035 
8036             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8037             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8038             immutable second = getUnitsFromHNSecs!"seconds"(hnsecs);
8039 
8040             return TimeOfDay(cast(int) hour, cast(int) minute, cast(int) second);
8041         }
8042         catch (Exception e)
8043             assert(0, "TimeOfDay's constructor threw.");
8044     }
8045 
8046     @safe unittest
8047     {
8048         import core.time;
8049         assert(cast(TimeOfDay) SysTime(Date(1999, 7, 6)) == TimeOfDay(0, 0, 0));
8050         assert(cast(TimeOfDay) SysTime(Date(2000, 12, 31)) == TimeOfDay(0, 0, 0));
8051         assert(cast(TimeOfDay) SysTime(Date(2001, 1, 1)) == TimeOfDay(0, 0, 0));
8052 
8053         assert(cast(TimeOfDay) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == TimeOfDay(12, 10, 9));
8054         assert(cast(TimeOfDay) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == TimeOfDay(13, 11, 10));
8055         assert(cast(TimeOfDay) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == TimeOfDay(14, 12, 11));
8056 
8057         assert(cast(TimeOfDay) SysTime(Date(-1999, 7, 6)) == TimeOfDay(0, 0, 0));
8058         assert(cast(TimeOfDay) SysTime(Date(-2000, 12, 31)) == TimeOfDay(0, 0, 0));
8059         assert(cast(TimeOfDay) SysTime(Date(-2001, 1, 1)) == TimeOfDay(0, 0, 0));
8060 
8061         assert(cast(TimeOfDay) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == TimeOfDay(12, 10, 9));
8062         assert(cast(TimeOfDay) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == TimeOfDay(13, 11, 10));
8063         assert(cast(TimeOfDay) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == TimeOfDay(14, 12, 11));
8064 
8065         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8066         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8067         assert(cast(TimeOfDay) cst != TimeOfDay.init);
8068         assert(cast(TimeOfDay) ist != TimeOfDay.init);
8069 
8070         static void testScope(scope ref SysTime st) @safe
8071         {
8072             auto result = cast(TimeOfDay) st;
8073         }
8074     }
8075 
8076 
8077     // Temporary hack until bug https://issues.dlang.org/show_bug.cgi?id=4867 is fixed.
8078     // This allows assignment from const(SysTime) to SysTime.
8079     // It may be a good idea to keep it though, since casting from a type to itself
8080     // should be allowed, and it doesn't work without this opCast() since opCast()
8081     // has already been defined for other types.
8082     SysTime opCast(T)() @safe const pure nothrow scope
8083         if (is(immutable T == immutable SysTime))
8084     {
8085         return SysTime(_stdTime, _timezone);
8086     }
8087 
8088     @safe unittest
8089     {
8090         static void testScope(scope ref SysTime st) @safe
8091         {
8092             auto result = cast(SysTime) st;
8093         }
8094     }
8095 
8096 
8097     /++
8098         Converts this $(LREF SysTime) to a string with the format
8099         YYYYMMDDTHHMMSS.FFFFFFFTZ (where F is fractional seconds and TZ is time
8100         zone).
8101 
8102         Note that the number of digits in the fractional seconds varies with the
8103         number of fractional seconds. It's a maximum of 7 (which would be
8104         hnsecs), but only has as many as are necessary to hold the correct value
8105         (so no trailing zeroes), and if there are no fractional seconds, then
8106         there is no decimal point.
8107 
8108         If this $(LREF SysTime)'s time zone is
8109         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
8110         zone is `UTC`, then it is "Z". Otherwise, it is the offset from UTC
8111         (e.g. +0100 or -0700). Note that the offset from UTC is $(I not) enough
8112         to uniquely identify the time zone.
8113 
8114         Time zone offsets will be in the form +HHMM or -HHMM.
8115 
8116         $(RED Warning:
8117             Previously, toISOString did the same as $(LREF toISOExtString) and
8118             generated +HH:MM or -HH:MM for the time zone when it was not
8119             $(REF LocalTime,std,datetime,timezone) or
8120             $(REF UTC,std,datetime,timezone), which is not in conformance with
8121             ISO 8601 for the non-extended string format. This has now been
8122             fixed. However, for now, fromISOString will continue to accept the
8123             extended format for the time zone so that any code which has been
8124             writing out the result of toISOString to read in later will continue
8125             to work. The current behavior will be kept until July 2019 at which
8126             point, fromISOString will be fixed to be standards compliant.)
8127 
8128         Params:
8129             writer = A `char` accepting
8130             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8131         Returns:
8132             A `string` when not using an output range; `void` otherwise.
8133       +/
8134     string toISOString() @safe const nothrow scope
8135     {
8136         import std.array : appender;
8137         auto app = appender!string();
8138         app.reserve(30);
8139         try
8140             toISOString(app);
8141         catch (Exception e)
8142             assert(0, "toISOString() threw.");
8143         return app.data;
8144     }
8145 
8146     /// ditto
8147     void toISOString(W)(ref W writer) const scope
8148     if (isOutputRange!(W, char))
8149     {
8150         immutable adjustedTime = adjTime;
8151         long hnsecs = adjustedTime;
8152 
8153         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
8154 
8155         if (hnsecs < 0)
8156         {
8157             hnsecs += convert!("hours", "hnsecs")(24);
8158             --days;
8159         }
8160 
8161         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8162         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8163         immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
8164 
8165         auto dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
8166                                       cast(int) minute, cast(int) second));
8167 
8168         if (_timezone is LocalTime())
8169         {
8170             dateTime.toISOString(writer);
8171             fracSecsToISOString(writer, cast(int) hnsecs);
8172             return;
8173         }
8174 
8175         if (_timezone is UTC())
8176         {
8177             dateTime.toISOString(writer);
8178             fracSecsToISOString(writer, cast(int) hnsecs);
8179             put(writer, 'Z');
8180             return;
8181         }
8182 
8183         immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
8184 
8185         dateTime.toISOString(writer);
8186         fracSecsToISOString(writer, cast(int) hnsecs);
8187         SimpleTimeZone.toISOExtString(writer, utcOffset);
8188     }
8189 
8190     ///
8191     @safe unittest
8192     {
8193         import core.time : msecs, hnsecs;
8194         import std.datetime.date : DateTime;
8195 
8196         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOString() ==
8197                "20100704T070612");
8198 
8199         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOString() ==
8200                "19981225T021500.024");
8201 
8202         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOString() ==
8203                "00000105T230959");
8204 
8205         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOString() ==
8206                "-00040105T000002.052092");
8207     }
8208 
8209     @safe unittest
8210     {
8211         import core.time;
8212         // Test A.D.
8213         assert(SysTime(DateTime.init, UTC()).toISOString() == "00010101T000000Z");
8214         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toISOString() == "00010101T000000.0000001Z");
8215 
8216         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOString() == "00091204T000000");
8217         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOString() == "00991204T050612");
8218         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOString() == "09991204T134459");
8219         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOString() == "99990704T235959");
8220         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOString() == "+100001020T010101");
8221 
8222         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toISOString() == "00091204T000000.042");
8223         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toISOString() == "00991204T050612.1");
8224         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toISOString() == "09991204T134459.04502");
8225         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOString() == "99990704T235959.0000012");
8226         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOString() == "+100001020T010101.050789");
8227 
8228         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8229                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toISOString() ==
8230                "20121221T121212-06:00");
8231 
8232         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8233                        new immutable SimpleTimeZone(dur!"minutes"(420))).toISOString() ==
8234                "20121221T121212+07:00");
8235 
8236         // Test B.C.
8237         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toISOString() ==
8238                "00001231T235959.9999999Z");
8239         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toISOString() == "00001231T235959.0000001Z");
8240         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOString() == "00001231T235959Z");
8241 
8242         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOString() == "00001204T001204");
8243         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOString() == "-00091204T000000");
8244         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOString() == "-00991204T050612");
8245         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOString() == "-09991204T134459");
8246         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOString() == "-99990704T235959");
8247         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOString() == "-100001020T010101");
8248 
8249         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toISOString() == "00001204T000000.007");
8250         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toISOString() == "-00091204T000000.042");
8251         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toISOString() == "-00991204T050612.1");
8252         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toISOString() == "-09991204T134459.04502");
8253         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOString() == "-99990704T235959.0000012");
8254         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOString() == "-100001020T010101.050789");
8255 
8256         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8257         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8258         assert(cst.toISOString() == "19990706T123033");
8259         assert(ist.toISOString() == "19990706T123033");
8260 
8261         static void testScope(scope ref SysTime st) @safe
8262         {
8263             auto result = st.toISOString();
8264         }
8265     }
8266 
8267 
8268 
8269     /++
8270         Converts this $(LREF SysTime) to a string with the format
8271         YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
8272         is the time zone).
8273 
8274         Note that the number of digits in the fractional seconds varies with the
8275         number of fractional seconds. It's a maximum of 7 (which would be
8276         hnsecs), but only has as many as are necessary to hold the correct value
8277         (so no trailing zeroes), and if there are no fractional seconds, then
8278         there is no decimal point.
8279 
8280         If this $(LREF SysTime)'s time zone is
8281         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
8282         zone is `UTC`, then it is "Z". Otherwise, it is the offset from UTC
8283         (e.g. +01:00 or -07:00). Note that the offset from UTC is $(I not)
8284         enough to uniquely identify the time zone.
8285 
8286         Time zone offsets will be in the form +HH:MM or -HH:MM.
8287 
8288         Params:
8289             writer = A `char` accepting
8290             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8291         Returns:
8292             A `string` when not using an output range; `void` otherwise.
8293       +/
8294     string toISOExtString() @safe const nothrow scope
8295     {
8296         import std.array : appender;
8297         auto app = appender!string();
8298         app.reserve(35);
8299         try
8300             toISOExtString(app);
8301         catch (Exception e)
8302             assert(0, "toISOExtString() threw.");
8303         return app.data;
8304     }
8305 
8306     /// ditto
8307     void toISOExtString(W)(ref W writer) const scope
8308     if (isOutputRange!(W, char))
8309     {
8310         immutable adjustedTime = adjTime;
8311         long hnsecs = adjustedTime;
8312 
8313         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
8314 
8315         if (hnsecs < 0)
8316         {
8317             hnsecs += convert!("hours", "hnsecs")(24);
8318             --days;
8319         }
8320 
8321         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8322         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8323         immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
8324 
8325         immutable dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
8326                                       cast(int) minute, cast(int) second));
8327 
8328         if (_timezone is LocalTime())
8329         {
8330             dateTime.toISOExtString(writer);
8331             fracSecsToISOString(writer, cast(int) hnsecs);
8332             return;
8333         }
8334 
8335         if (_timezone is UTC())
8336         {
8337             dateTime.toISOExtString(writer);
8338             fracSecsToISOString(writer, cast(int) hnsecs);
8339             put(writer, 'Z');
8340             return;
8341         }
8342 
8343         immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
8344 
8345         dateTime.toISOExtString(writer);
8346         fracSecsToISOString(writer, cast(int) hnsecs);
8347         SimpleTimeZone.toISOExtString(writer, utcOffset);
8348     }
8349 
8350     ///
8351     @safe unittest
8352     {
8353         import core.time : msecs, hnsecs;
8354         import std.datetime.date : DateTime;
8355 
8356         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOExtString() ==
8357                "2010-07-04T07:06:12");
8358 
8359         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOExtString() ==
8360                "1998-12-25T02:15:00.024");
8361 
8362         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOExtString() ==
8363                "0000-01-05T23:09:59");
8364 
8365         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString() ==
8366                "-0004-01-05T00:00:02.052092");
8367     }
8368 
8369     @safe unittest
8370     {
8371         import core.time;
8372         // Test A.D.
8373         assert(SysTime(DateTime.init, UTC()).toISOExtString() == "0001-01-01T00:00:00Z");
8374         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toISOExtString() ==
8375                "0001-01-01T00:00:00.0000001Z");
8376 
8377         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOExtString() == "0009-12-04T00:00:00");
8378         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOExtString() == "0099-12-04T05:06:12");
8379         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOExtString() == "0999-12-04T13:44:59");
8380         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOExtString() == "9999-07-04T23:59:59");
8381         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOExtString() == "+10000-10-20T01:01:01");
8382 
8383         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toISOExtString() == "0009-12-04T00:00:00.042");
8384         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toISOExtString() == "0099-12-04T05:06:12.1");
8385         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toISOExtString() == "0999-12-04T13:44:59.04502");
8386         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOExtString() == "9999-07-04T23:59:59.0000012");
8387         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOExtString() ==
8388                "+10000-10-20T01:01:01.050789");
8389 
8390         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8391                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toISOExtString() ==
8392                "2012-12-21T12:12:12-06:00");
8393 
8394         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8395                        new immutable SimpleTimeZone(dur!"minutes"(420))).toISOExtString() ==
8396                "2012-12-21T12:12:12+07:00");
8397 
8398         // Test B.C.
8399         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toISOExtString() ==
8400                "0000-12-31T23:59:59.9999999Z");
8401         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toISOExtString() ==
8402                "0000-12-31T23:59:59.0000001Z");
8403         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOExtString() == "0000-12-31T23:59:59Z");
8404 
8405         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOExtString() == "0000-12-04T00:12:04");
8406         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOExtString() == "-0009-12-04T00:00:00");
8407         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOExtString() == "-0099-12-04T05:06:12");
8408         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOExtString() == "-0999-12-04T13:44:59");
8409         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOExtString() == "-9999-07-04T23:59:59");
8410         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOExtString() == "-10000-10-20T01:01:01");
8411 
8412         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toISOExtString() == "0000-12-04T00:00:00.007");
8413         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toISOExtString() == "-0009-12-04T00:00:00.042");
8414         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toISOExtString() == "-0099-12-04T05:06:12.1");
8415         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toISOExtString() ==
8416                "-0999-12-04T13:44:59.04502");
8417         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOExtString() ==
8418                "-9999-07-04T23:59:59.0000012");
8419         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOExtString() ==
8420                "-10000-10-20T01:01:01.050789");
8421 
8422         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8423         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8424         assert(cst.toISOExtString() == "1999-07-06T12:30:33");
8425         assert(ist.toISOExtString() == "1999-07-06T12:30:33");
8426 
8427         static void testScope(scope ref SysTime st) @safe
8428         {
8429             auto result = st.toISOExtString();
8430         }
8431     }
8432 
8433     /++
8434         Converts this $(LREF SysTime) to a string with the format
8435         YYYY-Mon-DD HH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
8436         is the time zone).
8437 
8438         Note that the number of digits in the fractional seconds varies with the
8439         number of fractional seconds. It's a maximum of 7 (which would be
8440         hnsecs), but only has as many as are necessary to hold the correct value
8441         (so no trailing zeroes), and if there are no fractional seconds, then
8442         there is no decimal point.
8443 
8444         If this $(LREF SysTime)'s time zone is
8445         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
8446         zone is `UTC`, then it is "Z". Otherwise, it is the offset from UTC
8447         (e.g. +01:00 or -07:00). Note that the offset from UTC is $(I not)
8448         enough to uniquely identify the time zone.
8449 
8450         Time zone offsets will be in the form +HH:MM or -HH:MM.
8451 
8452         Params:
8453             writer = A `char` accepting
8454             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8455         Returns:
8456             A `string` when not using an output range; `void` otherwise.
8457       +/
8458     string toSimpleString() @safe const nothrow scope
8459     {
8460         import std.array : appender;
8461         auto app = appender!string();
8462         app.reserve(35);
8463         try
8464             toSimpleString(app);
8465         catch (Exception e)
8466             assert(0, "toSimpleString() threw.");
8467         return app.data;
8468     }
8469 
8470     /// ditto
8471     void toSimpleString(W)(ref W writer) const scope
8472     if (isOutputRange!(W, char))
8473     {
8474         immutable adjustedTime = adjTime;
8475         long hnsecs = adjustedTime;
8476 
8477         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
8478 
8479         if (hnsecs < 0)
8480         {
8481             hnsecs += convert!("hours", "hnsecs")(24);
8482             --days;
8483         }
8484 
8485         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8486         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8487         immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
8488 
8489         immutable dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
8490                                       cast(int) minute, cast(int) second));
8491 
8492         if (_timezone is LocalTime())
8493         {
8494             dateTime.toSimpleString(writer);
8495             fracSecsToISOString(writer, cast(int) hnsecs);
8496             return;
8497         }
8498 
8499         if (_timezone is UTC())
8500         {
8501             dateTime.toSimpleString(writer);
8502             fracSecsToISOString(writer, cast(int) hnsecs);
8503             put(writer, 'Z');
8504             return;
8505         }
8506 
8507         immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
8508 
8509         dateTime.toSimpleString(writer);
8510         fracSecsToISOString(writer, cast(int) hnsecs);
8511         SimpleTimeZone.toISOExtString(writer, utcOffset);
8512     }
8513 
8514     ///
8515     @safe unittest
8516     {
8517         import core.time : msecs, hnsecs;
8518         import std.datetime.date : DateTime;
8519 
8520         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toSimpleString() ==
8521                "2010-Jul-04 07:06:12");
8522 
8523         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toSimpleString() ==
8524                "1998-Dec-25 02:15:00.024");
8525 
8526         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toSimpleString() ==
8527                "0000-Jan-05 23:09:59");
8528 
8529         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toSimpleString() ==
8530                 "-0004-Jan-05 00:00:02.052092");
8531     }
8532 
8533     @safe unittest
8534     {
8535         import core.time;
8536         // Test A.D.
8537         assert(SysTime(DateTime.init, UTC()).toString() == "0001-Jan-01 00:00:00Z");
8538         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toString() == "0001-Jan-01 00:00:00.0000001Z");
8539 
8540         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toSimpleString() == "0009-Dec-04 00:00:00");
8541         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toSimpleString() == "0099-Dec-04 05:06:12");
8542         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toSimpleString() == "0999-Dec-04 13:44:59");
8543         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toSimpleString() == "9999-Jul-04 23:59:59");
8544         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toSimpleString() == "+10000-Oct-20 01:01:01");
8545 
8546         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toSimpleString() == "0009-Dec-04 00:00:00.042");
8547         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toSimpleString() == "0099-Dec-04 05:06:12.1");
8548         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toSimpleString() ==
8549                "0999-Dec-04 13:44:59.04502");
8550         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toSimpleString() ==
8551                "9999-Jul-04 23:59:59.0000012");
8552         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toSimpleString() ==
8553                "+10000-Oct-20 01:01:01.050789");
8554 
8555         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8556                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toSimpleString() ==
8557                "2012-Dec-21 12:12:12-06:00");
8558 
8559         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8560                        new immutable SimpleTimeZone(dur!"minutes"(420))).toSimpleString() ==
8561                "2012-Dec-21 12:12:12+07:00");
8562 
8563         // Test B.C.
8564         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toSimpleString() ==
8565                "0000-Dec-31 23:59:59.9999999Z");
8566         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toSimpleString() ==
8567                "0000-Dec-31 23:59:59.0000001Z");
8568         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toSimpleString() == "0000-Dec-31 23:59:59Z");
8569 
8570         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toSimpleString() == "0000-Dec-04 00:12:04");
8571         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toSimpleString() == "-0009-Dec-04 00:00:00");
8572         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toSimpleString() == "-0099-Dec-04 05:06:12");
8573         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toSimpleString() == "-0999-Dec-04 13:44:59");
8574         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toSimpleString() == "-9999-Jul-04 23:59:59");
8575         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toSimpleString() == "-10000-Oct-20 01:01:01");
8576 
8577         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toSimpleString() == "0000-Dec-04 00:00:00.007");
8578         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toSimpleString() == "-0009-Dec-04 00:00:00.042");
8579         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toSimpleString() == "-0099-Dec-04 05:06:12.1");
8580         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toSimpleString() ==
8581                "-0999-Dec-04 13:44:59.04502");
8582         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toSimpleString() ==
8583                "-9999-Jul-04 23:59:59.0000012");
8584         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toSimpleString() ==
8585                "-10000-Oct-20 01:01:01.050789");
8586 
8587         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8588         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8589         assert(cst.toSimpleString() == "1999-Jul-06 12:30:33");
8590         assert(ist.toSimpleString() == "1999-Jul-06 12:30:33");
8591 
8592         static void testScope(scope ref SysTime st) @safe
8593         {
8594             auto result = st.toSimpleString();
8595         }
8596     }
8597 
8598 
8599     /++
8600         Converts this $(LREF SysTime) to a string.
8601 
8602         This function exists to make it easy to convert a $(LREF SysTime) to a
8603         string for code that does not care what the exact format is - just that
8604         it presents the information in a clear manner. It also makes it easy to
8605         simply convert a $(LREF SysTime) to a string when using functions such
8606         as `to!string`, `format`, or `writeln` which use toString to convert
8607         user-defined types. So, it is unlikely that much code will call
8608         toString directly.
8609 
8610         The format of the string is purposefully unspecified, and code that
8611         cares about the format of the string should use `toISOString`,
8612         `toISOExtString`, `toSimpleString`, or some other custom formatting
8613         function that explicitly generates the format that the code needs. The
8614         reason is that the code is then clear about what format it's using,
8615         making it less error-prone to maintain the code and interact with other
8616         software that consumes the generated strings. It's for this same reason
8617         that $(LREF SysTime) has no `fromString` function, whereas it does have
8618         `fromISOString`, `fromISOExtString`, and `fromSimpleString`.
8619 
8620         The format returned by toString may or may not change in the future.
8621 
8622         Params:
8623             writer = A `char` accepting
8624             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8625         Returns:
8626             A `string` when not using an output range; `void` otherwise.
8627       +/
8628     string toString() @safe const nothrow scope
8629     {
8630         return toSimpleString();
8631     }
8632 
8633     /// ditto
8634     void toString(W)(ref W writer) const scope
8635     if (isOutputRange!(W, char))
8636     {
8637         toSimpleString(writer);
8638     }
8639 
8640     @safe unittest
8641     {
8642         import core.time;
8643         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8644         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8645         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8646         static assert(__traits(compiles, st.toString()));
8647         static assert(__traits(compiles, cst.toString()));
8648         static assert(__traits(compiles, ist.toString()));
8649 
8650         static void testScope(scope ref SysTime st) @safe
8651         {
8652             auto result = st.toString();
8653         }
8654     }
8655 
8656 
8657     /++
8658         Creates a $(LREF SysTime) from a string with the format
8659         YYYYMMDDTHHMMSS.FFFFFFFTZ (where F is fractional seconds is the time
8660         zone). Whitespace is stripped from the given string.
8661 
8662         The exact format is exactly as described in `toISOString` except that
8663         trailing zeroes are permitted - including having fractional seconds with
8664         all zeroes. However, a decimal point with nothing following it is
8665         invalid. Also, while $(LREF toISOString) will never generate a string
8666         with more than 7 digits in the fractional seconds (because that's the
8667         limit with hecto-nanosecond precision), it will allow more than 7 digits
8668         in order to read strings from other sources that have higher precision
8669         (however, any digits beyond 7 will be truncated).
8670 
8671         If there is no time zone in the string, then
8672         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
8673         then `UTC` is used. Otherwise, a
8674         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
8675         given offset from UTC is used. To get the returned $(LREF SysTime) to be
8676         a particular time zone, pass in that time zone and the $(LREF SysTime)
8677         to be returned will be converted to that time zone (though it will still
8678         be read in as whatever time zone is in its string).
8679 
8680         The accepted formats for time zone offsets are +HH, -HH, +HHMM, and
8681         -HHMM.
8682 
8683         $(RED Warning:
8684             Previously, $(LREF toISOString) did the same as
8685             $(LREF toISOExtString) and generated +HH:MM or -HH:MM for the time
8686             zone when it was not $(REF LocalTime,std,datetime,timezone) or
8687             $(REF UTC,std,datetime,timezone), which is not in conformance with
8688             ISO 8601 for the non-extended string format. This has now been
8689             fixed. However, for now, fromISOString will continue to accept the
8690             extended format for the time zone so that any code which has been
8691             writing out the result of toISOString to read in later will continue
8692             to work. The current behavior will be kept until July 2019 at which
8693             point, fromISOString will be fixed to be standards compliant.)
8694 
8695         Params:
8696             isoString = A string formatted in the ISO format for dates and times.
8697             tz        = The time zone to convert the given time to (no
8698                         conversion occurs if null).
8699 
8700         Throws:
8701             $(REF DateTimeException,std,datetime,date) if the given string is
8702             not in the ISO format or if the resulting $(LREF SysTime) would not
8703             be valid.
8704       +/
8705     static SysTime fromISOString(S)(scope const S isoString, immutable TimeZone tz = null) @safe
8706         if (isSomeString!S)
8707     {
8708         import std.algorithm.searching : startsWith, find;
8709         import std.conv : to;
8710         import std..string : strip;
8711         import std.utf : byCodeUnit;
8712 
8713         auto str = strip(isoString);
8714         immutable skipFirst = str.startsWith('+', '-');
8715 
8716         auto found = (skipFirst ? str[1..$] : str).byCodeUnit.find('.', 'Z', '+', '-');
8717         auto dateTimeStr = str[0 .. $ - found[0].length];
8718 
8719         typeof(str) fracSecStr;
8720         typeof(str) zoneStr;
8721 
8722         if (found[1] != 0)
8723         {
8724             if (found[1] == 1)
8725             {
8726                 auto foundTZ = found[0].find('Z', '+', '-');
8727 
8728                 if (foundTZ[1] != 0)
8729                 {
8730                     static if (isNarrowString!S)
8731                     {
8732                         fracSecStr = found[0][0 .. $ - foundTZ[0].length].source;
8733                         zoneStr = foundTZ[0].source;
8734                     }
8735                     else
8736                     {
8737                         fracSecStr = found[0][0 .. $ - foundTZ[0].length];
8738                         zoneStr = foundTZ[0];
8739                     }
8740                 }
8741                 else
8742                 {
8743                     static if (isNarrowString!S)
8744                         fracSecStr = found[0].source;
8745                     else
8746                         fracSecStr = found[0];
8747                 }
8748             }
8749             else
8750             {
8751                 static if (isNarrowString!S)
8752                     zoneStr = found[0].source;
8753                 else
8754                     zoneStr = found[0];
8755             }
8756         }
8757 
8758         try
8759         {
8760             auto dateTime = DateTime.fromISOString(dateTimeStr);
8761             auto fracSec = fracSecsFromISOString(fracSecStr);
8762 
8763             Rebindable!(immutable TimeZone) parsedZone;
8764 
8765             if (zoneStr.empty)
8766                 parsedZone = LocalTime();
8767             else if (zoneStr == "Z")
8768                 parsedZone = UTC();
8769             else
8770             {
8771                 try
8772                     parsedZone = SimpleTimeZone.fromISOString(zoneStr);
8773                 catch (DateTimeException dte)
8774                     parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
8775             }
8776 
8777             auto retval = SysTime(dateTime, fracSec, parsedZone);
8778 
8779             if (tz !is null)
8780                 retval.timezone = tz;
8781 
8782             return retval;
8783         }
8784         catch (DateTimeException dte)
8785             throw new DateTimeException(format("Invalid ISO String: %s", isoString));
8786     }
8787 
8788     ///
8789     @safe unittest
8790     {
8791         import core.time : hours, msecs, usecs, hnsecs;
8792         import std.datetime.date : DateTime;
8793         import std.datetime.timezone : SimpleTimeZone, UTC;
8794 
8795         assert(SysTime.fromISOString("20100704T070612") ==
8796                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8797 
8798         assert(SysTime.fromISOString("19981225T021500.007") ==
8799                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
8800 
8801         assert(SysTime.fromISOString("00000105T230959.00002") ==
8802                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
8803 
8804         assert(SysTime.fromISOString("20130207T043937.000050392") ==
8805                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
8806 
8807         assert(SysTime.fromISOString("-00040105T000002") ==
8808                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
8809 
8810         assert(SysTime.fromISOString(" 20100704T070612 ") ==
8811                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8812 
8813         assert(SysTime.fromISOString("20100704T070612Z") ==
8814                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
8815 
8816         assert(SysTime.fromISOString("20100704T070612-0800") ==
8817                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8818                        new immutable SimpleTimeZone(hours(-8))));
8819 
8820         assert(SysTime.fromISOString("20100704T070612+0800") ==
8821                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8822                        new immutable SimpleTimeZone(hours(8))));
8823     }
8824 
8825     @safe unittest
8826     {
8827         import core.time;
8828         foreach (str; ["", "20100704000000", "20100704 000000", "20100704t000000",
8829                        "20100704T000000.", "20100704T000000.A", "20100704T000000.Z",
8830                        "20100704T000000.0000000A", "20100704T000000.00000000A",
8831                        "20100704T000000+", "20100704T000000-", "20100704T000000:",
8832                        "20100704T000000-:", "20100704T000000+:", "20100704T000000-1:",
8833                        "20100704T000000+1:", "20100704T000000+1:0",
8834                        "20100704T000000-12.00", "20100704T000000+12.00",
8835                        "20100704T000000-8", "20100704T000000+8",
8836                        "20100704T000000-800", "20100704T000000+800",
8837                        "20100704T000000-080", "20100704T000000+080",
8838                        "20100704T000000-2400", "20100704T000000+2400",
8839                        "20100704T000000-1260", "20100704T000000+1260",
8840                        "20100704T000000.0-8", "20100704T000000.0+8",
8841                        "20100704T000000.0-800", "20100704T000000.0+800",
8842                        "20100704T000000.0-080", "20100704T000000.0+080",
8843                        "20100704T000000.0-2400", "20100704T000000.0+2400",
8844                        "20100704T000000.0-1260", "20100704T000000.0+1260",
8845                        "20100704T000000-8:00", "20100704T000000+8:00",
8846                        "20100704T000000-08:0", "20100704T000000+08:0",
8847                        "20100704T000000-24:00", "20100704T000000+24:00",
8848                        "20100704T000000-12:60", "20100704T000000+12:60",
8849                        "20100704T000000.0-8:00", "20100704T000000.0+8:00",
8850                        "20100704T000000.0-08:0", "20100704T000000.0+08:0",
8851                        "20100704T000000.0-24:00", "20100704T000000.0+24:00",
8852                        "20100704T000000.0-12:60", "20100704T000000.0+12:60",
8853                        "2010-07-0400:00:00", "2010-07-04 00:00:00",
8854                        "2010-07-04t00:00:00", "2010-07-04T00:00:00.",
8855                        "2010-Jul-0400:00:00", "2010-Jul-04 00:00:00", "2010-Jul-04t00:00:00",
8856                        "2010-Jul-04T00:00:00", "2010-Jul-04 00:00:00.",
8857                        "2010-12-22T172201", "2010-Dec-22 17:22:01"])
8858         {
8859             assertThrown!DateTimeException(SysTime.fromISOString(str), format("[%s]", str));
8860         }
8861 
8862         static void test(string str, SysTime st, size_t line = __LINE__)
8863         {
8864             if (SysTime.fromISOString(str) != st)
8865                 throw new AssertError("unittest failure", __FILE__, line);
8866         }
8867 
8868         test("20101222T172201", SysTime(DateTime(2010, 12, 22, 17, 22, 01)));
8869         test("19990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8870         test("-19990706T123033", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
8871         test("+019990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8872         test("19990706T123033 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8873         test(" 19990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8874         test(" 19990706T123033 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8875 
8876         test("19070707T121212.0", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
8877         test("19070707T121212.0000000", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
8878         test("19070707T121212.0000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1)));
8879         test("20100704T000000.00000000", SysTime(Date(2010, 07, 04)));
8880         test("20100704T000000.00000009", SysTime(Date(2010, 07, 04)));
8881         test("20100704T000000.00000019", SysTime(DateTime(2010, 07, 04), hnsecs(1)));
8882         test("19070707T121212.000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
8883         test("19070707T121212.0000010", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
8884         test("19070707T121212.001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
8885         test("19070707T121212.0010000", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
8886 
8887         auto west60 = new immutable SimpleTimeZone(hours(-1));
8888         auto west90 = new immutable SimpleTimeZone(minutes(-90));
8889         auto west480 = new immutable SimpleTimeZone(hours(-8));
8890         auto east60 = new immutable SimpleTimeZone(hours(1));
8891         auto east90 = new immutable SimpleTimeZone(minutes(90));
8892         auto east480 = new immutable SimpleTimeZone(hours(8));
8893 
8894         test("20101222T172201Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC()));
8895         test("20101222T172201-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
8896         test("20101222T172201-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
8897         test("20101222T172201-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90));
8898         test("20101222T172201-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480));
8899         test("20101222T172201+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8900         test("20101222T172201+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8901         test("20101222T172201+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8902         test("20101222T172201+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480));
8903 
8904         test("20101103T065106.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
8905         test("20101222T172201.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_341_200), UTC()));
8906         test("20101222T172201.23112-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60));
8907         test("20101222T172201.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), west60));
8908         test("20101222T172201.1-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90));
8909         test("20101222T172201.55-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480));
8910         test("20101222T172201.1234567+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60));
8911         test("20101222T172201.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8912         test("20101222T172201.0000000+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8913         test("20101222T172201.45+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480));
8914 
8915         // for dstring coverage
8916         assert(SysTime.fromISOString("20101222T172201.23112-0100"d) == SysTime(
8917             DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60));
8918         assert(SysTime.fromISOString("19070707T121212.0010000"d) == SysTime(
8919             DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
8920 
8921         // @@@DEPRECATED_2019-07@@@
8922         // This isn't deprecated per se, but that text will make it so that it
8923         // pops up when deprecations are moved along around July 2019. At that
8924         // time, we will update fromISOString so that it is conformant with ISO
8925         // 8601, and it will no longer accept ISO extended time zones (it does
8926         // currently because of https://issues.dlang.org/show_bug.cgi?id=15654
8927         // toISOString used to incorrectly use the ISO extended time zone format).
8928         // These tests will then start failing will need to be updated accordingly.
8929         // Also, the notes about this issue in toISOString and fromISOString's
8930         // documentation will need to be removed.
8931         test("20101222T172201-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
8932         test("20101222T172201-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90));
8933         test("20101222T172201-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480));
8934         test("20101222T172201+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8935         test("20101222T172201+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8936         test("20101222T172201+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480));
8937 
8938         test("20101222T172201.23112-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60));
8939         test("20101222T172201.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90));
8940         test("20101222T172201.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480));
8941         test("20101222T172201.1234567+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60));
8942         test("20101222T172201.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8943         test("20101222T172201.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480));
8944 
8945         static void testScope(scope ref string str) @safe
8946         {
8947             auto result = SysTime.fromISOString(str);
8948         }
8949     }
8950 
8951     // https://issues.dlang.org/show_bug.cgi?id=17801
8952     @safe unittest
8953     {
8954         import std.conv : to;
8955         import std.meta : AliasSeq;
8956         static foreach (C; AliasSeq!(char, wchar, dchar))
8957         {
8958             static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
8959             {
8960                 assert(SysTime.fromISOString(to!S("20121221T141516Z")) ==
8961                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
8962             }
8963         }
8964     }
8965 
8966 
8967     /++
8968         Creates a $(LREF SysTime) from a string with the format
8969         YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ (where F is fractional seconds is the
8970         time zone). Whitespace is stripped from the given string.
8971 
8972         The exact format is exactly as described in `toISOExtString`
8973         except that trailing zeroes are permitted - including having fractional
8974         seconds with all zeroes. However, a decimal point with nothing following
8975         it is invalid. Also, while $(LREF toISOExtString) will never generate a
8976         string with more than 7 digits in the fractional seconds (because that's
8977         the limit with hecto-nanosecond precision), it will allow more than 7
8978         digits in order to read strings from other sources that have higher
8979         precision (however, any digits beyond 7 will be truncated).
8980 
8981         If there is no time zone in the string, then
8982         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
8983         then `UTC` is used. Otherwise, a
8984         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
8985         given offset from UTC is used. To get the returned $(LREF SysTime) to be
8986         a particular time zone, pass in that time zone and the $(LREF SysTime)
8987         to be returned will be converted to that time zone (though it will still
8988         be read in as whatever time zone is in its string).
8989 
8990         The accepted formats for time zone offsets are +HH, -HH, +HH:MM, and
8991         -HH:MM.
8992 
8993         Params:
8994             isoExtString = A string formatted in the ISO Extended format for
8995                            dates and times.
8996             tz           = The time zone to convert the given time to (no
8997                            conversion occurs if null).
8998 
8999         Throws:
9000             $(REF DateTimeException,std,datetime,date) if the given string is
9001             not in the ISO format or if the resulting $(LREF SysTime) would not
9002             be valid.
9003       +/
9004     static SysTime fromISOExtString(S)(scope const S isoExtString, immutable TimeZone tz = null) @safe
9005         if (isSomeString!(S))
9006     {
9007         import std.algorithm.searching : countUntil, find;
9008         import std.conv : to;
9009         import std..string : strip, indexOf;
9010 
9011         auto str = strip(isoExtString);
9012 
9013         auto tIndex = str.indexOf('T');
9014         enforce(tIndex != -1, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
9015 
9016         auto found = str[tIndex + 1 .. $].find('.', 'Z', '+', '-');
9017         auto dateTimeStr = str[0 .. $ - found[0].length];
9018 
9019         typeof(str) fracSecStr;
9020         typeof(str) zoneStr;
9021 
9022         if (found[1] != 0)
9023         {
9024             if (found[1] == 1)
9025             {
9026                 auto foundTZ = found[0].find('Z', '+', '-');
9027 
9028                 if (foundTZ[1] != 0)
9029                 {
9030                     fracSecStr = found[0][0 .. $ - foundTZ[0].length];
9031                     zoneStr = foundTZ[0];
9032                 }
9033                 else
9034                     fracSecStr = found[0];
9035             }
9036             else
9037                 zoneStr = found[0];
9038         }
9039 
9040         try
9041         {
9042             auto dateTime = DateTime.fromISOExtString(dateTimeStr);
9043             auto fracSec = fracSecsFromISOString(fracSecStr);
9044             Rebindable!(immutable TimeZone) parsedZone;
9045 
9046             if (zoneStr.empty)
9047                 parsedZone = LocalTime();
9048             else if (zoneStr == "Z")
9049                 parsedZone = UTC();
9050             else
9051                 parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
9052 
9053             auto retval = SysTime(dateTime, fracSec, parsedZone);
9054 
9055             if (tz !is null)
9056                 retval.timezone = tz;
9057 
9058             return retval;
9059         }
9060         catch (DateTimeException dte)
9061             throw new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString));
9062     }
9063 
9064     ///
9065     @safe unittest
9066     {
9067         import core.time : hours, msecs, usecs, hnsecs;
9068         import std.datetime.date : DateTime;
9069         import std.datetime.timezone : SimpleTimeZone, UTC;
9070 
9071         assert(SysTime.fromISOExtString("2010-07-04T07:06:12") ==
9072                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9073 
9074         assert(SysTime.fromISOExtString("1998-12-25T02:15:00.007") ==
9075                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
9076 
9077         assert(SysTime.fromISOExtString("0000-01-05T23:09:59.00002") ==
9078                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
9079 
9080         assert(SysTime.fromISOExtString("2013-02-07T04:39:37.000050392") ==
9081                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
9082 
9083         assert(SysTime.fromISOExtString("-0004-01-05T00:00:02") ==
9084                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
9085 
9086         assert(SysTime.fromISOExtString(" 2010-07-04T07:06:12 ") ==
9087                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9088 
9089         assert(SysTime.fromISOExtString("2010-07-04T07:06:12Z") ==
9090                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
9091 
9092         assert(SysTime.fromISOExtString("2010-07-04T07:06:12-08:00") ==
9093                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9094                        new immutable SimpleTimeZone(hours(-8))));
9095         assert(SysTime.fromISOExtString("2010-07-04T07:06:12+08:00") ==
9096                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9097                        new immutable SimpleTimeZone(hours(8))));
9098     }
9099 
9100     @safe unittest
9101     {
9102         import core.time;
9103         foreach (str; ["", "20100704000000", "20100704 000000",
9104                        "20100704t000000", "20100704T000000.", "20100704T000000.0",
9105                        "2010-07:0400:00:00", "2010-07-04 00:00:00",
9106                        "2010-07-04 00:00:00", "2010-07-04t00:00:00",
9107                        "2010-07-04T00:00:00.", "2010-07-04T00:00:00.A", "2010-07-04T00:00:00.Z",
9108                        "2010-07-04T00:00:00.0000000A", "2010-07-04T00:00:00.00000000A",
9109                        "2010-07-04T00:00:00+", "2010-07-04T00:00:00-",
9110                        "2010-07-04T00:00:00:", "2010-07-04T00:00:00-:", "2010-07-04T00:00:00+:",
9111                        "2010-07-04T00:00:00-1:", "2010-07-04T00:00:00+1:", "2010-07-04T00:00:00+1:0",
9112                        "2010-07-04T00:00:00-12.00", "2010-07-04T00:00:00+12.00",
9113                        "2010-07-04T00:00:00-8", "2010-07-04T00:00:00+8",
9114                        "20100704T000000-800", "20100704T000000+800",
9115                        "20100704T000000-080", "20100704T000000+080",
9116                        "20100704T000000-2400", "20100704T000000+2400",
9117                        "20100704T000000-1260", "20100704T000000+1260",
9118                        "20100704T000000.0-800", "20100704T000000.0+800",
9119                        "20100704T000000.0-8", "20100704T000000.0+8",
9120                        "20100704T000000.0-080", "20100704T000000.0+080",
9121                        "20100704T000000.0-2400", "20100704T000000.0+2400",
9122                        "20100704T000000.0-1260", "20100704T000000.0+1260",
9123                        "2010-07-04T00:00:00-8:00", "2010-07-04T00:00:00+8:00",
9124                        "2010-07-04T00:00:00-24:00", "2010-07-04T00:00:00+24:00",
9125                        "2010-07-04T00:00:00-12:60", "2010-07-04T00:00:00+12:60",
9126                        "2010-07-04T00:00:00.0-8:00", "2010-07-04T00:00:00.0+8:00",
9127                        "2010-07-04T00:00:00.0-8", "2010-07-04T00:00:00.0+8",
9128                        "2010-07-04T00:00:00.0-24:00", "2010-07-04T00:00:00.0+24:00",
9129                        "2010-07-04T00:00:00.0-12:60", "2010-07-04T00:00:00.0+12:60",
9130                        "2010-Jul-0400:00:00", "2010-Jul-04t00:00:00",
9131                        "2010-Jul-04 00:00:00.", "2010-Jul-04 00:00:00.0",
9132                        "20101222T172201", "2010-Dec-22 17:22:01"])
9133         {
9134             assertThrown!DateTimeException(SysTime.fromISOExtString(str), format("[%s]", str));
9135         }
9136 
9137         static void test(string str, SysTime st, size_t line = __LINE__)
9138         {
9139             if (SysTime.fromISOExtString(str) != st)
9140                 throw new AssertError("unittest failure", __FILE__, line);
9141         }
9142 
9143         test("2010-12-22T17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 01)));
9144         test("1999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9145         test("-1999-07-06T12:30:33", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
9146         test("+01999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9147         test("1999-07-06T12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9148         test(" 1999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9149         test(" 1999-07-06T12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9150 
9151         test("1907-07-07T12:12:12.0", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
9152         test("1907-07-07T12:12:12.0000000", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
9153         test("1907-07-07T12:12:12.0000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1)));
9154         test("2010-07-04T00:00:00.00000000", SysTime(Date(2010, 07, 04)));
9155         test("2010-07-04T00:00:00.00000009", SysTime(Date(2010, 07, 04)));
9156         test("2010-07-04T00:00:00.00000019", SysTime(DateTime(2010, 07, 04), hnsecs(1)));
9157         test("1907-07-07T12:12:12.000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
9158         test("1907-07-07T12:12:12.0000010", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
9159         test("1907-07-07T12:12:12.001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
9160         test("1907-07-07T12:12:12.0010000", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
9161 
9162         auto west60 = new immutable SimpleTimeZone(hours(-1));
9163         auto west90 = new immutable SimpleTimeZone(minutes(-90));
9164         auto west480 = new immutable SimpleTimeZone(hours(-8));
9165         auto east60 = new immutable SimpleTimeZone(hours(1));
9166         auto east90 = new immutable SimpleTimeZone(minutes(90));
9167         auto east480 = new immutable SimpleTimeZone(hours(8));
9168 
9169         test("2010-12-22T17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC()));
9170         test("2010-12-22T17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
9171         test("2010-12-22T17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
9172         test("2010-12-22T17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90));
9173         test("2010-12-22T17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480));
9174         test("2010-12-22T17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
9175         test("2010-12-22T17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
9176         test("2010-12-22T17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
9177         test("2010-12-22T17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480));
9178 
9179         test("2010-11-03T06:51:06.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
9180         test("2010-12-22T17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_341_200), UTC()));
9181         test("2010-12-22T17:22:01.23112-01:00",
9182              SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60));
9183         test("2010-12-22T17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), west60));
9184         test("2010-12-22T17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90));
9185         test("2010-12-22T17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480));
9186         test("2010-12-22T17:22:01.1234567+01:00",
9187              SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60));
9188         test("2010-12-22T17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
9189         test("2010-12-22T17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
9190         test("2010-12-22T17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480));
9191 
9192         static void testScope(scope ref string str) @safe
9193         {
9194             auto result = SysTime.fromISOExtString(str);
9195         }
9196     }
9197 
9198     // https://issues.dlang.org/show_bug.cgi?id=17801
9199     @safe unittest
9200     {
9201         import core.time;
9202         import std.conv : to;
9203         import std.meta : AliasSeq;
9204         static foreach (C; AliasSeq!(char, wchar, dchar))
9205         {
9206             static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
9207             {
9208                 assert(SysTime.fromISOExtString(to!S("2012-12-21T14:15:16Z")) ==
9209                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
9210             }
9211         }
9212     }
9213 
9214 
9215     /++
9216         Creates a $(LREF SysTime) from a string with the format
9217         YYYY-MM-DD HH:MM:SS.FFFFFFFTZ (where F is fractional seconds is the
9218         time zone). Whitespace is stripped from the given string.
9219 
9220         The exact format is exactly as described in `toSimpleString` except
9221         that trailing zeroes are permitted - including having fractional seconds
9222         with all zeroes. However, a decimal point with nothing following it is
9223         invalid. Also, while $(LREF toSimpleString) will never generate a
9224         string with more than 7 digits in the fractional seconds (because that's
9225         the limit with hecto-nanosecond precision), it will allow more than 7
9226         digits in order to read strings from other sources that have higher
9227         precision (however, any digits beyond 7 will be truncated).
9228 
9229         If there is no time zone in the string, then
9230         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
9231         then `UTC` is used. Otherwise, a
9232         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
9233         given offset from UTC is used. To get the returned $(LREF SysTime) to be
9234         a particular time zone, pass in that time zone and the $(LREF SysTime)
9235         to be returned will be converted to that time zone (though it will still
9236         be read in as whatever time zone is in its string).
9237 
9238         The accepted formats for time zone offsets are +HH, -HH, +HH:MM, and
9239         -HH:MM.
9240 
9241         Params:
9242             simpleString = A string formatted in the way that
9243                            `toSimpleString` formats dates and times.
9244             tz           = The time zone to convert the given time to (no
9245                            conversion occurs if null).
9246 
9247         Throws:
9248             $(REF DateTimeException,std,datetime,date) if the given string is
9249             not in the ISO format or if the resulting $(LREF SysTime) would not
9250             be valid.
9251       +/
9252     static SysTime fromSimpleString(S)(scope const S simpleString, immutable TimeZone tz = null) @safe
9253         if (isSomeString!(S))
9254     {
9255         import std.algorithm.searching : find;
9256         import std.conv : to;
9257         import std..string : strip, indexOf;
9258 
9259         auto str = strip(simpleString);
9260 
9261         auto spaceIndex = str.indexOf(' ');
9262         enforce(spaceIndex != -1, new DateTimeException(format("Invalid Simple String: %s", simpleString)));
9263 
9264         auto found = str[spaceIndex + 1 .. $].find('.', 'Z', '+', '-');
9265         auto dateTimeStr = str[0 .. $ - found[0].length];
9266 
9267         typeof(str) fracSecStr;
9268         typeof(str) zoneStr;
9269 
9270         if (found[1] != 0)
9271         {
9272             if (found[1] == 1)
9273             {
9274                 auto foundTZ = found[0].find('Z', '+', '-');
9275 
9276                 if (foundTZ[1] != 0)
9277                 {
9278                     fracSecStr = found[0][0 .. $ - foundTZ[0].length];
9279                     zoneStr = foundTZ[0];
9280                 }
9281                 else
9282                     fracSecStr = found[0];
9283             }
9284             else
9285                 zoneStr = found[0];
9286         }
9287 
9288         try
9289         {
9290             auto dateTime = DateTime.fromSimpleString(dateTimeStr);
9291             auto fracSec = fracSecsFromISOString(fracSecStr);
9292             Rebindable!(immutable TimeZone) parsedZone;
9293 
9294             if (zoneStr.empty)
9295                 parsedZone = LocalTime();
9296             else if (zoneStr == "Z")
9297                 parsedZone = UTC();
9298             else
9299                 parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
9300 
9301             auto retval = SysTime(dateTime, fracSec, parsedZone);
9302 
9303             if (tz !is null)
9304                 retval.timezone = tz;
9305 
9306             return retval;
9307         }
9308         catch (DateTimeException dte)
9309             throw new DateTimeException(format("Invalid Simple String: %s", simpleString));
9310     }
9311 
9312     ///
9313     @safe unittest
9314     {
9315         import core.time : hours, msecs, usecs, hnsecs;
9316         import std.datetime.date : DateTime;
9317         import std.datetime.timezone : SimpleTimeZone, UTC;
9318 
9319         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12") ==
9320                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9321 
9322         assert(SysTime.fromSimpleString("1998-Dec-25 02:15:00.007") ==
9323                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
9324 
9325         assert(SysTime.fromSimpleString("0000-Jan-05 23:09:59.00002") ==
9326                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
9327 
9328         assert(SysTime.fromSimpleString("2013-Feb-07 04:39:37.000050392") ==
9329                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
9330 
9331         assert(SysTime.fromSimpleString("-0004-Jan-05 00:00:02") ==
9332                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
9333 
9334         assert(SysTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") ==
9335                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9336 
9337         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12Z") ==
9338                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
9339 
9340         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12-08:00") ==
9341                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9342                        new immutable SimpleTimeZone(hours(-8))));
9343 
9344         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12+08:00") ==
9345                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9346                        new immutable SimpleTimeZone(hours(8))));
9347     }
9348 
9349     @safe unittest
9350     {
9351         import core.time;
9352         foreach (str; ["", "20100704000000", "20100704 000000",
9353                        "20100704t000000", "20100704T000000.", "20100704T000000.0",
9354                        "2010-07-0400:00:00", "2010-07-04 00:00:00", "2010-07-04t00:00:00",
9355                        "2010-07-04T00:00:00.", "2010-07-04T00:00:00.0",
9356                        "2010-Jul-0400:00:00", "2010-Jul-04t00:00:00", "2010-Jul-04T00:00:00",
9357                        "2010-Jul-04 00:00:00.", "2010-Jul-04 00:00:00.A", "2010-Jul-04 00:00:00.Z",
9358                        "2010-Jul-04 00:00:00.0000000A", "2010-Jul-04 00:00:00.00000000A",
9359                        "2010-Jul-04 00:00:00+", "2010-Jul-04 00:00:00-",
9360                        "2010-Jul-04 00:00:00:", "2010-Jul-04 00:00:00-:",
9361                        "2010-Jul-04 00:00:00+:", "2010-Jul-04 00:00:00-1:",
9362                        "2010-Jul-04 00:00:00+1:", "2010-Jul-04 00:00:00+1:0",
9363                        "2010-Jul-04 00:00:00-12.00", "2010-Jul-04 00:00:00+12.00",
9364                        "2010-Jul-04 00:00:00-8", "2010-Jul-04 00:00:00+8",
9365                        "20100704T000000-800", "20100704T000000+800",
9366                        "20100704T000000-080", "20100704T000000+080",
9367                        "20100704T000000-2400", "20100704T000000+2400",
9368                        "20100704T000000-1260", "20100704T000000+1260",
9369                        "20100704T000000.0-800", "20100704T000000.0+800",
9370                        "20100704T000000.0-8", "20100704T000000.0+8",
9371                        "20100704T000000.0-080", "20100704T000000.0+080",
9372                        "20100704T000000.0-2400", "20100704T000000.0+2400",
9373                        "20100704T000000.0-1260", "20100704T000000.0+1260",
9374                        "2010-Jul-04 00:00:00-8:00", "2010-Jul-04 00:00:00+8:00",
9375                        "2010-Jul-04 00:00:00-08:0", "2010-Jul-04 00:00:00+08:0",
9376                        "2010-Jul-04 00:00:00-24:00", "2010-Jul-04 00:00:00+24:00",
9377                        "2010-Jul-04 00:00:00-12:60", "2010-Jul-04 00:00:00+24:60",
9378                        "2010-Jul-04 00:00:00.0-8:00", "2010-Jul-04 00:00:00+8:00",
9379                        "2010-Jul-04 00:00:00.0-8", "2010-Jul-04 00:00:00.0+8",
9380                        "2010-Jul-04 00:00:00.0-08:0", "2010-Jul-04 00:00:00.0+08:0",
9381                        "2010-Jul-04 00:00:00.0-24:00", "2010-Jul-04 00:00:00.0+24:00",
9382                        "2010-Jul-04 00:00:00.0-12:60", "2010-Jul-04 00:00:00.0+24:60",
9383                        "20101222T172201", "2010-12-22T172201"])
9384         {
9385             assertThrown!DateTimeException(SysTime.fromSimpleString(str), format("[%s]", str));
9386         }
9387 
9388         static void test(string str, SysTime st, size_t line = __LINE__)
9389         {
9390             if (SysTime.fromSimpleString(str) != st)
9391                 throw new AssertError("unittest failure", __FILE__, line);
9392         }
9393 
9394         test("2010-Dec-22 17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 01)));
9395         test("1999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9396         test("-1999-Jul-06 12:30:33", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
9397         test("+01999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9398         test("1999-Jul-06 12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9399         test(" 1999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9400         test(" 1999-Jul-06 12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9401 
9402         test("1907-Jul-07 12:12:12.0", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
9403         test("1907-Jul-07 12:12:12.0000000", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
9404         test("2010-Jul-04 00:00:00.00000000", SysTime(Date(2010, 07, 04)));
9405         test("2010-Jul-04 00:00:00.00000009", SysTime(Date(2010, 07, 04)));
9406         test("2010-Jul-04 00:00:00.00000019", SysTime(DateTime(2010, 07, 04), hnsecs(1)));
9407         test("1907-Jul-07 12:12:12.0000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1)));
9408         test("1907-Jul-07 12:12:12.000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
9409         test("1907-Jul-07 12:12:12.0000010", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
9410         test("1907-Jul-07 12:12:12.001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
9411         test("1907-Jul-07 12:12:12.0010000", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
9412 
9413         auto west60 = new immutable SimpleTimeZone(hours(-1));
9414         auto west90 = new immutable SimpleTimeZone(minutes(-90));
9415         auto west480 = new immutable SimpleTimeZone(hours(-8));
9416         auto east60 = new immutable SimpleTimeZone(hours(1));
9417         auto east90 = new immutable SimpleTimeZone(minutes(90));
9418         auto east480 = new immutable SimpleTimeZone(hours(8));
9419 
9420         test("2010-Dec-22 17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC()));
9421         test("2010-Dec-22 17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
9422         test("2010-Dec-22 17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
9423         test("2010-Dec-22 17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90));
9424         test("2010-Dec-22 17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480));
9425         test("2010-Dec-22 17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
9426         test("2010-Dec-22 17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
9427         test("2010-Dec-22 17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
9428         test("2010-Dec-22 17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480));
9429 
9430         test("2010-Nov-03 06:51:06.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
9431         test("2010-Dec-22 17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_341_200), UTC()));
9432         test("2010-Dec-22 17:22:01.23112-01:00",
9433              SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60));
9434         test("2010-Dec-22 17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), west60));
9435         test("2010-Dec-22 17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90));
9436         test("2010-Dec-22 17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480));
9437         test("2010-Dec-22 17:22:01.1234567+01:00",
9438              SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60));
9439         test("2010-Dec-22 17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
9440         test("2010-Dec-22 17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
9441         test("2010-Dec-22 17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480));
9442 
9443         static void testScope(scope ref string str) @safe
9444         {
9445             auto result = SysTime.fromSimpleString(str);
9446         }
9447     }
9448 
9449     // https://issues.dlang.org/show_bug.cgi?id=17801
9450     @safe unittest
9451     {
9452         import core.time;
9453         import std.conv : to;
9454         import std.meta : AliasSeq;
9455         static foreach (C; AliasSeq!(char, wchar, dchar))
9456         {
9457             static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
9458             {
9459                 assert(SysTime.fromSimpleString(to!S("2012-Dec-21 14:15:16Z")) ==
9460                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
9461             }
9462         }
9463     }
9464 
9465 
9466     /++
9467         Returns the $(LREF SysTime) farthest in the past which is representable
9468         by $(LREF SysTime).
9469 
9470         The $(LREF SysTime) which is returned is in UTC.
9471       +/
9472     @property static SysTime min() @safe pure nothrow
9473     {
9474         return SysTime(long.min, UTC());
9475     }
9476 
9477     @safe unittest
9478     {
9479         assert(SysTime.min.year < 0);
9480         assert(SysTime.min < SysTime.max);
9481     }
9482 
9483 
9484     /++
9485         Returns the $(LREF SysTime) farthest in the future which is representable
9486         by $(LREF SysTime).
9487 
9488         The $(LREF SysTime) which is returned is in UTC.
9489       +/
9490     @property static SysTime max() @safe pure nothrow
9491     {
9492         return SysTime(long.max, UTC());
9493     }
9494 
9495     @safe unittest
9496     {
9497         assert(SysTime.max.year > 0);
9498         assert(SysTime.max > SysTime.min);
9499     }
9500 
9501 
9502 private:
9503 
9504     /+
9505         Returns `stdTime` converted to $(LREF SysTime)'s time zone.
9506       +/
9507     @property long adjTime() @safe const nothrow scope
9508     {
9509         return _timezone.utcToTZ(_stdTime);
9510     }
9511 
9512 
9513     /+
9514         Converts the given hnsecs from $(LREF SysTime)'s time zone to std time.
9515       +/
9516     @property void adjTime(long adjTime) @safe nothrow scope
9517     {
9518         _stdTime = _timezone.tzToUTC(adjTime);
9519     }
9520 
9521 
9522     final class InitTimeZone : TimeZone
9523     {
9524     public:
9525 
9526         static immutable(InitTimeZone) opCall() @safe pure nothrow @nogc { return _initTimeZone; }
9527 
9528         @property override bool hasDST() @safe const nothrow @nogc { return false; }
9529 
9530         override bool dstInEffect(long stdTime) @safe const nothrow @nogc { return false; }
9531 
9532         override long utcToTZ(long stdTime) @safe const nothrow @nogc { return 0; }
9533 
9534         override long tzToUTC(long adjTime) @safe const nothrow @nogc { return 0; }
9535 
9536         override Duration utcOffsetAt(long stdTime) @safe const nothrow @nogc { return Duration.zero; }
9537 
9538     private:
9539 
9540         this() @safe immutable pure
9541         {
9542             super("SysTime.init's timezone", "SysTime.init's timezone", "SysTime.init's timezone");
9543         }
9544 
9545         static immutable InitTimeZone _initTimeZone = new immutable(InitTimeZone);
9546     }
9547 
9548     // https://issues.dlang.org/show_bug.cgi?id=17732
9549     @safe unittest
9550     {
9551         assert(SysTime.init.timezone is InitTimeZone());
9552         assert(SysTime.init.toISOString() == "00010101T000000+00:00");
9553         assert(SysTime.init.toISOExtString() == "0001-01-01T00:00:00+00:00");
9554         assert(SysTime.init.toSimpleString() == "0001-Jan-01 00:00:00+00:00");
9555         assert(SysTime.init.toString() == "0001-Jan-01 00:00:00+00:00");
9556     }
9557 
9558     // Assigning a value to _timezone in SysTime.init currently doesn't work due
9559     // to https://issues.dlang.org/show_bug.cgi?id=17740. So, to hack around
9560     // that problem, these accessors have been added so that we can insert a
9561     // runtime check for null and then use InitTimeZone for SysTime.init (which
9562     // which is the only case where _timezone would be null). This thus fixes
9563     // the problem with segfaulting when using SysTime.init but at the cost of
9564     // what should be an unnecessary null check. Once 17740 has finally been
9565     // fixed, _timezoneStorage should be removed, these accessors should be
9566     // removed, and the _timezone variable declaration should be restored.
9567     pragma(inline, true) @property _timezone() @safe const pure nothrow @nogc
9568     {
9569         return _timezoneStorage is null ? InitTimeZone() : _timezoneStorage;
9570     }
9571 
9572     pragma(inline, true) @property void _timezone(immutable TimeZone tz) @safe pure nothrow @nogc scope
9573     {
9574         _timezoneStorage = tz;
9575     }
9576 
9577 
9578     long  _stdTime;
9579     Rebindable!(immutable TimeZone) _timezoneStorage;
9580     //Rebindable!(immutable TimeZone) _timezone = InitTimeZone();
9581 }
9582 
9583 ///
9584 @safe unittest
9585 {
9586     import core.time : days, hours, seconds;
9587     import std.datetime.date : DateTime;
9588     import std.datetime.timezone : SimpleTimeZone, UTC;
9589 
9590     // make a specific point in time in the UTC timezone
9591     auto st = SysTime(DateTime(2018, 1, 1, 10, 30, 0), UTC());
9592     // make a specific point in time in the New York timezone
9593     auto ny = SysTime(
9594         DateTime(2018, 1, 1, 10, 30, 0),
9595         new immutable SimpleTimeZone(-5.hours, "America/New_York")
9596     );
9597 
9598     // ISO standard time strings
9599     assert(st.toISOString() == "20180101T103000Z");
9600     assert(st.toISOExtString() == "2018-01-01T10:30:00Z");
9601 
9602     // add two days and 30 seconds
9603     st += 2.days + 30.seconds;
9604     assert(st.toISOExtString() == "2018-01-03T10:30:30Z");
9605 }
9606 
9607 
9608 /++
9609     Converts from unix time (which uses midnight, January 1st, 1970 UTC as its
9610     epoch and seconds as its units) to "std time" (which uses midnight,
9611     January 1st, 1 A.D. UTC and hnsecs as its units).
9612 
9613     The C standard does not specify the representation of time_t, so it is
9614     implementation defined. On POSIX systems, unix time is equivalent to
9615     time_t, but that's not necessarily true on other systems (e.g. it is
9616     not true for the Digital Mars C runtime). So, be careful when using unix
9617     time with C functions on non-POSIX systems.
9618 
9619     "std time"'s epoch is based on the Proleptic Gregorian Calendar per ISO
9620     8601 and is what $(LREF SysTime) uses internally. However, holding the time
9621     as an integer in hnsecs since that epoch technically isn't actually part of
9622     the standard, much as it's based on it, so the name "std time" isn't
9623     particularly good, but there isn't an official name for it. C# uses "ticks"
9624     for the same thing, but they aren't actually clock ticks, and the term
9625     "ticks" $(I is) used for actual clock ticks for $(REF MonoTime, core,time),
9626     so it didn't make sense to use the term ticks here. So, for better or worse,
9627     std.datetime uses the term "std time" for this.
9628 
9629     Params:
9630         unixTime = The unix time to convert.
9631 
9632     See_Also:
9633         SysTime.fromUnixTime
9634   +/
9635 long unixTimeToStdTime(long unixTime) @safe pure nothrow @nogc
9636 {
9637     return 621_355_968_000_000_000L + convert!("seconds", "hnsecs")(unixTime);
9638 }
9639 
9640 ///
9641 @safe unittest
9642 {
9643     import std.datetime.date : DateTime;
9644     import std.datetime.timezone : UTC;
9645 
9646     // Midnight, January 1st, 1970
9647     assert(unixTimeToStdTime(0) == 621_355_968_000_000_000L);
9648     assert(SysTime(unixTimeToStdTime(0)) ==
9649            SysTime(DateTime(1970, 1, 1), UTC()));
9650 
9651     assert(unixTimeToStdTime(int.max) == 642_830_804_470_000_000L);
9652     assert(SysTime(unixTimeToStdTime(int.max)) ==
9653            SysTime(DateTime(2038, 1, 19, 3, 14, 07), UTC()));
9654 
9655     assert(unixTimeToStdTime(-127_127) == 621_354_696_730_000_000L);
9656     assert(SysTime(unixTimeToStdTime(-127_127)) ==
9657            SysTime(DateTime(1969, 12, 30, 12, 41, 13), UTC()));
9658 }
9659 
9660 @safe unittest
9661 {
9662     // Midnight, January 2nd, 1970
9663     assert(unixTimeToStdTime(86_400) == 621_355_968_000_000_000L + 864_000_000_000L);
9664     // Midnight, December 31st, 1969
9665     assert(unixTimeToStdTime(-86_400) == 621_355_968_000_000_000L - 864_000_000_000L);
9666 
9667     assert(unixTimeToStdTime(0) == (Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs");
9668     assert(unixTimeToStdTime(0) == (DateTime(1970, 1, 1) - DateTime(1, 1, 1)).total!"hnsecs");
9669 
9670     foreach (dt; [DateTime(2010, 11, 1, 19, 5, 22), DateTime(1952, 7, 6, 2, 17, 9)])
9671         assert(unixTimeToStdTime((dt - DateTime(1970, 1, 1)).total!"seconds") == (dt - DateTime.init).total!"hnsecs");
9672 }
9673 
9674 
9675 /++
9676     Converts std time (which uses midnight, January 1st, 1 A.D. UTC as its epoch
9677     and hnsecs as its units) to unix time (which uses midnight, January 1st,
9678     1970 UTC as its epoch and seconds as its units).
9679 
9680     The C standard does not specify the representation of time_t, so it is
9681     implementation defined. On POSIX systems, unix time is equivalent to
9682     time_t, but that's not necessarily true on other systems (e.g. it is
9683     not true for the Digital Mars C runtime). So, be careful when using unix
9684     time with C functions on non-POSIX systems.
9685 
9686     "std time"'s epoch is based on the Proleptic Gregorian Calendar per ISO
9687     8601 and is what $(LREF SysTime) uses internally. However, holding the time
9688     as an integer in hnescs since that epoch technically isn't actually part of
9689     the standard, much as it's based on it, so the name "std time" isn't
9690     particularly good, but there isn't an official name for it. C# uses "ticks"
9691     for the same thing, but they aren't actually clock ticks, and the term
9692     "ticks" $(I is) used for actual clock ticks for $(REF MonoTime, core,time),
9693     so it didn't make sense to use the term ticks here. So, for better or worse,
9694     std.datetime uses the term "std time" for this.
9695 
9696     By default, the return type is time_t (which is normally an alias for
9697     int on 32-bit systems and long on 64-bit systems), but if a different
9698     size is required than either int or long can be passed as a template
9699     argument to get the desired size.
9700 
9701     If the return type is int, and the result can't fit in an int, then the
9702     closest value that can be held in 32 bits will be used (so `int.max`
9703     if it goes over and `int.min` if it goes under). However, no attempt
9704     is made to deal with integer overflow if the return type is long.
9705 
9706     Params:
9707         T = The return type (int or long). It defaults to time_t, which is
9708             normally 32 bits on a 32-bit system and 64 bits on a 64-bit
9709             system.
9710         stdTime = The std time to convert.
9711 
9712     Returns:
9713         A signed integer representing the unix time which is equivalent to
9714         the given std time.
9715 
9716     See_Also:
9717         SysTime.toUnixTime
9718   +/
9719 T stdTimeToUnixTime(T = time_t)(long stdTime) @safe pure nothrow
9720 if (is(T == int) || is(T == long))
9721 {
9722     immutable unixTime = convert!("hnsecs", "seconds")(stdTime - 621_355_968_000_000_000L);
9723 
9724     static assert(is(time_t == int) || is(time_t == long),
9725                   "Currently, std.datetime only supports systems where time_t is int or long");
9726 
9727     static if (is(T == long))
9728         return unixTime;
9729     else static if (is(T == int))
9730     {
9731         if (unixTime > int.max)
9732             return int.max;
9733         return unixTime < int.min ? int.min : cast(int) unixTime;
9734     }
9735     else
9736         static assert(0, "Bug in template constraint. Only int and long allowed.");
9737 }
9738 
9739 ///
9740 @safe unittest
9741 {
9742     // Midnight, January 1st, 1970 UTC
9743     assert(stdTimeToUnixTime(621_355_968_000_000_000L) == 0);
9744 
9745     // 2038-01-19 03:14:07 UTC
9746     assert(stdTimeToUnixTime(642_830_804_470_000_000L) == int.max);
9747 }
9748 
9749 @safe unittest
9750 {
9751     enum unixEpochAsStdTime = (Date(1970, 1, 1) - Date.init).total!"hnsecs";
9752 
9753     assert(stdTimeToUnixTime(unixEpochAsStdTime) == 0);  // Midnight, January 1st, 1970
9754     assert(stdTimeToUnixTime(unixEpochAsStdTime + 864_000_000_000L) == 86_400);  // Midnight, January 2nd, 1970
9755     assert(stdTimeToUnixTime(unixEpochAsStdTime - 864_000_000_000L) == -86_400);  // Midnight, December 31st, 1969
9756 
9757     assert(stdTimeToUnixTime((Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs") == 0);
9758     assert(stdTimeToUnixTime((DateTime(1970, 1, 1) - DateTime(1, 1, 1)).total!"hnsecs") == 0);
9759 
9760     foreach (dt; [DateTime(2010, 11, 1, 19, 5, 22), DateTime(1952, 7, 6, 2, 17, 9)])
9761         assert(stdTimeToUnixTime((dt - DateTime.init).total!"hnsecs") == (dt - DateTime(1970, 1, 1)).total!"seconds");
9762 
9763     enum max = convert!("seconds", "hnsecs")(int.max);
9764     enum min = convert!("seconds", "hnsecs")(int.min);
9765     enum one = convert!("seconds", "hnsecs")(1);
9766 
9767     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max) == int.max);
9768     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max) == int.max);
9769 
9770     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max + one) == int.max + 1L);
9771     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max + one) == int.max);
9772     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max + 9_999_999) == int.max);
9773     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max + 9_999_999) == int.max);
9774 
9775     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min) == int.min);
9776     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min) == int.min);
9777 
9778     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min - one) == int.min - 1L);
9779     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min - one) == int.min);
9780     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min - 9_999_999) == int.min);
9781     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min - 9_999_999) == int.min);
9782 }
9783 
9784 
9785 version (StdDdoc)
9786 {
9787     version (Windows)
9788     {}
9789     else
9790     {
9791         alias SYSTEMTIME = void*;
9792         alias FILETIME = void*;
9793     }
9794 
9795     /++
9796         $(BLUE This function is Windows-Only.)
9797 
9798         Converts a `SYSTEMTIME` struct to a $(LREF SysTime).
9799 
9800         Params:
9801             st = The `SYSTEMTIME` struct to convert.
9802             tz = The time zone that the time in the `SYSTEMTIME` struct is
9803                  assumed to be (if the `SYSTEMTIME` was supplied by a Windows
9804                  system call, the `SYSTEMTIME` will either be in local time
9805                  or UTC, depending on the call).
9806 
9807         Throws:
9808             $(REF DateTimeException,std,datetime,date) if the given
9809             `SYSTEMTIME` will not fit in a $(LREF SysTime), which is highly
9810             unlikely to happen given that `SysTime.max` is in 29,228 A.D. and
9811             the maximum `SYSTEMTIME` is in 30,827 A.D.
9812       +/
9813     SysTime SYSTEMTIMEToSysTime(const scope SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) @safe;
9814 
9815 
9816     /++
9817         $(BLUE This function is Windows-Only.)
9818 
9819         Converts a $(LREF SysTime) to a `SYSTEMTIME` struct.
9820 
9821         The `SYSTEMTIME` which is returned will be set using the given
9822         $(LREF SysTime)'s time zone, so to get the `SYSTEMTIME` in
9823         UTC, set the $(LREF SysTime)'s time zone to UTC.
9824 
9825         Params:
9826             sysTime = The $(LREF SysTime) to convert.
9827 
9828         Throws:
9829             $(REF DateTimeException,std,datetime,date) if the given
9830             $(LREF SysTime) will not fit in a `SYSTEMTIME`. This will only
9831             happen if the $(LREF SysTime)'s date is prior to 1601 A.D.
9832       +/
9833     SYSTEMTIME SysTimeToSYSTEMTIME(scope SysTime sysTime) @safe;
9834 
9835 
9836     /++
9837         $(BLUE This function is Windows-Only.)
9838 
9839         Converts a `FILETIME` struct to the number of hnsecs since midnight,
9840         January 1st, 1 A.D.
9841 
9842         Params:
9843             ft = The `FILETIME` struct to convert.
9844 
9845         Throws:
9846             $(REF DateTimeException,std,datetime,date) if the given
9847             `FILETIME` cannot be represented as the return value.
9848       +/
9849     long FILETIMEToStdTime(scope const FILETIME* ft) @safe;
9850 
9851 
9852     /++
9853         $(BLUE This function is Windows-Only.)
9854 
9855         Converts a `FILETIME` struct to a $(LREF SysTime).
9856 
9857         Params:
9858             ft = The `FILETIME` struct to convert.
9859             tz = The time zone that the $(LREF SysTime) will be in
9860                  (`FILETIME`s are in UTC).
9861 
9862         Throws:
9863             $(REF DateTimeException,std,datetime,date) if the given
9864             `FILETIME` will not fit in a $(LREF SysTime).
9865       +/
9866     SysTime FILETIMEToSysTime(scope const FILETIME* ft, immutable TimeZone tz = LocalTime()) @safe;
9867 
9868 
9869     /++
9870         $(BLUE This function is Windows-Only.)
9871 
9872         Converts a number of hnsecs since midnight, January 1st, 1 A.D. to a
9873         `FILETIME` struct.
9874 
9875         Params:
9876             stdTime = The number of hnsecs since midnight, January 1st, 1 A.D.
9877                       UTC.
9878 
9879         Throws:
9880             $(REF DateTimeException,std,datetime,date) if the given value will
9881             not fit in a `FILETIME`.
9882       +/
9883     FILETIME stdTimeToFILETIME(long stdTime) @safe;
9884 
9885 
9886     /++
9887         $(BLUE This function is Windows-Only.)
9888 
9889         Converts a $(LREF SysTime) to a `FILETIME` struct.
9890 
9891         `FILETIME`s are always in UTC.
9892 
9893         Params:
9894             sysTime = The $(LREF SysTime) to convert.
9895 
9896         Throws:
9897             $(REF DateTimeException,std,datetime,date) if the given
9898             $(LREF SysTime) will not fit in a `FILETIME`.
9899       +/
9900     FILETIME SysTimeToFILETIME(scope SysTime sysTime) @safe;
9901 }
9902 else version (Windows)
9903 {
9904     SysTime SYSTEMTIMEToSysTime(const scope SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) @safe
9905     {
9906         const max = SysTime.max;
9907 
9908         static void throwLaterThanMax()
9909         {
9910             throw new DateTimeException("The given SYSTEMTIME is for a date greater than SysTime.max.");
9911         }
9912 
9913         if (st.wYear > max.year)
9914             throwLaterThanMax();
9915         else if (st.wYear == max.year)
9916         {
9917             if (st.wMonth > max.month)
9918                 throwLaterThanMax();
9919             else if (st.wMonth == max.month)
9920             {
9921                 if (st.wDay > max.day)
9922                     throwLaterThanMax();
9923                 else if (st.wDay == max.day)
9924                 {
9925                     if (st.wHour > max.hour)
9926                         throwLaterThanMax();
9927                     else if (st.wHour == max.hour)
9928                     {
9929                         if (st.wMinute > max.minute)
9930                             throwLaterThanMax();
9931                         else if (st.wMinute == max.minute)
9932                         {
9933                             if (st.wSecond > max.second)
9934                                 throwLaterThanMax();
9935                             else if (st.wSecond == max.second)
9936                             {
9937                                 if (st.wMilliseconds > max.fracSecs.total!"msecs")
9938                                     throwLaterThanMax();
9939                             }
9940                         }
9941                     }
9942                 }
9943             }
9944         }
9945 
9946         auto dt = DateTime(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
9947 
9948         import core.time : msecs;
9949         return SysTime(dt, msecs(st.wMilliseconds), tz);
9950     }
9951 
9952     @system unittest
9953     {
9954         auto sysTime = Clock.currTime(UTC());
9955         SYSTEMTIME st = void;
9956         GetSystemTime(&st);
9957         auto converted = SYSTEMTIMEToSysTime(&st, UTC());
9958         import core.time : abs;
9959         assert(abs((converted - sysTime)) <= dur!"seconds"(2));
9960 
9961         static void testScope(scope SYSTEMTIME* st) @safe
9962         {
9963             auto result = SYSTEMTIMEToSysTime(st);
9964         }
9965     }
9966 
9967 
9968     SYSTEMTIME SysTimeToSYSTEMTIME(scope SysTime sysTime) @safe
9969     {
9970         immutable dt = cast(DateTime) sysTime;
9971 
9972         if (dt.year < 1601)
9973             throw new DateTimeException("SYSTEMTIME cannot hold dates prior to the year 1601.");
9974 
9975         SYSTEMTIME st;
9976 
9977         st.wYear = dt.year;
9978         st.wMonth = dt.month;
9979         st.wDayOfWeek = dt.dayOfWeek;
9980         st.wDay = dt.day;
9981         st.wHour = dt.hour;
9982         st.wMinute = dt.minute;
9983         st.wSecond = dt.second;
9984         st.wMilliseconds = cast(ushort) sysTime.fracSecs.total!"msecs";
9985 
9986         return st;
9987     }
9988 
9989     @system unittest
9990     {
9991         SYSTEMTIME st = void;
9992         GetSystemTime(&st);
9993         auto sysTime = SYSTEMTIMEToSysTime(&st, UTC());
9994 
9995         SYSTEMTIME result = SysTimeToSYSTEMTIME(sysTime);
9996 
9997         assert(st.wYear == result.wYear);
9998         assert(st.wMonth == result.wMonth);
9999         assert(st.wDayOfWeek == result.wDayOfWeek);
10000         assert(st.wDay == result.wDay);
10001         assert(st.wHour == result.wHour);
10002         assert(st.wMinute == result.wMinute);
10003         assert(st.wSecond == result.wSecond);
10004         assert(st.wMilliseconds == result.wMilliseconds);
10005 
10006         static void testScope(scope ref SysTime st) @safe
10007         {
10008             auto result = SysTimeToSYSTEMTIME(st);
10009         }
10010     }
10011 
10012     private enum hnsecsFrom1601 = 504_911_232_000_000_000L;
10013 
10014     long FILETIMEToStdTime(scope const FILETIME* ft) @safe
10015     {
10016         ULARGE_INTEGER ul;
10017         ul.HighPart = ft.dwHighDateTime;
10018         ul.LowPart = ft.dwLowDateTime;
10019         ulong tempHNSecs = ul.QuadPart;
10020 
10021         if (tempHNSecs > long.max - hnsecsFrom1601)
10022             throw new DateTimeException("The given FILETIME cannot be represented as a stdTime value.");
10023 
10024         return cast(long) tempHNSecs + hnsecsFrom1601;
10025     }
10026 
10027     SysTime FILETIMEToSysTime(scope const FILETIME* ft, immutable TimeZone tz = LocalTime()) @safe
10028     {
10029         auto sysTime = SysTime(FILETIMEToStdTime(ft), UTC());
10030         sysTime.timezone = tz;
10031         return sysTime;
10032     }
10033 
10034     @system unittest
10035     {
10036         auto sysTime = Clock.currTime(UTC());
10037         SYSTEMTIME st = void;
10038         GetSystemTime(&st);
10039 
10040         FILETIME ft = void;
10041         SystemTimeToFileTime(&st, &ft);
10042 
10043         auto converted = FILETIMEToSysTime(&ft);
10044 
10045         import core.time : abs;
10046         assert(abs((converted - sysTime)) <= dur!"seconds"(2));
10047 
10048         static void testScope(scope FILETIME* ft) @safe
10049         {
10050             auto result = FILETIMEToSysTime(ft);
10051         }
10052     }
10053 
10054 
10055     FILETIME stdTimeToFILETIME(long stdTime) @safe
10056     {
10057         if (stdTime < hnsecsFrom1601)
10058             throw new DateTimeException("The given stdTime value cannot be represented as a FILETIME.");
10059 
10060         ULARGE_INTEGER ul;
10061         ul.QuadPart = cast(ulong) stdTime - hnsecsFrom1601;
10062 
10063         FILETIME ft;
10064         ft.dwHighDateTime = ul.HighPart;
10065         ft.dwLowDateTime = ul.LowPart;
10066 
10067         return ft;
10068     }
10069 
10070     FILETIME SysTimeToFILETIME(scope SysTime sysTime) @safe
10071     {
10072         return stdTimeToFILETIME(sysTime.stdTime);
10073     }
10074 
10075     @system unittest
10076     {
10077         SYSTEMTIME st = void;
10078         GetSystemTime(&st);
10079 
10080         FILETIME ft = void;
10081         SystemTimeToFileTime(&st, &ft);
10082         auto sysTime = FILETIMEToSysTime(&ft, UTC());
10083 
10084         FILETIME result = SysTimeToFILETIME(sysTime);
10085 
10086         assert(ft.dwLowDateTime == result.dwLowDateTime);
10087         assert(ft.dwHighDateTime == result.dwHighDateTime);
10088 
10089         static void testScope(scope ref SysTime st) @safe
10090         {
10091             auto result = SysTimeToFILETIME(st);
10092         }
10093     }
10094 }
10095 
10096 
10097 /++
10098     Type representing the DOS file date/time format.
10099   +/
10100 alias DosFileTime = uint;
10101 
10102 /++
10103     Converts from DOS file date/time to $(LREF SysTime).
10104 
10105     Params:
10106         dft = The DOS file time to convert.
10107         tz  = The time zone which the DOS file time is assumed to be in.
10108 
10109     Throws:
10110         $(REF DateTimeException,std,datetime,date) if the `DosFileTime` is
10111         invalid.
10112   +/
10113 SysTime DosFileTimeToSysTime(DosFileTime dft, immutable TimeZone tz = LocalTime()) @safe
10114 {
10115     uint dt = cast(uint) dft;
10116 
10117     if (dt == 0)
10118         throw new DateTimeException("Invalid DosFileTime.");
10119 
10120     int year = ((dt >> 25) & 0x7F) + 1980;
10121     int month = ((dt >> 21) & 0x0F);       // 1 .. 12
10122     int dayOfMonth = ((dt >> 16) & 0x1F);  // 1 .. 31
10123     int hour = (dt >> 11) & 0x1F;          // 0 .. 23
10124     int minute = (dt >> 5) & 0x3F;         // 0 .. 59
10125     int second = (dt << 1) & 0x3E;         // 0 .. 58 (in 2 second increments)
10126 
10127     try
10128         return SysTime(DateTime(year, month, dayOfMonth, hour, minute, second), tz);
10129     catch (DateTimeException dte)
10130         throw new DateTimeException("Invalid DosFileTime", __FILE__, __LINE__, dte);
10131 }
10132 
10133 ///
10134 @safe unittest
10135 {
10136     import std.datetime.date : DateTime;
10137 
10138     assert(DosFileTimeToSysTime(0b00000000001000010000000000000000) == SysTime(DateTime(1980, 1, 1, 0, 0, 0)));
10139     assert(DosFileTimeToSysTime(0b11111111100111111011111101111101) == SysTime(DateTime(2107, 12, 31, 23, 59, 58)));
10140     assert(DosFileTimeToSysTime(0x3E3F8456) == SysTime(DateTime(2011, 1, 31, 16, 34, 44)));
10141 }
10142 
10143 @safe unittest
10144 {
10145     static void testScope(scope ref DosFileTime dft) @safe
10146     {
10147         auto result = DosFileTimeToSysTime(dft);
10148     }
10149 }
10150 
10151 
10152 /++
10153     Converts from $(LREF SysTime) to DOS file date/time.
10154 
10155     Params:
10156         sysTime = The $(LREF SysTime) to convert.
10157 
10158     Throws:
10159         $(REF DateTimeException,std,datetime,date) if the given
10160         $(LREF SysTime) cannot be converted to a `DosFileTime`.
10161   +/
10162 DosFileTime SysTimeToDosFileTime(scope SysTime sysTime) @safe
10163 {
10164     auto dateTime = cast(DateTime) sysTime;
10165 
10166     if (dateTime.year < 1980)
10167         throw new DateTimeException("DOS File Times cannot hold dates prior to 1980.");
10168 
10169     if (dateTime.year > 2107)
10170         throw new DateTimeException("DOS File Times cannot hold dates past 2107.");
10171 
10172     uint retval = 0;
10173     retval = (dateTime.year - 1980) << 25;
10174     retval |= (dateTime.month & 0x0F) << 21;
10175     retval |= (dateTime.day & 0x1F) << 16;
10176     retval |= (dateTime.hour & 0x1F) << 11;
10177     retval |= (dateTime.minute & 0x3F) << 5;
10178     retval |= (dateTime.second >> 1) & 0x1F;
10179 
10180     return cast(DosFileTime) retval;
10181 }
10182 
10183 ///
10184 @safe unittest
10185 {
10186     import std.datetime.date : DateTime;
10187 
10188     assert(SysTimeToDosFileTime(SysTime(DateTime(1980, 1, 1, 0, 0, 0))) == 0b00000000001000010000000000000000);
10189     assert(SysTimeToDosFileTime(SysTime(DateTime(2107, 12, 31, 23, 59, 58))) == 0b11111111100111111011111101111101);
10190     assert(SysTimeToDosFileTime(SysTime(DateTime(2011, 1, 31, 16, 34, 44))) == 0x3E3F8456);
10191 }
10192 
10193 @safe unittest
10194 {
10195     static void testScope(scope ref SysTime st) @safe
10196     {
10197         auto result = SysTimeToDosFileTime(st);
10198     }
10199 }
10200 
10201 
10202 /++
10203     The given array of `char` or random-access range of `char` or
10204     `ubyte` is expected to be in the format specified in
10205     $(HTTP tools.ietf.org/html/rfc5322, RFC 5322) section 3.3 with the
10206     grammar rule $(I date-time). It is the date-time format commonly used in
10207     internet messages such as e-mail and HTTP. The corresponding
10208     $(LREF SysTime) will be returned.
10209 
10210     RFC 822 was the original spec (hence the function's name), whereas RFC 5322
10211     is the current spec.
10212 
10213     The day of the week is ignored beyond verifying that it's a valid day of the
10214     week, as the day of the week can be inferred from the date. It is not
10215     checked whether the given day of the week matches the actual day of the week
10216     of the given date (though it is technically invalid per the spec if the
10217     day of the week doesn't match the actual day of the week of the given date).
10218 
10219     If the time zone is `"-0000"` (or considered to be equivalent to
10220     `"-0000"` by section 4.3 of the spec), a
10221     $(REF SimpleTimeZone,std,datetime,timezone) with a utc offset of `0` is
10222     used rather than $(REF UTC,std,datetime,timezone), whereas `"+0000"` uses
10223     $(REF UTC,std,datetime,timezone).
10224 
10225     Note that because $(LREF SysTime) does not currently support having a second
10226     value of 60 (as is sometimes done for leap seconds), if the date-time value
10227     does have a value of 60 for the seconds, it is treated as 59.
10228 
10229     The one area in which this function violates RFC 5322 is that it accepts
10230     `"\n"` in folding whitespace in the place of `"\r\n"`, because the
10231     HTTP spec requires it.
10232 
10233     Throws:
10234         $(REF DateTimeException,std,datetime,date) if the given string doesn't
10235         follow the grammar for a date-time field or if the resulting
10236         $(LREF SysTime) is invalid.
10237   +/
10238 SysTime parseRFC822DateTime()(scope const char[] value) @safe
10239 {
10240     import std..string : representation;
10241     return parseRFC822DateTime(value.representation);
10242 }
10243 
10244 /++ Ditto +/
10245 SysTime parseRFC822DateTime(R)(scope R value)
10246 if (isRandomAccessRange!R && hasSlicing!R && hasLength!R &&
10247     (is(immutable ElementType!R == immutable char) || is(immutable ElementType!R == immutable ubyte)))
10248 {
10249     import std.algorithm.searching : find, all;
10250     import std.ascii : isDigit, isAlpha, isPrintable;
10251     import std.conv : to;
10252     import std.functional : not;
10253     import std..string : capitalize, format;
10254     import std.traits : EnumMembers, isArray;
10255     import std.typecons : Rebindable;
10256 
10257     void stripAndCheckLen(R valueBefore, size_t minLen, size_t line = __LINE__)
10258     {
10259         value = _stripCFWS(valueBefore);
10260         if (value.length < minLen)
10261             throw new DateTimeException("date-time value too short", __FILE__, line);
10262     }
10263     stripAndCheckLen(value, "7Dec1200:00A".length);
10264 
10265     static if (isArray!R && (is(ElementEncodingType!R == char) || is(ElementEncodingType!R == ubyte)))
10266     {
10267         static string sliceAsString(R str) @trusted
10268         {
10269             return cast(string) str;
10270         }
10271     }
10272     else
10273     {
10274         char[4] temp;
10275         char[] sliceAsString(R str) @trusted
10276         {
10277             size_t i = 0;
10278             foreach (c; str)
10279                 temp[i++] = cast(char) c;
10280             return temp[0 .. str.length];
10281         }
10282     }
10283 
10284     // day-of-week
10285     if (isAlpha(value[0]))
10286     {
10287         auto dowStr = sliceAsString(value[0 .. 3]);
10288         switch (dowStr)
10289         {
10290             foreach (dow; EnumMembers!DayOfWeek)
10291             {
10292                 enum dowC = capitalize(to!string(dow));
10293                 case dowC:
10294                     goto afterDoW;
10295             }
10296             default: throw new DateTimeException(format("Invalid day-of-week: %s", dowStr));
10297         }
10298 afterDoW: stripAndCheckLen(value[3 .. value.length], ",7Dec1200:00A".length);
10299         if (value[0] != ',')
10300             throw new DateTimeException("day-of-week missing comma");
10301         stripAndCheckLen(value[1 .. value.length], "7Dec1200:00A".length);
10302     }
10303 
10304     // day
10305     immutable digits = isDigit(value[1]) ? 2 : 1;
10306     immutable day = _convDigits!short(value[0 .. digits]);
10307     if (day == -1)
10308         throw new DateTimeException("Invalid day");
10309     stripAndCheckLen(value[digits .. value.length], "Dec1200:00A".length);
10310 
10311     // month
10312     Month month;
10313     {
10314         auto monStr = sliceAsString(value[0 .. 3]);
10315         switch (monStr)
10316         {
10317             foreach (mon; EnumMembers!Month)
10318             {
10319                 enum monC = capitalize(to!string(mon));
10320                 case monC:
10321                 {
10322                     month = mon;
10323                     goto afterMon;
10324                 }
10325             }
10326             default: throw new DateTimeException(format("Invalid month: %s", monStr));
10327         }
10328 afterMon: stripAndCheckLen(value[3 .. value.length], "1200:00A".length);
10329     }
10330 
10331     // year
10332     auto found = value[2 .. value.length].find!(not!(std.ascii.isDigit))();
10333     size_t yearLen = value.length - found.length;
10334     if (found.length == 0)
10335         throw new DateTimeException("Invalid year");
10336     if (found[0] == ':')
10337         yearLen -= 2;
10338     auto year = _convDigits!short(value[0 .. yearLen]);
10339     if (year < 1900)
10340     {
10341         if (year == -1)
10342             throw new DateTimeException("Invalid year");
10343         if (yearLen < 4)
10344         {
10345             if (yearLen == 3)
10346                 year += 1900;
10347             else if (yearLen == 2)
10348                 year += year < 50 ? 2000 : 1900;
10349             else
10350                 throw new DateTimeException("Invalid year. Too few digits.");
10351         }
10352         else
10353             throw new DateTimeException("Invalid year. Cannot be earlier than 1900.");
10354     }
10355     stripAndCheckLen(value[yearLen .. value.length], "00:00A".length);
10356 
10357     // hour
10358     immutable hour = _convDigits!short(value[0 .. 2]);
10359     stripAndCheckLen(value[2 .. value.length], ":00A".length);
10360     if (value[0] != ':')
10361         throw new DateTimeException("Invalid hour");
10362     stripAndCheckLen(value[1 .. value.length], "00A".length);
10363 
10364     // minute
10365     immutable minute = _convDigits!short(value[0 .. 2]);
10366     stripAndCheckLen(value[2 .. value.length], "A".length);
10367 
10368     // second
10369     short second;
10370     if (value[0] == ':')
10371     {
10372         stripAndCheckLen(value[1 .. value.length], "00A".length);
10373         second = _convDigits!short(value[0 .. 2]);
10374         // this is just if/until SysTime is sorted out to fully support leap seconds
10375         if (second == 60)
10376             second = 59;
10377         stripAndCheckLen(value[2 .. value.length], "A".length);
10378     }
10379 
10380     immutable(TimeZone) parseTZ(int sign)
10381     {
10382         if (value.length < 5)
10383             throw new DateTimeException("Invalid timezone");
10384         immutable zoneHours = _convDigits!short(value[1 .. 3]);
10385         immutable zoneMinutes = _convDigits!short(value[3 .. 5]);
10386         if (zoneHours == -1 || zoneMinutes == -1 || zoneMinutes > 59)
10387             throw new DateTimeException("Invalid timezone");
10388         value = value[5 .. value.length];
10389         immutable utcOffset = (dur!"hours"(zoneHours) + dur!"minutes"(zoneMinutes)) * sign;
10390         if (utcOffset == Duration.zero)
10391         {
10392             return sign == 1 ? cast(immutable(TimeZone))UTC()
10393                              : cast(immutable(TimeZone))new immutable SimpleTimeZone(Duration.zero);
10394         }
10395         return new immutable(SimpleTimeZone)(utcOffset);
10396     }
10397 
10398     // zone
10399     Rebindable!(immutable TimeZone) tz;
10400     if (value[0] == '-')
10401         tz = parseTZ(-1);
10402     else if (value[0] == '+')
10403         tz = parseTZ(1);
10404     else
10405     {
10406         // obs-zone
10407         immutable tzLen = value.length - find(value, ' ', '\t', '(')[0].length;
10408         switch (sliceAsString(value[0 .. tzLen <= 4 ? tzLen : 4]))
10409         {
10410             case "UT": case "GMT": tz = UTC(); break;
10411             case "EST": tz = new immutable SimpleTimeZone(dur!"hours"(-5)); break;
10412             case "EDT": tz = new immutable SimpleTimeZone(dur!"hours"(-4)); break;
10413             case "CST": tz = new immutable SimpleTimeZone(dur!"hours"(-6)); break;
10414             case "CDT": tz = new immutable SimpleTimeZone(dur!"hours"(-5)); break;
10415             case "MST": tz = new immutable SimpleTimeZone(dur!"hours"(-7)); break;
10416             case "MDT": tz = new immutable SimpleTimeZone(dur!"hours"(-6)); break;
10417             case "PST": tz = new immutable SimpleTimeZone(dur!"hours"(-8)); break;
10418             case "PDT": tz = new immutable SimpleTimeZone(dur!"hours"(-7)); break;
10419             case "J": case "j": throw new DateTimeException("Invalid timezone");
10420             default:
10421             {
10422                 if (all!(std.ascii.isAlpha)(value[0 .. tzLen]))
10423                 {
10424                     tz = new immutable SimpleTimeZone(Duration.zero);
10425                     break;
10426                 }
10427                 throw new DateTimeException("Invalid timezone");
10428             }
10429         }
10430         value = value[tzLen .. value.length];
10431     }
10432 
10433     // This is kind of arbitrary. Technically, nothing but CFWS is legal past
10434     // the end of the timezone, but we don't want to be picky about that in a
10435     // function that's just parsing rather than validating. So, the idea here is
10436     // that if the next character is printable (and not part of CFWS), then it
10437     // might be part of the timezone and thus affect what the timezone was
10438     // supposed to be, so we'll throw, but otherwise, we'll just ignore it.
10439     if (!value.empty && isPrintable(value[0]) && value[0] != ' ' && value[0] != '(')
10440         throw new DateTimeException("Invalid timezone");
10441 
10442     try
10443         return SysTime(DateTime(year, month, day, hour, minute, second), tz);
10444     catch (DateTimeException dte)
10445         throw new DateTimeException("date-time format is correct, but the resulting SysTime is invalid.", dte);
10446 }
10447 
10448 ///
10449 @safe unittest
10450 {
10451     import core.time : hours;
10452     import std.datetime.date : DateTime, DateTimeException;
10453     import std.datetime.timezone : SimpleTimeZone, UTC;
10454     import std.exception : assertThrown;
10455 
10456     auto tz = new immutable SimpleTimeZone(hours(-8));
10457     assert(parseRFC822DateTime("Sat, 6 Jan 1990 12:14:19 -0800") ==
10458            SysTime(DateTime(1990, 1, 6, 12, 14, 19), tz));
10459 
10460     assert(parseRFC822DateTime("9 Jul 2002 13:11 +0000") ==
10461            SysTime(DateTime(2002, 7, 9, 13, 11, 0), UTC()));
10462 
10463     auto badStr = "29 Feb 2001 12:17:16 +0200";
10464     assertThrown!DateTimeException(parseRFC822DateTime(badStr));
10465 }
10466 
10467 version (StdUnittest) private void testParse822(alias cr)(string str, SysTime expected, size_t line = __LINE__)
10468 {
10469     import std.format : format;
10470     auto value = cr(str);
10471     auto result = parseRFC822DateTime(value);
10472     if (result != expected)
10473         throw new AssertError(format("wrong result. expected [%s], actual[%s]", expected, result), __FILE__, line);
10474 }
10475 
10476 version (StdUnittest) private void testBadParse822(alias cr)(string str, size_t line = __LINE__)
10477 {
10478     try
10479         parseRFC822DateTime(cr(str));
10480     catch (DateTimeException)
10481         return;
10482     throw new AssertError("No DateTimeException was thrown", __FILE__, line);
10483 }
10484 
10485 @system unittest
10486 {
10487     import core.time;
10488     import std.algorithm.iteration : filter, map;
10489     import std.algorithm.searching : canFind;
10490     import std.array : array;
10491     import std.ascii : letters;
10492     import std.format : format;
10493     import std.meta : AliasSeq;
10494     import std.range : chain, iota, take;
10495     import std.stdio : writefln, writeln;
10496     import std..string : representation;
10497 
10498     static struct Rand3Letters
10499     {
10500         enum empty = false;
10501         @property auto front() { return _mon; }
10502         void popFront()
10503         {
10504             import std.exception : assumeUnique;
10505             import std.random : rndGen;
10506             _mon = rndGen.map!(a => letters[a % letters.length])().take(3).array().assumeUnique();
10507         }
10508         string _mon;
10509         static auto start() { Rand3Letters retval; retval.popFront(); return retval; }
10510     }
10511 
10512     static foreach (cr; AliasSeq!(function(string a){return cast(char[]) a;},
10513                            function(string a){return cast(ubyte[]) a;},
10514                            function(string a){return a;},
10515                            function(string a){return map!(b => cast(char) b)(a.representation);}))
10516     {(){ // workaround slow optimizations for large functions
10517          // https://issues.dlang.org/show_bug.cgi?id=2396
10518         scope(failure) writeln(typeof(cr).stringof);
10519         alias test = testParse822!cr;
10520         alias testBad = testBadParse822!cr;
10521 
10522         immutable std1 = DateTime(2012, 12, 21, 13, 14, 15);
10523         immutable std2 = DateTime(2012, 12, 21, 13, 14, 0);
10524         immutable dst1 = DateTime(1976, 7, 4, 5, 4, 22);
10525         immutable dst2 = DateTime(1976, 7, 4, 5, 4, 0);
10526 
10527         test("21 Dec 2012 13:14:15 +0000", SysTime(std1, UTC()));
10528         test("21 Dec 2012 13:14 +0000", SysTime(std2, UTC()));
10529         test("Fri, 21 Dec 2012 13:14 +0000", SysTime(std2, UTC()));
10530         test("Fri, 21 Dec 2012 13:14:15 +0000", SysTime(std1, UTC()));
10531 
10532         test("04 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10533         test("04 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10534         test("Sun, 04 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10535         test("Sun, 04 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10536 
10537         test("4 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10538         test("4 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10539         test("Sun, 4 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10540         test("Sun, 4 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10541 
10542         auto badTZ = new immutable SimpleTimeZone(Duration.zero);
10543         test("21 Dec 2012 13:14:15 -0000", SysTime(std1, badTZ));
10544         test("21 Dec 2012 13:14 -0000", SysTime(std2, badTZ));
10545         test("Fri, 21 Dec 2012 13:14 -0000", SysTime(std2, badTZ));
10546         test("Fri, 21 Dec 2012 13:14:15 -0000", SysTime(std1, badTZ));
10547 
10548         test("04 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10549         test("04 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10550         test("Sun, 04 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10551         test("Sun, 04 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10552 
10553         test("4 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10554         test("4 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10555         test("Sun, 4 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10556         test("Sun, 4 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10557 
10558         auto pst = new immutable SimpleTimeZone(dur!"hours"(-8));
10559         auto pdt = new immutable SimpleTimeZone(dur!"hours"(-7));
10560         test("21 Dec 2012 13:14:15 -0800", SysTime(std1, pst));
10561         test("21 Dec 2012 13:14 -0800", SysTime(std2, pst));
10562         test("Fri, 21 Dec 2012 13:14 -0800", SysTime(std2, pst));
10563         test("Fri, 21 Dec 2012 13:14:15 -0800", SysTime(std1, pst));
10564 
10565         test("04 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10566         test("04 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10567         test("Sun, 04 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10568         test("Sun, 04 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10569 
10570         test("4 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10571         test("4 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10572         test("Sun, 4 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10573         test("Sun, 4 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10574 
10575         auto cet = new immutable SimpleTimeZone(dur!"hours"(1));
10576         auto cest = new immutable SimpleTimeZone(dur!"hours"(2));
10577         test("21 Dec 2012 13:14:15 +0100", SysTime(std1, cet));
10578         test("21 Dec 2012 13:14 +0100", SysTime(std2, cet));
10579         test("Fri, 21 Dec 2012 13:14 +0100", SysTime(std2, cet));
10580         test("Fri, 21 Dec 2012 13:14:15 +0100", SysTime(std1, cet));
10581 
10582         test("04 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10583         test("04 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10584         test("Sun, 04 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10585         test("Sun, 04 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10586 
10587         test("4 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10588         test("4 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10589         test("Sun, 4 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10590         test("Sun, 4 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10591 
10592         // dst and std times are switched in the Southern Hemisphere which is why the
10593         // time zone names and DateTime variables don't match.
10594         auto cstStd = new immutable SimpleTimeZone(dur!"hours"(9) + dur!"minutes"(30));
10595         auto cstDST = new immutable SimpleTimeZone(dur!"hours"(10) + dur!"minutes"(30));
10596         test("21 Dec 2012 13:14:15 +1030", SysTime(std1, cstDST));
10597         test("21 Dec 2012 13:14 +1030", SysTime(std2, cstDST));
10598         test("Fri, 21 Dec 2012 13:14 +1030", SysTime(std2, cstDST));
10599         test("Fri, 21 Dec 2012 13:14:15 +1030", SysTime(std1, cstDST));
10600 
10601         test("04 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10602         test("04 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10603         test("Sun, 04 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10604         test("Sun, 04 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10605 
10606         test("4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10607         test("4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10608         test("Sun, 4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10609         test("Sun, 4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10610 
10611         foreach (int i, mon; _monthNames)
10612         {
10613             test(format("17 %s 2012 00:05:02 +0000", mon), SysTime(DateTime(2012, i + 1, 17, 0, 5, 2), UTC()));
10614             test(format("17 %s 2012 00:05 +0000", mon), SysTime(DateTime(2012, i + 1, 17, 0, 5, 0), UTC()));
10615         }
10616 
10617         import std.uni : toLower, toUpper;
10618         foreach (mon; chain(_monthNames[].map!(a => toLower(a))(),
10619                             _monthNames[].map!(a => toUpper(a))(),
10620                             ["Jam", "Jen", "Fec", "Fdb", "Mas", "Mbr", "Aps", "Aqr", "Mai", "Miy",
10621                              "Jum", "Jbn", "Jup", "Jal", "Aur", "Apg", "Sem", "Sap", "Ocm", "Odt",
10622                              "Nom", "Nav", "Dem", "Dac"],
10623                             Rand3Letters.start().filter!(a => !_monthNames[].canFind(a)).take(20)))
10624         {
10625             scope(failure) writefln("Month: %s", mon);
10626             testBad(format("17 %s 2012 00:05:02 +0000", mon));
10627             testBad(format("17 %s 2012 00:05 +0000", mon));
10628         }
10629 
10630         immutable string[7] daysOfWeekNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
10631 
10632         {
10633             auto start = SysTime(DateTime(2012, 11, 11, 9, 42, 0), UTC());
10634             int day = 11;
10635 
10636             foreach (int i, dow; daysOfWeekNames)
10637             {
10638                 auto curr = start + dur!"days"(i);
10639                 test(format("%s, %s Nov 2012 09:42:00 +0000", dow, day), curr);
10640                 test(format("%s, %s Nov 2012 09:42 +0000", dow, day++), curr);
10641 
10642                 // Whether the day of the week matches the date is ignored.
10643                 test(format("%s, 11 Nov 2012 09:42:00 +0000", dow), start);
10644                 test(format("%s, 11 Nov 2012 09:42 +0000", dow), start);
10645             }
10646         }
10647 
10648         foreach (dow; chain(daysOfWeekNames[].map!(a => toLower(a))(),
10649                             daysOfWeekNames[].map!(a => toUpper(a))(),
10650                             ["Sum", "Spn", "Mom", "Man", "Tuf", "Tae", "Wem", "Wdd", "The", "Tur",
10651                              "Fro", "Fai", "San", "Sut"],
10652                             Rand3Letters.start().filter!(a => !daysOfWeekNames[].canFind(a)).take(20)))
10653         {
10654             scope(failure) writefln("Day of Week: %s", dow);
10655             testBad(format("%s, 11 Nov 2012 09:42:00 +0000", dow));
10656             testBad(format("%s, 11 Nov 2012 09:42 +0000", dow));
10657         }
10658 
10659         testBad("31 Dec 1899 23:59:59 +0000");
10660         test("01 Jan 1900 00:00:00 +0000", SysTime(Date(1900, 1, 1), UTC()));
10661         test("01 Jan 1900 00:00:00 -0000", SysTime(Date(1900, 1, 1),
10662                                                    new immutable SimpleTimeZone(Duration.zero)));
10663         test("01 Jan 1900 00:00:00 -0700", SysTime(Date(1900, 1, 1),
10664                                                    new immutable SimpleTimeZone(dur!"hours"(-7))));
10665 
10666         {
10667             auto st1 = SysTime(Date(1900, 1, 1), UTC());
10668             auto st2 = SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-11)));
10669             foreach (i; 1900 .. 2102)
10670             {
10671                 test(format("1 Jan %05d 00:00 +0000", i), st1);
10672                 test(format("1 Jan %05d 00:00 -1100", i), st2);
10673                 st1.add!"years"(1);
10674                 st2.add!"years"(1);
10675             }
10676             st1.year = 9998;
10677             st2.year = 9998;
10678             foreach (i; 9998 .. 11_002)
10679             {
10680                 test(format("1 Jan %05d 00:00 +0000", i), st1);
10681                 test(format("1 Jan %05d 00:00 -1100", i), st2);
10682                 st1.add!"years"(1);
10683                 st2.add!"years"(1);
10684             }
10685         }
10686 
10687         testBad("12 Feb 1907 23:17:09 0000");
10688         testBad("12 Feb 1907 23:17:09 +000");
10689         testBad("12 Feb 1907 23:17:09 -000");
10690         testBad("12 Feb 1907 23:17:09 +00000");
10691         testBad("12 Feb 1907 23:17:09 -00000");
10692         testBad("12 Feb 1907 23:17:09 +A");
10693         testBad("12 Feb 1907 23:17:09 +PST");
10694         testBad("12 Feb 1907 23:17:09 -A");
10695         testBad("12 Feb 1907 23:17:09 -PST");
10696 
10697         // test trailing stuff that gets ignored
10698         {
10699             foreach (c; chain(iota(0, 33), ['('], iota(127, ubyte.max + 1)))
10700             {
10701                 scope(failure) writefln("c: %d", c);
10702                 test(format("21 Dec 2012 13:14:15 +0000%c", cast(char) c), SysTime(std1, UTC()));
10703                 test(format("21 Dec 2012 13:14:15 +0000%c  ", cast(char) c), SysTime(std1, UTC()));
10704                 test(format("21 Dec 2012 13:14:15 +0000%chello", cast(char) c), SysTime(std1, UTC()));
10705             }
10706         }
10707 
10708         // test trailing stuff that doesn't get ignored
10709         {
10710             foreach (c; chain(iota(33, '('), iota('(' + 1, 127)))
10711             {
10712                 scope(failure) writefln("c: %d", c);
10713                 testBad(format("21 Dec 2012 13:14:15 +0000%c", cast(char) c));
10714                 testBad(format("21 Dec 2012 13:14:15 +0000%c   ", cast(char) c));
10715                 testBad(format("21 Dec 2012 13:14:15 +0000%chello", cast(char) c));
10716             }
10717         }
10718 
10719         testBad("32 Jan 2012 12:13:14 -0800");
10720         testBad("31 Jan 2012 24:13:14 -0800");
10721         testBad("31 Jan 2012 12:60:14 -0800");
10722         testBad("31 Jan 2012 12:13:61 -0800");
10723         testBad("31 Jan 2012 12:13:14 -0860");
10724         test("31 Jan 2012 12:13:14 -0859",
10725              SysTime(DateTime(2012, 1, 31, 12, 13, 14),
10726                      new immutable SimpleTimeZone(dur!"hours"(-8) + dur!"minutes"(-59))));
10727 
10728         // leap-seconds
10729         test("21 Dec 2012 15:59:60 -0800", SysTime(DateTime(2012, 12, 21, 15, 59, 59), pst));
10730 
10731         // FWS
10732         test("Sun,4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10733         test("Sun,4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10734         test("Sun,4 Jul 1976 05:04 +0930 (foo)", SysTime(dst2, cstStd));
10735         test("Sun,4 Jul 1976 05:04:22 +0930 (foo)", SysTime(dst1, cstStd));
10736         test("Sun,4  \r\n  Jul  \r\n  1976  \r\n  05:04  \r\n  +0930  \r\n  (foo)", SysTime(dst2, cstStd));
10737         test("Sun,4  \r\n  Jul  \r\n  1976  \r\n  05:04:22  \r\n  +0930  \r\n  (foo)", SysTime(dst1, cstStd));
10738 
10739         auto str = "01 Jan 2012 12:13:14 -0800 ";
10740         test(str, SysTime(DateTime(2012, 1, 1, 12, 13, 14), new immutable SimpleTimeZone(hours(-8))));
10741         foreach (i; 0 .. str.length)
10742         {
10743             auto currStr = str.dup;
10744             currStr[i] = 'x';
10745             scope(failure) writefln("failed: %s", currStr);
10746             testBad(cast(string) currStr);
10747         }
10748         foreach (i; 2 .. str.length)
10749         {
10750             auto currStr = str[0 .. $ - i];
10751             scope(failure) writefln("failed: %s", currStr);
10752             testBad(cast(string) currStr);
10753             testBad((cast(string) currStr) ~ "                                    ");
10754         }
10755     }();}
10756 
10757     static void testScope(scope ref string str) @safe
10758     {
10759         auto result = parseRFC822DateTime(str);
10760     }
10761 }
10762 
10763 // Obsolete Format per section 4.3 of RFC 5322.
10764 @system unittest
10765 {
10766     import std.algorithm.iteration : filter, map;
10767     import std.ascii : letters;
10768     import std.exception : collectExceptionMsg;
10769     import std.format : format;
10770     import std.meta : AliasSeq;
10771     import std.range : chain, iota;
10772     import std.stdio : writefln, writeln;
10773     import std..string : representation;
10774 
10775     auto std1 = SysTime(DateTime(2012, 12, 21, 13, 14, 15), UTC());
10776     auto std2 = SysTime(DateTime(2012, 12, 21, 13, 14, 0), UTC());
10777     auto std3 = SysTime(DateTime(1912, 12, 21, 13, 14, 15), UTC());
10778     auto std4 = SysTime(DateTime(1912, 12, 21, 13, 14, 0), UTC());
10779     auto dst1 = SysTime(DateTime(1976, 7, 4, 5, 4, 22), UTC());
10780     auto dst2 = SysTime(DateTime(1976, 7, 4, 5, 4, 0), UTC());
10781     auto tooLate1 = SysTime(Date(10_000, 1, 1), UTC());
10782     auto tooLate2 = SysTime(DateTime(12_007, 12, 31, 12, 22, 19), UTC());
10783 
10784     static foreach (cr; AliasSeq!(function(string a){return cast(char[]) a;},
10785                            function(string a){return cast(ubyte[]) a;},
10786                            function(string a){return a;},
10787                            function(string a){return map!(b => cast(char) b)(a.representation);}))
10788     {(){ // workaround slow optimizations for large functions
10789          // https://issues.dlang.org/show_bug.cgi?id=2396
10790         scope(failure) writeln(typeof(cr).stringof);
10791         alias test = testParse822!cr;
10792         {
10793             auto list = ["", " ", " \r\n\t", "\t\r\n (hello world( frien(dog)) silly \r\n )  \t\t \r\n ()",
10794                          " \n ", "\t\n\t", " \n\t (foo) \n (bar) \r\n (baz) \n "];
10795 
10796             foreach (i, cfws; list)
10797             {
10798                 scope(failure) writefln("i: %s", i);
10799 
10800                 test(format("%1$s21%1$sDec%1$s2012%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10801                 test(format("%1$s21%1$sDec%1$s2012%1$s13:14%1$s+0000%1$s", cfws), std2);
10802                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s2012%1$s13:14%1$s+0000%1$s", cfws), std2);
10803                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s2012%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10804 
10805                 test(format("%1$s04%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10806                 test(format("%1$s04%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10807                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10808                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s1976%1$s05:04:22 +0000%1$s", cfws), dst1);
10809 
10810                 test(format("%1$s4%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10811                 test(format("%1$s4%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10812                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10813                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10814 
10815                 test(format("%1$s21%1$sDec%1$s12%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10816                 test(format("%1$s21%1$sDec%1$s12%1$s13:14%1$s+0000%1$s", cfws), std2);
10817                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s12%1$s13:14%1$s+0000%1$s", cfws), std2);
10818                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s12%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10819 
10820                 test(format("%1$s04%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10821                 test(format("%1$s04%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
10822                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
10823                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10824 
10825                 test(format("%1$s4%1$sJul%1$s76 05:04:22%1$s+0000%1$s", cfws), dst1);
10826                 test(format("%1$s4%1$sJul%1$s76 05:04%1$s+0000%1$s", cfws), dst2);
10827                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
10828                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10829 
10830                 test(format("%1$s21%1$sDec%1$s012%1$s13:14:15%1$s+0000%1$s", cfws), std3);
10831                 test(format("%1$s21%1$sDec%1$s012%1$s13:14%1$s+0000%1$s", cfws), std4);
10832                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s012%1$s13:14%1$s+0000%1$s", cfws), std4);
10833                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s012%1$s13:14:15%1$s+0000%1$s", cfws), std3);
10834 
10835                 test(format("%1$s04%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10836                 test(format("%1$s04%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10837                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10838                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10839 
10840                 test(format("%1$s4%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10841                 test(format("%1$s4%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10842                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10843                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10844 
10845                 test(format("%1$s1%1$sJan%1$s10000%1$s00:00:00%1$s+0000%1$s", cfws), tooLate1);
10846                 test(format("%1$s31%1$sDec%1$s12007%1$s12:22:19%1$s+0000%1$s", cfws), tooLate2);
10847                 test(format("%1$sSat%1$s,%1$s1%1$sJan%1$s10000%1$s00:00:00%1$s+0000%1$s", cfws), tooLate1);
10848                 test(format("%1$sSun%1$s,%1$s31%1$sDec%1$s12007%1$s12:22:19%1$s+0000%1$s", cfws), tooLate2);
10849             }
10850         }
10851 
10852         // test years of 1, 2, and 3 digits.
10853         {
10854             auto st1 = SysTime(Date(2000, 1, 1), UTC());
10855             auto st2 = SysTime(Date(2000, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-12)));
10856             foreach (i; 0 .. 50)
10857             {
10858                 test(format("1 Jan %02d 00:00 GMT", i), st1);
10859                 test(format("1 Jan %02d 00:00 -1200", i), st2);
10860                 st1.add!"years"(1);
10861                 st2.add!"years"(1);
10862             }
10863         }
10864 
10865         {
10866             auto st1 = SysTime(Date(1950, 1, 1), UTC());
10867             auto st2 = SysTime(Date(1950, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-12)));
10868             foreach (i; 50 .. 100)
10869             {
10870                 test(format("1 Jan %02d 00:00 GMT", i), st1);
10871                 test(format("1 Jan %02d 00:00 -1200", i), st2);
10872                 st1.add!"years"(1);
10873                 st2.add!"years"(1);
10874             }
10875         }
10876 
10877         {
10878             auto st1 = SysTime(Date(1900, 1, 1), UTC());
10879             auto st2 = SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-11)));
10880             foreach (i; 0 .. 1000)
10881             {
10882                 test(format("1 Jan %03d 00:00 GMT", i), st1);
10883                 test(format("1 Jan %03d 00:00 -1100", i), st2);
10884                 st1.add!"years"(1);
10885                 st2.add!"years"(1);
10886             }
10887         }
10888 
10889         foreach (i; 0 .. 10)
10890         {
10891             auto str1 = cr(format("1 Jan %d 00:00 GMT", i));
10892             auto str2 = cr(format("1 Jan %d 00:00 -1200", i));
10893             assertThrown!DateTimeException(parseRFC822DateTime(str1));
10894             assertThrown!DateTimeException(parseRFC822DateTime(str1));
10895         }
10896 
10897         // test time zones
10898         {
10899             auto dt = DateTime(1982, 05, 03, 12, 22, 04);
10900             test("Wed, 03 May 1982 12:22:04 UT", SysTime(dt, UTC()));
10901             test("Wed, 03 May 1982 12:22:04 GMT", SysTime(dt, UTC()));
10902             test("Wed, 03 May 1982 12:22:04 EST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-5))));
10903             test("Wed, 03 May 1982 12:22:04 EDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-4))));
10904             test("Wed, 03 May 1982 12:22:04 CST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-6))));
10905             test("Wed, 03 May 1982 12:22:04 CDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-5))));
10906             test("Wed, 03 May 1982 12:22:04 MST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-7))));
10907             test("Wed, 03 May 1982 12:22:04 MDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-6))));
10908             test("Wed, 03 May 1982 12:22:04 PST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-8))));
10909             test("Wed, 03 May 1982 12:22:04 PDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-7))));
10910 
10911             auto badTZ = new immutable SimpleTimeZone(Duration.zero);
10912             foreach (dchar c; filter!(a => a != 'j' && a != 'J')(letters))
10913             {
10914                 scope(failure) writefln("c: %s", c);
10915                 test(format("Wed, 03 May 1982 12:22:04 %s", c), SysTime(dt, badTZ));
10916                 test(format("Wed, 03 May 1982 12:22:04%s", c), SysTime(dt, badTZ));
10917             }
10918 
10919             foreach (dchar c; ['j', 'J'])
10920             {
10921                 scope(failure) writefln("c: %s", c);
10922                 assertThrown!DateTimeException(parseRFC822DateTime(cr(format("Wed, 03 May 1982 12:22:04 %s", c))));
10923                 assertThrown!DateTimeException(parseRFC822DateTime(cr(format("Wed, 03 May 1982 12:22:04%s", c))));
10924             }
10925 
10926             foreach (string s; ["AAA", "GQW", "DDT", "PDA", "GT", "GM"])
10927             {
10928                 scope(failure) writefln("s: %s", s);
10929                 test(format("Wed, 03 May 1982 12:22:04 %s", s), SysTime(dt, badTZ));
10930             }
10931 
10932             // test trailing stuff that gets ignored
10933             {
10934                 foreach (c; chain(iota(0, 33), ['('], iota(127, ubyte.max + 1)))
10935                 {
10936                     scope(failure) writefln("c: %d", c);
10937                     test(format("21Dec1213:14:15+0000%c", cast(char) c), std1);
10938                     test(format("21Dec1213:14:15+0000%c  ", cast(char) c), std1);
10939                     test(format("21Dec1213:14:15+0000%chello", cast(char) c), std1);
10940                 }
10941             }
10942 
10943             // test trailing stuff that doesn't get ignored
10944             {
10945                 foreach (c; chain(iota(33, '('), iota('(' + 1, 127)))
10946                 {
10947                     scope(failure) writefln("c: %d", c);
10948                     assertThrown!DateTimeException(
10949                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%c", cast(char) c))));
10950                     assertThrown!DateTimeException(
10951                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%c  ", cast(char) c))));
10952                     assertThrown!DateTimeException(
10953                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%chello", cast(char) c))));
10954                 }
10955             }
10956         }
10957 
10958         // test that the checks for minimum length work correctly and avoid
10959         // any RangeErrors.
10960         test("7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
10961                                      new immutable SimpleTimeZone(Duration.zero)));
10962         test("Fri,7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
10963                                          new immutable SimpleTimeZone(Duration.zero)));
10964         test("7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
10965                                         new immutable SimpleTimeZone(Duration.zero)));
10966         test("Fri,7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
10967                                             new immutable SimpleTimeZone(Duration.zero)));
10968 
10969         auto tooShortMsg = collectExceptionMsg!DateTimeException(parseRFC822DateTime(""));
10970         foreach (str; ["Fri,7Dec1200:00:00", "7Dec1200:00:00"])
10971         {
10972             foreach (i; 0 .. str.length)
10973             {
10974                 auto value = str[0 .. $ - i];
10975                 scope(failure) writeln(value);
10976                 assert(collectExceptionMsg!DateTimeException(parseRFC822DateTime(value)) == tooShortMsg);
10977             }
10978         }
10979     }();}
10980 }
10981 
10982 
10983 private:
10984 
10985 /+
10986     Returns the given hnsecs as an ISO string of fractional seconds.
10987   +/
10988 string fracSecsToISOString(int hnsecs) @safe pure nothrow
10989 {
10990     import std.array : appender;
10991     auto w = appender!string();
10992     try
10993         fracSecsToISOString(w, hnsecs);
10994     catch (Exception e)
10995         assert(0, "fracSecsToISOString() threw.");
10996     return w.data;
10997 }
10998 
10999 void fracSecsToISOString(W)(ref W writer, int hnsecs)
11000 {
11001     import std.conv : toChars;
11002     import std.range : padLeft;
11003 
11004     assert(hnsecs >= 0);
11005 
11006     if (hnsecs == 0)
11007         return;
11008 
11009     put(writer, '.');
11010     auto chars = hnsecs.toChars.padLeft('0', 7);
11011     while (chars.back == '0')
11012         chars.popBack();
11013     put(writer, chars);
11014 }
11015 
11016 @safe unittest
11017 {
11018     assert(fracSecsToISOString(0) == "");
11019     assert(fracSecsToISOString(1) == ".0000001");
11020     assert(fracSecsToISOString(10) == ".000001");
11021     assert(fracSecsToISOString(100) == ".00001");
11022     assert(fracSecsToISOString(1000) == ".0001");
11023     assert(fracSecsToISOString(10_000) == ".001");
11024     assert(fracSecsToISOString(100_000) == ".01");
11025     assert(fracSecsToISOString(1_000_000) == ".1");
11026     assert(fracSecsToISOString(1_000_001) == ".1000001");
11027     assert(fracSecsToISOString(1_001_001) == ".1001001");
11028     assert(fracSecsToISOString(1_071_601) == ".1071601");
11029     assert(fracSecsToISOString(1_271_641) == ".1271641");
11030     assert(fracSecsToISOString(9_999_999) == ".9999999");
11031     assert(fracSecsToISOString(9_999_990) == ".999999");
11032     assert(fracSecsToISOString(9_999_900) == ".99999");
11033     assert(fracSecsToISOString(9_999_000) == ".9999");
11034     assert(fracSecsToISOString(9_990_000) == ".999");
11035     assert(fracSecsToISOString(9_900_000) == ".99");
11036     assert(fracSecsToISOString(9_000_000) == ".9");
11037     assert(fracSecsToISOString(999) == ".0000999");
11038     assert(fracSecsToISOString(9990) == ".000999");
11039     assert(fracSecsToISOString(99_900) == ".00999");
11040     assert(fracSecsToISOString(999_000) == ".0999");
11041 }
11042 
11043 
11044 /+
11045     Returns a Duration corresponding to to the given ISO string of
11046     fractional seconds.
11047   +/
11048 static Duration fracSecsFromISOString(S)(scope const S isoString) @safe pure
11049 if (isSomeString!S)
11050 {
11051     import std.algorithm.searching : all;
11052     import std.ascii : isDigit;
11053     import std.conv : to;
11054     import std..string : representation;
11055 
11056     if (isoString.empty)
11057         return Duration.zero;
11058 
11059     auto str = isoString.representation;
11060 
11061     enforce(str[0] == '.', new DateTimeException("Invalid ISO String"));
11062     str.popFront();
11063 
11064     enforce(!str.empty && all!isDigit(str), new DateTimeException("Invalid ISO String"));
11065 
11066     dchar[7] fullISOString = void;
11067     foreach (i, ref dchar c; fullISOString)
11068     {
11069         if (i < str.length)
11070             c = str[i];
11071         else
11072             c = '0';
11073     }
11074 
11075     return hnsecs(to!int(fullISOString[]));
11076 }
11077 
11078 @safe unittest
11079 {
11080     import core.time;
11081     static void testFSInvalid(string isoString)
11082     {
11083         fracSecsFromISOString(isoString);
11084     }
11085 
11086     assertThrown!DateTimeException(testFSInvalid("."));
11087     assertThrown!DateTimeException(testFSInvalid("0."));
11088     assertThrown!DateTimeException(testFSInvalid("0"));
11089     assertThrown!DateTimeException(testFSInvalid("0000000"));
11090     assertThrown!DateTimeException(testFSInvalid("T"));
11091     assertThrown!DateTimeException(testFSInvalid("T."));
11092     assertThrown!DateTimeException(testFSInvalid(".T"));
11093     assertThrown!DateTimeException(testFSInvalid(".00000Q0"));
11094     assertThrown!DateTimeException(testFSInvalid(".000000Q"));
11095     assertThrown!DateTimeException(testFSInvalid(".0000000Q"));
11096     assertThrown!DateTimeException(testFSInvalid(".0000000000Q"));
11097 
11098     assert(fracSecsFromISOString("") == Duration.zero);
11099     assert(fracSecsFromISOString(".0000001") == hnsecs(1));
11100     assert(fracSecsFromISOString(".000001") == hnsecs(10));
11101     assert(fracSecsFromISOString(".00001") == hnsecs(100));
11102     assert(fracSecsFromISOString(".0001") == hnsecs(1000));
11103     assert(fracSecsFromISOString(".001") == hnsecs(10_000));
11104     assert(fracSecsFromISOString(".01") == hnsecs(100_000));
11105     assert(fracSecsFromISOString(".1") == hnsecs(1_000_000));
11106     assert(fracSecsFromISOString(".1000001") == hnsecs(1_000_001));
11107     assert(fracSecsFromISOString(".1001001") == hnsecs(1_001_001));
11108     assert(fracSecsFromISOString(".1071601") == hnsecs(1_071_601));
11109     assert(fracSecsFromISOString(".1271641") == hnsecs(1_271_641));
11110     assert(fracSecsFromISOString(".9999999") == hnsecs(9_999_999));
11111     assert(fracSecsFromISOString(".9999990") == hnsecs(9_999_990));
11112     assert(fracSecsFromISOString(".999999") == hnsecs(9_999_990));
11113     assert(fracSecsFromISOString(".9999900") == hnsecs(9_999_900));
11114     assert(fracSecsFromISOString(".99999") == hnsecs(9_999_900));
11115     assert(fracSecsFromISOString(".9999000") == hnsecs(9_999_000));
11116     assert(fracSecsFromISOString(".9999") == hnsecs(9_999_000));
11117     assert(fracSecsFromISOString(".9990000") == hnsecs(9_990_000));
11118     assert(fracSecsFromISOString(".999") == hnsecs(9_990_000));
11119     assert(fracSecsFromISOString(".9900000") == hnsecs(9_900_000));
11120     assert(fracSecsFromISOString(".9900") == hnsecs(9_900_000));
11121     assert(fracSecsFromISOString(".99") == hnsecs(9_900_000));
11122     assert(fracSecsFromISOString(".9000000") == hnsecs(9_000_000));
11123     assert(fracSecsFromISOString(".9") == hnsecs(9_000_000));
11124     assert(fracSecsFromISOString(".0000999") == hnsecs(999));
11125     assert(fracSecsFromISOString(".0009990") == hnsecs(9990));
11126     assert(fracSecsFromISOString(".000999") == hnsecs(9990));
11127     assert(fracSecsFromISOString(".0099900") == hnsecs(99_900));
11128     assert(fracSecsFromISOString(".00999") == hnsecs(99_900));
11129     assert(fracSecsFromISOString(".0999000") == hnsecs(999_000));
11130     assert(fracSecsFromISOString(".0999") == hnsecs(999_000));
11131     assert(fracSecsFromISOString(".00000000") == Duration.zero);
11132     assert(fracSecsFromISOString(".00000001") == Duration.zero);
11133     assert(fracSecsFromISOString(".00000009") == Duration.zero);
11134     assert(fracSecsFromISOString(".1234567890") == hnsecs(1_234_567));
11135     assert(fracSecsFromISOString(".12345678901234567890") == hnsecs(1_234_567));
11136 }
11137 
11138 
11139 /+
11140     This function is used to split out the units without getting the remaining
11141     hnsecs.
11142 
11143     Params:
11144         units  = The units to split out.
11145         hnsecs = The current total hnsecs.
11146 
11147     Returns:
11148         The split out value.
11149   +/
11150 long getUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow
11151 if (validTimeUnits(units) &&
11152     CmpTimeUnits!(units, "months") < 0)
11153 {
11154     return convert!("hnsecs", units)(hnsecs);
11155 }
11156 
11157 @safe unittest
11158 {
11159     auto hnsecs = 2595000000007L;
11160     immutable days = getUnitsFromHNSecs!"days"(hnsecs);
11161     assert(days == 3);
11162     assert(hnsecs == 2595000000007L);
11163 }
11164 
11165 
11166 /+
11167     This function is used to split out the units without getting the units but
11168     just the remaining hnsecs.
11169 
11170     Params:
11171         units  = The units to split out.
11172         hnsecs = The current total hnsecs.
11173 
11174     Returns:
11175         The remaining hnsecs.
11176   +/
11177 long removeUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow
11178 if (validTimeUnits(units) &&
11179     CmpTimeUnits!(units, "months") < 0)
11180 {
11181     immutable value = convert!("hnsecs", units)(hnsecs);
11182     return hnsecs - convert!(units, "hnsecs")(value);
11183 }
11184 
11185 @safe unittest
11186 {
11187     auto hnsecs = 2595000000007L;
11188     auto returned = removeUnitsFromHNSecs!"days"(hnsecs);
11189     assert(returned == 3000000007);
11190     assert(hnsecs == 2595000000007L);
11191 }
11192 
11193 
11194 /+
11195     Strips what RFC 5322, section 3.2.2 refers to as CFWS from the left-hand
11196     side of the given range (it strips comments delimited by $(D '(') and
11197     `'`') as well as folding whitespace).
11198 
11199     It is assumed that the given range contains the value of a header field and
11200     no terminating CRLF for the line (though the CRLF for folding whitespace is
11201     of course expected and stripped) and thus that the only case of CR or LF is
11202     in folding whitespace.
11203 
11204     If a comment does not terminate correctly (e.g. mismatched parens) or if the
11205     the FWS is malformed, then the range will be empty when stripCWFS is done.
11206     However, only minimal validation of the content is done (e.g. quoted pairs
11207     within a comment aren't validated beyond \$LPAREN or \$RPAREN, because
11208     they're inside a comment, and thus their value doesn't matter anyway). It's
11209     only when the content does not conform to the grammar rules for FWS and thus
11210     literally cannot be parsed that content is considered invalid, and an empty
11211     range is returned.
11212 
11213     Note that _stripCFWS is eager, not lazy. It does not create a new range.
11214     Rather, it pops off the CFWS from the range and returns it.
11215   +/
11216 R _stripCFWS(R)(R range)
11217 if (isRandomAccessRange!R && hasSlicing!R && hasLength!R &&
11218     (is(immutable ElementType!R == immutable char) || is(immutable ElementType!R == immutable ubyte)))
11219 {
11220     immutable e = range.length;
11221     outer: for (size_t i = 0; i < e; )
11222     {
11223         switch (range[i])
11224         {
11225             case ' ': case '\t':
11226             {
11227                 ++i;
11228                 break;
11229             }
11230             case '\r':
11231             {
11232                 if (i + 2 < e && range[i + 1] == '\n' && (range[i + 2] == ' ' || range[i + 2] == '\t'))
11233                 {
11234                     i += 3;
11235                     break;
11236                 }
11237                 break outer;
11238             }
11239             case '\n':
11240             {
11241                 if (i + 1 < e && (range[i + 1] == ' ' || range[i + 1] == '\t'))
11242                 {
11243                     i += 2;
11244                     break;
11245                 }
11246                 break outer;
11247             }
11248             case '(':
11249             {
11250                 ++i;
11251                 size_t commentLevel = 1;
11252                 while (i < e)
11253                 {
11254                     if (range[i] == '(')
11255                         ++commentLevel;
11256                     else if (range[i] == ')')
11257                     {
11258                         ++i;
11259                         if (--commentLevel == 0)
11260                             continue outer;
11261                         continue;
11262                     }
11263                     else if (range[i] == '\\')
11264                     {
11265                         if (++i == e)
11266                             break outer;
11267                     }
11268                     ++i;
11269                 }
11270                 break outer;
11271             }
11272             default: return range[i .. e];
11273         }
11274     }
11275     return range[e .. e];
11276 }
11277 
11278 @system unittest
11279 {
11280     import std.algorithm.comparison : equal;
11281     import std.algorithm.iteration : map;
11282     import std.meta : AliasSeq;
11283     import std.stdio : writeln;
11284     import std..string : representation;
11285 
11286     static foreach (cr; AliasSeq!(function(string a){return cast(ubyte[]) a;},
11287                            function(string a){return map!(b => cast(char) b)(a.representation);}))
11288     {
11289         scope(failure) writeln(typeof(cr).stringof);
11290 
11291         assert(_stripCFWS(cr("")).empty);
11292         assert(_stripCFWS(cr("\r")).empty);
11293         assert(_stripCFWS(cr("\r\n")).empty);
11294         assert(_stripCFWS(cr("\r\n ")).empty);
11295         assert(_stripCFWS(cr(" \t\r\n")).empty);
11296         assert(equal(_stripCFWS(cr(" \t\r\n hello")), cr("hello")));
11297         assert(_stripCFWS(cr(" \t\r\nhello")).empty);
11298         assert(_stripCFWS(cr(" \t\r\n\v")).empty);
11299         assert(equal(_stripCFWS(cr("\v \t\r\n\v")), cr("\v \t\r\n\v")));
11300         assert(_stripCFWS(cr("()")).empty);
11301         assert(_stripCFWS(cr("(hello world)")).empty);
11302         assert(_stripCFWS(cr("(hello world)(hello world)")).empty);
11303         assert(_stripCFWS(cr("(hello world\r\n foo\r where's\nwaldo)")).empty);
11304         assert(_stripCFWS(cr(" \t (hello \tworld\r\n foo\r where's\nwaldo)\t\t ")).empty);
11305         assert(_stripCFWS(cr("      ")).empty);
11306         assert(_stripCFWS(cr("\t\t\t")).empty);
11307         assert(_stripCFWS(cr("\t \r\n\r \n")).empty);
11308         assert(_stripCFWS(cr("(hello world) (can't find waldo) (he's lost)")).empty);
11309         assert(_stripCFWS(cr("(hello\\) world) (can't \\(find waldo) (he's \\(\\)lost)")).empty);
11310         assert(_stripCFWS(cr("(((((")).empty);
11311         assert(_stripCFWS(cr("(((()))")).empty);
11312         assert(_stripCFWS(cr("(((())))")).empty);
11313         assert(equal(_stripCFWS(cr("(((()))))")), cr(")")));
11314         assert(equal(_stripCFWS(cr(")))))")), cr(")))))")));
11315         assert(equal(_stripCFWS(cr("()))))")), cr("))))")));
11316         assert(equal(_stripCFWS(cr(" hello hello ")), cr("hello hello ")));
11317         assert(equal(_stripCFWS(cr("\thello (world)")), cr("hello (world)")));
11318         assert(equal(_stripCFWS(cr(" \r\n \\((\\))  foo")), cr("\\((\\))  foo")));
11319         assert(equal(_stripCFWS(cr(" \r\n (\\((\\)))  foo")), cr("foo")));
11320         assert(equal(_stripCFWS(cr(" \r\n (\\(()))  foo")), cr(")  foo")));
11321         assert(_stripCFWS(cr(" \r\n (((\\)))  foo")).empty);
11322 
11323         assert(_stripCFWS(cr("(hello)(hello)")).empty);
11324         assert(_stripCFWS(cr(" \r\n (hello)\r\n (hello)")).empty);
11325         assert(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n ")).empty);
11326         assert(_stripCFWS(cr("\t\t\t\t(hello)\t\t\t\t(hello)\t\t\t\t")).empty);
11327         assert(equal(_stripCFWS(cr(" \r\n (hello)\r\n (hello) \r\n hello")), cr("hello")));
11328         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n hello")), cr("hello")));
11329         assert(equal(_stripCFWS(cr("\t\r\n\t(hello)\r\n\t(hello)\t\r\n hello")), cr("hello")));
11330         assert(equal(_stripCFWS(cr("\t\r\n\t(hello)\t\r\n\t(hello)\t\r\n hello")), cr("hello")));
11331         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n \r\n (hello) \r\n hello")), cr("hello")));
11332         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n \r\n hello")), cr("hello")));
11333         assert(equal(_stripCFWS(cr(" \r\n \r\n (hello)\t\r\n (hello) \r\n hello")), cr("hello")));
11334         assert(equal(_stripCFWS(cr(" \r\n\t\r\n\t(hello)\t\r\n (hello) \r\n hello")), cr("hello")));
11335 
11336         assert(equal(_stripCFWS(cr(" (\r\n ( \r\n ) \r\n ) foo")), cr("foo")));
11337         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n ) foo")), cr("foo")));
11338         assert(equal(_stripCFWS(cr(" (\t\r\n ( \r\n ) \r\n ) foo")), cr("foo")));
11339         assert(equal(_stripCFWS(cr(" (\r\n\t( \r\n ) \r\n ) foo")), cr("foo")));
11340         assert(equal(_stripCFWS(cr(" ( \r\n (\t\r\n ) \r\n ) foo")), cr("foo")));
11341         assert(equal(_stripCFWS(cr(" ( \r\n (\r\n ) \r\n ) foo")), cr("foo")));
11342         assert(equal(_stripCFWS(cr(" ( \r\n (\r\n\t) \r\n ) foo")), cr("foo")));
11343         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n) \r\n ) foo")), cr("foo")));
11344         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n )\t\r\n ) foo")), cr("foo")));
11345         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n )\r\n ) foo")), cr("foo")));
11346         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n) foo")), cr("foo")));
11347         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n\t) foo")), cr("foo")));
11348         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n ) \r\n foo")), cr("foo")));
11349         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n )\t\r\n foo")), cr("foo")));
11350         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n )\r\n foo")), cr("foo")));
11351 
11352         assert(equal(_stripCFWS(cr(" ( \r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11353         assert(equal(_stripCFWS(cr(" ( \r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11354         assert(equal(_stripCFWS(cr(" (\t\r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11355         assert(equal(_stripCFWS(cr(" (\r\n \r\n\t( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11356         assert(equal(_stripCFWS(cr(" (\r\n \r\n( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11357         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n\t) \r\n ) foo")), cr("foo")));
11358         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n )\t\r\n ) foo")), cr("foo")));
11359         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n )\r\n ) foo")), cr("foo")));
11360 
11361         assert(equal(_stripCFWS(cr(" ( \r\n bar \r\n ( \r\n bar \r\n ) \r\n ) foo")), cr("foo")));
11362         assert(equal(_stripCFWS(cr(" ( \r\n () \r\n ( \r\n () \r\n ) \r\n ) foo")), cr("foo")));
11363         assert(equal(_stripCFWS(cr(" ( \r\n \\\\ \r\n ( \r\n \\\\ \r\n ) \r\n ) foo")), cr("foo")));
11364 
11365         assert(_stripCFWS(cr("(hello)(hello)")).empty);
11366         assert(_stripCFWS(cr(" \n (hello)\n (hello) \n ")).empty);
11367         assert(_stripCFWS(cr(" \n (hello) \n (hello) \n ")).empty);
11368         assert(equal(_stripCFWS(cr(" \n (hello)\n (hello) \n hello")), cr("hello")));
11369         assert(equal(_stripCFWS(cr(" \n (hello) \n (hello) \n hello")), cr("hello")));
11370         assert(equal(_stripCFWS(cr("\t\n\t(hello)\n\t(hello)\t\n hello")), cr("hello")));
11371         assert(equal(_stripCFWS(cr("\t\n\t(hello)\t\n\t(hello)\t\n hello")), cr("hello")));
11372         assert(equal(_stripCFWS(cr(" \n (hello) \n \n (hello) \n hello")), cr("hello")));
11373         assert(equal(_stripCFWS(cr(" \n (hello) \n (hello) \n \n hello")), cr("hello")));
11374         assert(equal(_stripCFWS(cr(" \n \n (hello)\t\n (hello) \n hello")), cr("hello")));
11375         assert(equal(_stripCFWS(cr(" \n\t\n\t(hello)\t\n (hello) \n hello")), cr("hello")));
11376     }
11377 }
11378 
11379 // This is so that we don't have to worry about std.conv.to throwing. It also
11380 // doesn't have to worry about quite as many cases as std.conv.to, since it
11381 // doesn't have to worry about a sign on the value or about whether it fits.
11382 T _convDigits(T, R)(R str)
11383 if (isIntegral!T && isSigned!T) // The constraints on R were already covered by parseRFC822DateTime.
11384 {
11385     import std.ascii : isDigit;
11386 
11387     assert(!str.empty);
11388     T num = 0;
11389     foreach (i; 0 .. str.length)
11390     {
11391         if (i != 0)
11392             num *= 10;
11393         if (!isDigit(str[i]))
11394             return -1;
11395         num += str[i] - '0';
11396     }
11397     return num;
11398 }
11399 
11400 @safe unittest
11401 {
11402     import std.conv : to;
11403     import std.range : chain, iota;
11404     foreach (i; chain(iota(0, 101), [250, 999, 1000, 1001, 2345, 9999]))
11405     {
11406         assert(_convDigits!int(to!string(i)) == i, i.to!string);
11407     }
11408     foreach (str; ["-42", "+42", "1a", "1 ", " ", " 42 "])
11409     {
11410         assert(_convDigits!int(str) == -1, str);
11411     }
11412 }
11413 
11414 
11415 // NOTE: all the non-simple array literals are wrapped in functions, because
11416 // otherwise importing causes re-evaluation of the static initializers using
11417 // CTFE with unittests enabled
11418 version (StdUnittest)
11419 {
11420 private @safe:
11421     // Variables to help in testing.
11422     Duration currLocalDiffFromUTC;
11423     immutable (TimeZone)[] testTZs;
11424 
11425     // All of these helper arrays are sorted in ascending order.
11426     auto testYearsBC = [-1999, -1200, -600, -4, -1, 0];
11427     auto testYearsAD = [1, 4, 1000, 1999, 2000, 2012];
11428 
11429     // I'd use a Tuple, but I get forward reference errors if I try.
11430     struct MonthDay
11431     {
11432         Month month;
11433         short day;
11434 
11435         this(int m, short d)
11436         {
11437             month = cast(Month) m;
11438             day = d;
11439         }
11440     }
11441 
11442     MonthDay[] testMonthDays()
11443     {
11444        static result = [MonthDay(1, 1),
11445                                 MonthDay(1, 2),
11446                                 MonthDay(3, 17),
11447                                 MonthDay(7, 4),
11448                                 MonthDay(10, 27),
11449                                 MonthDay(12, 30),
11450                                 MonthDay(12, 31)];
11451        return result;
11452     }
11453 
11454     auto testDays = [1, 2, 9, 10, 16, 20, 25, 28, 29, 30, 31];
11455 
11456     TimeOfDay[] testTODs()
11457     {
11458        static result = [TimeOfDay(0, 0, 0),
11459                      TimeOfDay(0, 0, 1),
11460                      TimeOfDay(0, 1, 0),
11461                      TimeOfDay(1, 0, 0),
11462                      TimeOfDay(13, 13, 13),
11463                      TimeOfDay(23, 59, 59)];
11464        return result;
11465     }
11466 
11467     auto testHours = [0, 1, 12, 22, 23];
11468     auto testMinSecs = [0, 1, 30, 58, 59];
11469 
11470     // Throwing exceptions is incredibly expensive, so we want to use a smaller
11471     // set of values for tests using assertThrown.
11472     TimeOfDay[] testTODsThrown()
11473     {
11474        static result = [TimeOfDay(0, 0, 0),
11475                            TimeOfDay(13, 13, 13),
11476                            TimeOfDay(23, 59, 59)];
11477        return result;
11478     }
11479 
11480     Date[] testDatesBC;
11481     Date[] testDatesAD;
11482 
11483     DateTime[] testDateTimesBC;
11484     DateTime[] testDateTimesAD;
11485 
11486     Duration[] testFracSecs;
11487 
11488     SysTime[] testSysTimesBC;
11489     SysTime[] testSysTimesAD;
11490 
11491     // I'd use a Tuple, but I get forward reference errors if I try.
11492     struct GregDay { int day; Date date; }
11493     GregDay[] testGregDaysBC()
11494     {
11495        static result = [GregDay(-1_373_427, Date(-3760, 9, 7)), // Start of the Hebrew Calendar
11496                            GregDay(-735_233, Date(-2012, 1, 1)),
11497                            GregDay(-735_202, Date(-2012, 2, 1)),
11498                            GregDay(-735_175, Date(-2012, 2, 28)),
11499                            GregDay(-735_174, Date(-2012, 2, 29)),
11500                            GregDay(-735_173, Date(-2012, 3, 1)),
11501                            GregDay(-734_502, Date(-2010, 1, 1)),
11502                            GregDay(-734_472, Date(-2010, 1, 31)),
11503                            GregDay(-734_471, Date(-2010, 2, 1)),
11504                            GregDay(-734_444, Date(-2010, 2, 28)),
11505                            GregDay(-734_443, Date(-2010, 3, 1)),
11506                            GregDay(-734_413, Date(-2010, 3, 31)),
11507                            GregDay(-734_412, Date(-2010, 4, 1)),
11508                            GregDay(-734_383, Date(-2010, 4, 30)),
11509                            GregDay(-734_382, Date(-2010, 5, 1)),
11510                            GregDay(-734_352, Date(-2010, 5, 31)),
11511                            GregDay(-734_351, Date(-2010, 6, 1)),
11512                            GregDay(-734_322, Date(-2010, 6, 30)),
11513                            GregDay(-734_321, Date(-2010, 7, 1)),
11514                            GregDay(-734_291, Date(-2010, 7, 31)),
11515                            GregDay(-734_290, Date(-2010, 8, 1)),
11516                            GregDay(-734_260, Date(-2010, 8, 31)),
11517                            GregDay(-734_259, Date(-2010, 9, 1)),
11518                            GregDay(-734_230, Date(-2010, 9, 30)),
11519                            GregDay(-734_229, Date(-2010, 10, 1)),
11520                            GregDay(-734_199, Date(-2010, 10, 31)),
11521                            GregDay(-734_198, Date(-2010, 11, 1)),
11522                            GregDay(-734_169, Date(-2010, 11, 30)),
11523                            GregDay(-734_168, Date(-2010, 12, 1)),
11524                            GregDay(-734_139, Date(-2010, 12, 30)),
11525                            GregDay(-734_138, Date(-2010, 12, 31)),
11526                            GregDay(-731_215, Date(-2001, 1, 1)),
11527                            GregDay(-730_850, Date(-2000, 1, 1)),
11528                            GregDay(-730_849, Date(-2000, 1, 2)),
11529                            GregDay(-730_486, Date(-2000, 12, 30)),
11530                            GregDay(-730_485, Date(-2000, 12, 31)),
11531                            GregDay(-730_484, Date(-1999, 1, 1)),
11532                            GregDay(-694_690, Date(-1901, 1, 1)),
11533                            GregDay(-694_325, Date(-1900, 1, 1)),
11534                            GregDay(-585_118, Date(-1601, 1, 1)),
11535                            GregDay(-584_753, Date(-1600, 1, 1)),
11536                            GregDay(-584_388, Date(-1600, 12, 31)),
11537                            GregDay(-584_387, Date(-1599, 1, 1)),
11538                            GregDay(-365_972, Date(-1001, 1, 1)),
11539                            GregDay(-365_607, Date(-1000, 1, 1)),
11540                            GregDay(-183_351, Date(-501, 1, 1)),
11541                            GregDay(-182_986, Date(-500, 1, 1)),
11542                            GregDay(-182_621, Date(-499, 1, 1)),
11543                            GregDay(-146_827, Date(-401, 1, 1)),
11544                            GregDay(-146_462, Date(-400, 1, 1)),
11545                            GregDay(-146_097, Date(-400, 12, 31)),
11546                            GregDay(-110_302, Date(-301, 1, 1)),
11547                            GregDay(-109_937, Date(-300, 1, 1)),
11548                            GregDay(-73_778, Date(-201, 1, 1)),
11549                            GregDay(-73_413, Date(-200, 1, 1)),
11550                            GregDay(-38_715, Date(-105, 1, 1)),
11551                            GregDay(-37_254, Date(-101, 1, 1)),
11552                            GregDay(-36_889, Date(-100, 1, 1)),
11553                            GregDay(-36_524, Date(-99, 1, 1)),
11554                            GregDay(-36_160, Date(-99, 12, 31)),
11555                            GregDay(-35_794, Date(-97, 1, 1)),
11556                            GregDay(-18_627, Date(-50, 1, 1)),
11557                            GregDay(-18_262, Date(-49, 1, 1)),
11558                            GregDay(-3652, Date(-9, 1, 1)),
11559                            GregDay(-2191, Date(-5, 1, 1)),
11560                            GregDay(-1827, Date(-5, 12, 31)),
11561                            GregDay(-1826, Date(-4, 1, 1)),
11562                            GregDay(-1825, Date(-4, 1, 2)),
11563                            GregDay(-1462, Date(-4, 12, 30)),
11564                            GregDay(-1461, Date(-4, 12, 31)),
11565                            GregDay(-1460, Date(-3, 1, 1)),
11566                            GregDay(-1096, Date(-3, 12, 31)),
11567                            GregDay(-1095, Date(-2, 1, 1)),
11568                            GregDay(-731, Date(-2, 12, 31)),
11569                            GregDay(-730, Date(-1, 1, 1)),
11570                            GregDay(-367, Date(-1, 12, 30)),
11571                            GregDay(-366, Date(-1, 12, 31)),
11572                            GregDay(-365, Date(0, 1, 1)),
11573                            GregDay(-31, Date(0, 11, 30)),
11574                            GregDay(-30, Date(0, 12, 1)),
11575                            GregDay(-1, Date(0, 12, 30)),
11576                            GregDay(0, Date(0, 12, 31))];
11577        return result;
11578     }
11579 
11580     GregDay[] testGregDaysAD()
11581     {
11582        static result = [GregDay(1, Date(1, 1, 1)),
11583                            GregDay(2, Date(1, 1, 2)),
11584                            GregDay(32, Date(1, 2, 1)),
11585                            GregDay(365, Date(1, 12, 31)),
11586                            GregDay(366, Date(2, 1, 1)),
11587                            GregDay(731, Date(3, 1, 1)),
11588                            GregDay(1096, Date(4, 1, 1)),
11589                            GregDay(1097, Date(4, 1, 2)),
11590                            GregDay(1460, Date(4, 12, 30)),
11591                            GregDay(1461, Date(4, 12, 31)),
11592                            GregDay(1462, Date(5, 1, 1)),
11593                            GregDay(17_898, Date(50, 1, 1)),
11594                            GregDay(35_065, Date(97, 1, 1)),
11595                            GregDay(36_160, Date(100, 1, 1)),
11596                            GregDay(36_525, Date(101, 1, 1)),
11597                            GregDay(37_986, Date(105, 1, 1)),
11598                            GregDay(72_684, Date(200, 1, 1)),
11599                            GregDay(73_049, Date(201, 1, 1)),
11600                            GregDay(109_208, Date(300, 1, 1)),
11601                            GregDay(109_573, Date(301, 1, 1)),
11602                            GregDay(145_732, Date(400, 1, 1)),
11603                            GregDay(146_098, Date(401, 1, 1)),
11604                            GregDay(182_257, Date(500, 1, 1)),
11605                            GregDay(182_622, Date(501, 1, 1)),
11606                            GregDay(364_878, Date(1000, 1, 1)),
11607                            GregDay(365_243, Date(1001, 1, 1)),
11608                            GregDay(584_023, Date(1600, 1, 1)),
11609                            GregDay(584_389, Date(1601, 1, 1)),
11610                            GregDay(693_596, Date(1900, 1, 1)),
11611                            GregDay(693_961, Date(1901, 1, 1)),
11612                            GregDay(729_755, Date(1999, 1, 1)),
11613                            GregDay(730_120, Date(2000, 1, 1)),
11614                            GregDay(730_121, Date(2000, 1, 2)),
11615                            GregDay(730_484, Date(2000, 12, 30)),
11616                            GregDay(730_485, Date(2000, 12, 31)),
11617                            GregDay(730_486, Date(2001, 1, 1)),
11618                            GregDay(733_773, Date(2010, 1, 1)),
11619                            GregDay(733_774, Date(2010, 1, 2)),
11620                            GregDay(733_803, Date(2010, 1, 31)),
11621                            GregDay(733_804, Date(2010, 2, 1)),
11622                            GregDay(733_831, Date(2010, 2, 28)),
11623                            GregDay(733_832, Date(2010, 3, 1)),
11624                            GregDay(733_862, Date(2010, 3, 31)),
11625                            GregDay(733_863, Date(2010, 4, 1)),
11626                            GregDay(733_892, Date(2010, 4, 30)),
11627                            GregDay(733_893, Date(2010, 5, 1)),
11628                            GregDay(733_923, Date(2010, 5, 31)),
11629                            GregDay(733_924, Date(2010, 6, 1)),
11630                            GregDay(733_953, Date(2010, 6, 30)),
11631                            GregDay(733_954, Date(2010, 7, 1)),
11632                            GregDay(733_984, Date(2010, 7, 31)),
11633                            GregDay(733_985, Date(2010, 8, 1)),
11634                            GregDay(734_015, Date(2010, 8, 31)),
11635                            GregDay(734_016, Date(2010, 9, 1)),
11636                            GregDay(734_045, Date(2010, 9, 30)),
11637                            GregDay(734_046, Date(2010, 10, 1)),
11638                            GregDay(734_076, Date(2010, 10, 31)),
11639                            GregDay(734_077, Date(2010, 11, 1)),
11640                            GregDay(734_106, Date(2010, 11, 30)),
11641                            GregDay(734_107, Date(2010, 12, 1)),
11642                            GregDay(734_136, Date(2010, 12, 30)),
11643                            GregDay(734_137, Date(2010, 12, 31)),
11644                            GregDay(734_503, Date(2012, 1, 1)),
11645                            GregDay(734_534, Date(2012, 2, 1)),
11646                            GregDay(734_561, Date(2012, 2, 28)),
11647                            GregDay(734_562, Date(2012, 2, 29)),
11648                            GregDay(734_563, Date(2012, 3, 1)),
11649                            GregDay(734_858, Date(2012, 12, 21))];
11650        return result;
11651     }
11652 
11653     // I'd use a Tuple, but I get forward reference errors if I try.
11654     struct DayOfYear { int day; MonthDay md; }
11655     DayOfYear[] testDaysOfYear()
11656     {
11657        static result = [DayOfYear(1, MonthDay(1, 1)),
11658                            DayOfYear(2, MonthDay(1, 2)),
11659                            DayOfYear(3, MonthDay(1, 3)),
11660                            DayOfYear(31, MonthDay(1, 31)),
11661                            DayOfYear(32, MonthDay(2, 1)),
11662                            DayOfYear(59, MonthDay(2, 28)),
11663                            DayOfYear(60, MonthDay(3, 1)),
11664                            DayOfYear(90, MonthDay(3, 31)),
11665                            DayOfYear(91, MonthDay(4, 1)),
11666                            DayOfYear(120, MonthDay(4, 30)),
11667                            DayOfYear(121, MonthDay(5, 1)),
11668                            DayOfYear(151, MonthDay(5, 31)),
11669                            DayOfYear(152, MonthDay(6, 1)),
11670                            DayOfYear(181, MonthDay(6, 30)),
11671                            DayOfYear(182, MonthDay(7, 1)),
11672                            DayOfYear(212, MonthDay(7, 31)),
11673                            DayOfYear(213, MonthDay(8, 1)),
11674                            DayOfYear(243, MonthDay(8, 31)),
11675                            DayOfYear(244, MonthDay(9, 1)),
11676                            DayOfYear(273, MonthDay(9, 30)),
11677                            DayOfYear(274, MonthDay(10, 1)),
11678                            DayOfYear(304, MonthDay(10, 31)),
11679                            DayOfYear(305, MonthDay(11, 1)),
11680                            DayOfYear(334, MonthDay(11, 30)),
11681                            DayOfYear(335, MonthDay(12, 1)),
11682                            DayOfYear(363, MonthDay(12, 29)),
11683                            DayOfYear(364, MonthDay(12, 30)),
11684                            DayOfYear(365, MonthDay(12, 31))];
11685        return result;
11686     }
11687 
11688     DayOfYear[] testDaysOfLeapYear()
11689     {
11690        static result = [DayOfYear(1, MonthDay(1, 1)),
11691                                DayOfYear(2, MonthDay(1, 2)),
11692                                DayOfYear(3, MonthDay(1, 3)),
11693                                DayOfYear(31, MonthDay(1, 31)),
11694                                DayOfYear(32, MonthDay(2, 1)),
11695                                DayOfYear(59, MonthDay(2, 28)),
11696                                DayOfYear(60, MonthDay(2, 29)),
11697                                DayOfYear(61, MonthDay(3, 1)),
11698                                DayOfYear(91, MonthDay(3, 31)),
11699                                DayOfYear(92, MonthDay(4, 1)),
11700                                DayOfYear(121, MonthDay(4, 30)),
11701                                DayOfYear(122, MonthDay(5, 1)),
11702                                DayOfYear(152, MonthDay(5, 31)),
11703                                DayOfYear(153, MonthDay(6, 1)),
11704                                DayOfYear(182, MonthDay(6, 30)),
11705                                DayOfYear(183, MonthDay(7, 1)),
11706                                DayOfYear(213, MonthDay(7, 31)),
11707                                DayOfYear(214, MonthDay(8, 1)),
11708                                DayOfYear(244, MonthDay(8, 31)),
11709                                DayOfYear(245, MonthDay(9, 1)),
11710                                DayOfYear(274, MonthDay(9, 30)),
11711                                DayOfYear(275, MonthDay(10, 1)),
11712                                DayOfYear(305, MonthDay(10, 31)),
11713                                DayOfYear(306, MonthDay(11, 1)),
11714                                DayOfYear(335, MonthDay(11, 30)),
11715                                DayOfYear(336, MonthDay(12, 1)),
11716                                DayOfYear(364, MonthDay(12, 29)),
11717                                DayOfYear(365, MonthDay(12, 30)),
11718                                DayOfYear(366, MonthDay(12, 31))];
11719        return result;
11720     }
11721 
11722     void initializeTests()
11723     {
11724         import std.algorithm.sorting : sort;
11725         import std.typecons : Rebindable;
11726         immutable lt = LocalTime().utcToTZ(0);
11727         currLocalDiffFromUTC = dur!"hnsecs"(lt);
11728 
11729         version (Posix)
11730         {
11731             import std.datetime.timezone : PosixTimeZone;
11732             immutable otherTZ = lt < 0 ? PosixTimeZone.getTimeZone("Australia/Sydney")
11733                                        : PosixTimeZone.getTimeZone("America/Denver");
11734         }
11735         else version (Windows)
11736         {
11737             import std.datetime.timezone : WindowsTimeZone;
11738             immutable otherTZ = lt < 0 ? WindowsTimeZone.getTimeZone("AUS Eastern Standard Time")
11739                                        : WindowsTimeZone.getTimeZone("Mountain Standard Time");
11740         }
11741 
11742         immutable ot = otherTZ.utcToTZ(0);
11743 
11744         auto diffs = [0L, lt, ot];
11745         auto diffAA = [0L : Rebindable!(immutable TimeZone)(UTC())];
11746         diffAA[lt] = Rebindable!(immutable TimeZone)(LocalTime());
11747         diffAA[ot] = Rebindable!(immutable TimeZone)(otherTZ);
11748 
11749         sort(diffs);
11750         testTZs = [diffAA[diffs[0]], diffAA[diffs[1]], diffAA[diffs[2]]];
11751 
11752         testFracSecs = [Duration.zero, hnsecs(1), hnsecs(5007), hnsecs(9_999_999)];
11753 
11754         foreach (year; testYearsBC)
11755         {
11756             foreach (md; testMonthDays)
11757                 testDatesBC ~= Date(year, md.month, md.day);
11758         }
11759 
11760         foreach (year; testYearsAD)
11761         {
11762             foreach (md; testMonthDays)
11763                 testDatesAD ~= Date(year, md.month, md.day);
11764         }
11765 
11766         foreach (dt; testDatesBC)
11767         {
11768             foreach (tod; testTODs)
11769                 testDateTimesBC ~= DateTime(dt, tod);
11770         }
11771 
11772         foreach (dt; testDatesAD)
11773         {
11774             foreach (tod; testTODs)
11775                 testDateTimesAD ~= DateTime(dt, tod);
11776         }
11777 
11778         foreach (dt; testDateTimesBC)
11779         {
11780             foreach (tz; testTZs)
11781             {
11782                 foreach (fs; testFracSecs)
11783                     testSysTimesBC ~= SysTime(dt, fs, tz);
11784             }
11785         }
11786 
11787         foreach (dt; testDateTimesAD)
11788         {
11789             foreach (tz; testTZs)
11790             {
11791                 foreach (fs; testFracSecs)
11792                     testSysTimesAD ~= SysTime(dt, fs, tz);
11793             }
11794         }
11795     }
11796 }
Suggestion Box / Bug Report