diff --git a/phobos.d b/phobos.d
index 3c23c91a6..81d8832b9 100644
--- a/phobos.d
+++ b/phobos.d
@@ -148,6 +148,9 @@ D language compiler. Also, check out the
std.date
Date and time functions. Support locales.
+ std.datetime
+ Date and time-related types and functions.
+
std.file
Basic file operations like read, write, append.
diff --git a/std.ddoc b/std.ddoc
index 5295a18e7..984cfa57d 100644
--- a/std.ddoc
+++ b/std.ddoc
@@ -167,6 +167,7 @@ NAVIGATION_PHOBOS=
$(LI std.cpuid)
$(LI std.ctype)
$(LI std.date)
+ $(LI std.datetime)
$(LI std.demangle)
$(LI std.encoding)
$(LI std.exception)
diff --git a/std/datetime.d b/std/datetime.d
index a4e288a40..b9a2b62df 100644
--- a/std/datetime.d
+++ b/std/datetime.d
@@ -1,500 +1,29485 @@
-/*******************************************************************************
- * Platform-independent high precision StopWatch.
- *
- * This module provide:
- * $(UL
- * $(LI StopWatch)
- * $(LI Benchmarks)
- * $(LI Some helper functions)
- * )
- *
- *
- * License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
- * Authors: Kato Shoichi
- */
+//Written in the D programming language
+
+/++
+ Module containing Date/Time functionality.
+
+ This module provides:
+ $(UL
+ $(LI Types to represent points in time: SysTime, Date, TimeOfDay, and DateTime.)
+ $(LI Types to represent durations of time.)
+ $(LI Types to represent intervals of time.)
+ $(LI Types to represent ranges over intervals of time.)
+ $(LI Types to represent time zones (used by SysTime).)
+ $(LI A platform-independent, high precision stop watch type: StopWatch)
+ $(LI Benchmarking functions.)
+ $(LI Various helper functions.)
+ )
+
+ Three of the main concepts used in this module are time points, time durations,
+ and time intervals.
+
+ A time point is a specific point in time. e.g. January 5th, 2010
+ or 5:00.
+
+ A time duration is a length of time with units. e.g. 5 days or 231 seconds.
+
+ A time interval indicates a period of time associated with a fixed point in time.
+ So, it is either two time points associated with each other, indicating the time
+ starting at the first point up to, but not including, the second point - e.g.
+ [January 5th, 2010 - March 10th, 2010$(RPAREN) - or it is a time point and a time
+ duration associated with one another. e.g. January 5th, 2010 and 5 days,
+ indicating [January 5th, 2010 - January 10th, 2010$(RPAREN).
+
+ Various arithmetic operations are supported between time points and durations
+ (e.g. the difference between two time points is a time duration), and ranges
+ can be gotten from time intervals, so range-based operations may be done on a
+ series of time points.
+
+ The types that the typical user is most likely to be interested in are Date
+ (if they want dates but don't care about time), DateTime (if they want dates
+ and times but don't care about time zones), SysTime (if they want the date
+ and time from the OS and/or do care about time zones), and StopWatch (a
+ platform-independent, high precision stop watch). Date and DateTime are
+ optimized for calendar-based operations, while SysTime is designed for dealing
+ with time from the OS. Check out their specific documentation for more details.
+
+ To get the current time, use $(D Clock.currTime()). It will return the current
+ time as a SysTime. If you want to print it, simple $(D toString()) will do,
+ but if you use one of $(D toISOString()), $(D toISOExtendedString()), or
+ $(D toSimpleString()), you can use the corresponding $(D fromISOString()),
+ $(D fromISOExtendedString()), or $(D fromISOExtendedString()) to create a
+ $(D SysTime) from the string.
+
+ Examples:
+--------------------
+auto currentTime = Clock.currTime();
+auto timeString = currentTime.toISOExtendedString();
+auto restoredTime = SysTime.fromISOExtendedString(timeString);
+--------------------
+
+ Various functions take a string (or strings) to represent a unit of time
+ (e.g. $(D convert!("days", "hours")(numDays))). The valid strings to use
+ with such functions are "years", "months", "weeks", "days", "hours",
+ "minutes", "seconds", "msecs" (milliseconds), "usecs" (microseconds),
+ "hnsecs" (hecto-nanoseconds - i.e. 100 ns) or some subset thereof. There
+ are a few functions in core.time which take "nsecs", but because nothing
+ in std.datetime has precision greater than hnsecs, and very little in
+ core.time does, no functions in std.datetime accept "nsecs".
+
+ Note:
+ core.time is publicly imported by std.datetime, so if you're using
+ std.datetime, you don't need to import core.time. Also, DateTimeException
+ is an alias for core.time's TimeException, so you don't need to worry
+ about core.time functions and std.datetime functions throwing a different
+ type of exception (except in the rare case that they throw something other
+ than TimeException or DateTimeException).
+
+ See_Also:
+ ISO 8601
+ Wikipedia entry on TZ database
+ List of Time Zones
+
+ Copyright: Copyright 2010
+ License: Boost License 1.0.
+ Authors: Jonathan M Davis and Kato Shoichi
++/
module std.datetime;
-@safe:
+public import core.time;
-import std.traits, std.exception, std.functional;
+import core.exception;
+import core.stdc.time;
-version (Windows)
+import std.array;
+import std.algorithm;
+import std.conv;
+import std.ctype;
+import std.exception;
+import std.file;
+import std.functional;
+import std.math;
+import std.metastrings;
+import std.path;
+import std.range;
+import std.stdio;
+import std.string;
+import std.system;
+import std.traits;
+
+version(Windows)
{
- import core.sys.windows.windows;
- import std.windows.syserror;
+import core.sys.windows.windows;
+import std.c.windows.winsock;
+
+//For system call to access the registry.
+pragma(lib, "advapi32.lib");
}
-else version (Posix)
+else version(Posix)
{
- import core.sys.posix.time;
- import core.sys.posix.sys.time;
+import core.sys.posix.arpa.inet;
+import core.sys.posix.stdlib;
+import core.sys.posix.time;
+import core.sys.posix.sys.time;
}
-
-//##############################################################################
-//##############################################################################
-//###
-//### StopWatch
-//###
-//##############################################################################
-//##############################################################################
-
-
-/*******************************************************************************
- * System clock time.
- *
- * This type maintains the most high precision ticks of system clock in each
- * environment.
- * (For StopWatch)
- */
-struct Ticks
+version(unittest)
{
-@safe:// @@@BUG@@@ workaround for bug 4211
-
-
- /***************************************************************************
- * Ticks that is counted per 1[s].
- *
- * Confirm that it is not 0, to examine whether you can use Ticks.
- */
- static immutable long ticksPerSec;
-
-
- /***************************************************************************
- * Ticks when application begins.
- */
- static immutable Ticks appOrigin;
-
-
- @trusted
- shared static this()
- {
- version (Windows)
- {
- if (QueryPerformanceFrequency(cast(long*)&ticksPerSec) == 0)
- {
- ticksPerSec = 0;
- }
- }
- else version (Posix)
- {
- static if (is(typeof(clock_gettime)==function))
- {
- timespec ts;
- if ( clock_getres(CLOCK_REALTIME, &ts) != 0)
- {
- ticksPerSec = 0;
- }
- else
- {
- ticksPerSec = 1000_000_000 / ts.tv_nsec;
- }
- }
- else
- {
- ticksPerSec = 1_000_000;
- }
- }
- if (ticksPerSec != 0)
- {
- appOrigin = systime();
- }
- }
-
-
- unittest
- {
- assert(ticksPerSec);
- }
-
-
- /***************************************************************************
- * Unknown value for Ticks
- *
- * You can convert this value into number of seconds by dividing it
- * by ticksPerSec.
- */
- long value;
-
-
- /***************************************************************************
- * [s] as integer or real number
- *
- * Attention: This method truncate the number of digits after decimal point.
- */
- const
- T toSeconds(T)() if (isIntegral!T && T.sizeof >= 4)
- {
- return cast(T)(value/ticksPerSec);
- }
-
-
- /// ditto
- const
- T toSeconds(T)() if (isFloatingPoint!T)
- {
- //@@@BUG@@@ workaround for bug 4689
- long t = ticksPerSec;
- return value/cast(T)t;
- }
-
-
- /***************************************************************************
- * [s] as real number
- */
- @property alias toSeconds!real seconds;
-
-
- /***************************************************************************
- * [s] as integer
- */
- @property alias toSeconds!long sec;
-
-
-
- unittest
- {
- auto t = Ticks(ticksPerSec);
- assert(t.sec == 1);
- t = Ticks(ticksPerSec-1);
- assert(t.sec == 0);
- t = Ticks(ticksPerSec*2);
- assert(t.sec == 2);
- t = Ticks(ticksPerSec*2-1);
- assert(t.sec == 1);
- t = Ticks(-1);
- assert(t.sec == 0);
- t = Ticks(-ticksPerSec-1);
- assert(t.sec == -1);
- t = Ticks(-ticksPerSec);
- assert(t.sec == -1);
- }
-
-
- /***************************************************************************
- * Create Ticks from [s] as integer
- */
- static Ticks fromSeconds(T)(T sec) if (isNumeric!T)
- {
- return Ticks(cast(long)(sec * ticksPerSec));
- }
-
-
- unittest
- {
- auto t = Ticks.fromSeconds(1000000);
- assert(t.sec == 1000000);
- t = Ticks.fromSeconds(2000000);
- assert(t.sec == 2000000);
- t.value -= 1;
- assert(t.sec == 1999999);
- }
-
-
- /***************************************************************************
- * [ms] as integer or real number
- */
- const
- T toMilliseconds(T)() if (isIntegral!T && T.sizeof >= 4)
- {
- return value/(ticksPerSec/1000);
- }
-
-
- /// ditto
- const
- T toMilliseconds(T)() if (isFloatingPoint!T)
- {
- return toSeconds!T * 1000;
- }
-
- /***************************************************************************
- * [ms] as real number
- */
- @property alias toMilliseconds!real milliseconds;
-
-
- /***************************************************************************
- * [ms] as integer
- */
- @property alias toMilliseconds!long msec;
-
-
- /***************************************************************************
- * Create Ticks from [ms] as integer
- */
- static Ticks fromMilliseconds(long msec)
- {
- return Ticks(msec*(ticksPerSec/1000));
- }
-
-
- unittest
- {
- auto t = Ticks.fromMilliseconds(1000000);
- assert(t.msec == 1000000);
- t = Ticks.fromMilliseconds(2000000);
- assert(t.msec == 2000000);
- t.value -= 1;
- assert(t.msec == 1999999);
- }
-
-
- /***************************************************************************
- * [us] as integer or real number
- */
- const
- T toMicroseconds(T)() if (isIntegral!T && T.sizeof >= 4)
- {
- return value/(ticksPerSec/1000/1000);
- }
-
-
- /// ditto
- const
- T toMicroseconds(T)() if (isFloatingPoint!T)
- {
- return toMilliseconds!T * 1000;
- }
-
-
- /***************************************************************************
- * [us] as real number
- */
- @property alias toMicroseconds!real microseconds;
-
-
- /***************************************************************************
- * [us] as integer
- */
- alias toMicroseconds!long usec;
-
-
- /***************************************************************************
- * Create Ticks from [us] as integer
- */
- static Ticks fromMicroseconds(long usec)
- {
- return Ticks(usec*(ticksPerSec/1000/1000));
- }
-
-
- unittest
- {
- auto t = Ticks.fromMicroseconds(1000000);
- assert(t.usec == 1000000);
- t = Ticks.fromMicroseconds(2000000);
- assert(t.usec == 2000000);
- t.value -= 1;
- assert(t.usec == 1999999);
- }
-
-
- /***************************************************************************
- * operator overroading "-=, +="
- *
- * BUG: This should be return "ref Ticks", but bug2460 prevents that.
- */
- void opOpAssign(string op)(in Ticks t) if (op == "+" || op == "-")
- {
- mixin("value "~op~"= t.value;");
- //return this;
- }
-
-
- unittest
- {
- Ticks a = systime(), b = systime();
- a += systime();
- assert(a.seconds >= 0);
- b -= systime();
- assert(b.seconds <= 0);
- }
-
-
- /***************************************************************************
- * operator overroading "-, +"
- */
- const
- Ticks opBinary(string op)(in Ticks t) if (op == "-" || op == "+")
- {
- Ticks lhs = this;
- lhs.opOpAssign!op(t);
- return lhs;
- }
-
-
- unittest
- {
- auto a = systime();
- auto b = systime();
- assert((a + b).seconds > 0);
- assert((a - b).seconds <= 0);
- }
-
-
- /***************************************************************************
- * operator overroading "=="
- */
- const
- equals_t opEquals(ref const Ticks t)
- {
- return value == t.value;
- }
-
-
- unittest
- {
- auto t1 = systime();
- assert(t1 == t1);
- }
-
-
- /***************************************************************************
- * operator overroading "<, >, <=, >="
- */
- const
- int opCmp(ref const Ticks t)
- {
- return value < t.value? -1: value == t.value ? 0 : 1;
- }
-
-
- unittest
- {
- auto t1 = systime();
- auto t2 = systime();
- assert(t1 <= t2);
- assert(t2 >= t1);
- }
-
-
- /***************************************************************************
- * operator overroading "*=, /="
- */
- void opOpAssign(string op, T)(T x)
- if ((op == "*" || op == "/") && isNumeric!(T))
- {
- mixin("value "~op~"= x;");
- }
-
-
- unittest
- {
- immutable t = systime();
- // *
- {
- Ticks t1 = t, t2 = t;
- t1 *= 2;
- assert(t < t1);
- t2 *= 2.1L;
- assert(t2 > t1);
- }
- // /
- {
- Ticks t1 = t, t2 = t;
- t1 /= 2;
- assert(t1 < t);
- t2 /= 2.1L;
- assert(t2 < t1);
- }
- }
-
-
- /***************************************************************************
- * operator overroading "*", "/"
- */
- Ticks opBinary(string op, T)(T x)
- if ((op == "*" || op == "/") && isNumeric!(T))
- {
- auto lhs = this;
- lhs.opOpAssign!op(x);
- return lhs;
- }
-
-
- unittest
- {
- auto t = systime();
- auto t2 = t*2;
- assert(t < t2);
- assert(t*3.5 > t2);
- }
-
-
- /***************************************************************************
- * operator overroading "/"
- */
- const
- real opBinary(string op)(Ticks x) if (op == "/")
- {
- return value / cast(real)x.value;
- }
-
-
- unittest
- {
- auto t = systime();
- assert(t/systime() <= 1);
- }
+import std.c.string;
}
-/***************************************************************************
- * Special type for constructor
- */
-enum AutoStart
+alias std.string.indexOf indexOf;
+alias std.math.abs abs;
+
+
+//Note: There various functions which void as their return type and ref of the
+// struct type which they're in as a commented out return type. Ideally,
+// they would return the ref, but there are several dmd bugs which prevent
+// that, relating to both ref and invariants. So, I've left the ref return
+// types commented out with the idea that those functions can be made to
+// return a ref to this once those bugs have been fixed.
+
+
+//==============================================================================
+// Section with public enums and constants.
+//==============================================================================
+
+/++
+ Represents the 12 months of the Gregorian year (January is 1).
+ +/
+enum Month : ubyte { jan = 1, ///
+ feb, ///
+ mar, ///
+ apr, ///
+ may, ///
+ jun, ///
+ jul, ///
+ aug, ///
+ sep, ///
+ oct, ///
+ nov, ///
+ dec ///
+ }
+
+
+/++
+ Represents the 7 days of the Gregorian week (Sunday is 0).
+ +/
+enum DayOfWeek : ubyte { sun = 0, ///
+ mon, ///
+ tue, ///
+ wed, ///
+ thu, ///
+ fri, ///
+ sat ///
+ }
+
+
+/++
+ In some date calculations, adding months or years can cause the date to fall on
+ a day of the month which is not valid (e.g. February 29th 2001 or June 31st 2000).
+ If overflow is allowed (as is the default), then the month will be incremented
+ accordingly (so, February 29th 2001 would become March 1st 2001, and June 31st 2000
+ would become July 1st 2000). If overflow is not allowed, then the day will be
+ adjusted to the last valid day in that month (so, February 29th 2001 would become
+ February 28th 2001 and June 31st 2000 would become June 30th 2000).
+
+ AllowDayOverflow only applies to calculations involving months or years.
+ +/
+enum AllowDayOverflow
{
- ///
+ /// No, don't allow day overflow.
no,
- ///
+
+ /// Yes, allow day overflow.
yes
}
+/++
+ Indicates a direction in time. One example of its use is $(D Interval)'s
+ $(D expand()) function which uses it to indicate whether the interval should
+ be expanded backwards (into the past), forwards (into the future), or both.
+ +/
+enum Direction
+{
+ /// Backward.
+ bwd,
-/*******************************************************************************
- * StopWatch's AutoStart flag
- */
+ /// Forward.
+ fwd,
+
+ /// Both backward and forward.
+ both
+}
+
+
+/++
+ Used to indicate whether $(D popFront()) should be called immediately upon
+ creating a range. The idea is that for some functions used to generate a
+ range for an interval, $(D front) is not necessarily a time point which would
+ ever be generated by the range, and if you want the first time point in the
+ range to match what the function generates, then you use $(D PopFirst.yes)
+ to indicate that the range should have $(D popFront()) called on it before the
+ range is returned so that $(D front) is a time point which the function would
+ generate.
+
+ For instance, if the function used to generate a range of time points generated
+ successive Easters (i.e. you're iterating over all of the Easters within the
+ interval), the initial date probably isn't an Easter. By using $(D PopFirst.yes),
+ you would be telling the function which returned the range that you wanted
+ $(D popFront()) to be called so that front would then be an Easter - the next
+ one generated by the function (which if you were iterating forward, would be
+ the Easter following the original $(D front), while if you were iterating backward,
+ it would be the Easter prior to the original $(D front)). If $(D PopFirst.no)
+ were used, then $(D front) would remain the original time point and it would
+ not necessarily be a time point which would be generated by the range-generating
+ function (which in many cases is exactly what you want - e.g. if you were
+ iterating over every day starting at the beginning of the interval).
+ +/
+enum PopFirst
+{
+ /// No, don't call popFront() before returning the range.
+ no,
+
+ /// Yes, call popFront() before returning the range.
+ yes
+}
+
+
+/++
+ Used by StopWatch to indicate whether it should start immediately upon construction.
+ +/
+enum AutoStart
+{
+ /// No, don't start the StopWatch when it is constructed.
+ no,
+
+ /// Yes, do start the StopWatch when it is constructed.
+ yes
+}
+
+
+/++
+ Array of the strings representing time units, starting with the smallest unit
+ and going to the largest. It does not include "nsecs".
+
+ "hnsecs" (hecto-nanoseconds (100 ns)), "usecs" (microseconds), "msecs" (milliseconds),
+ "seconds", "minutes", "hours", "days", "weeks", "months", "years"
+ +/
+immutable string[] timeStrings = ["hnsecs", "usecs", "msecs", "seconds", "minutes",
+ "hours", "days", "weeks", "months", "years"];
+
+
+//==============================================================================
+// Section with time points.
+//==============================================================================
+
+/++
+ Represents a date in the Proleptic Gregorian Calendar ranging from 32,768 B.C.
+ to 32,767 A.D. Positive years are A.D. Non-positive years are B.C.
+
+ Year, month, and day are kept separately internally so that Date is optimized for
+ calendar operations.
+
+ Date uses the Proleptic Gregorian Calendar, so it assumes the Gregorian leap year
+ calculations for its entire length. And, as per ISO 8601, it also treats 1 B.C. as
+ year 0, so 1 B.C. is 0, 2 B.C. is -1, etc. Use $(D yearBC) if want B.C. as a positive
+ integer with 1 B.C. being the year prior to 1 A.D.
+
+ Year 0 is a leap year.
+ +/
+struct Date
+{
+public:
+
+ /++
+ Throws:
+ DateTimeException if the resulting Date would not be valid.
+
+ Params:
+ year = Year of the Gregorian Calendar. Positive values are A.D.
+ Non-positive values are B.C. with year 0 being the year
+ prior to 1 A.D.
+ month = Month of the year.
+ day = Day of the month.
+ +/
+ this(int year, int month, int day) pure
+ {
+ enforceValid!"months"(cast(Month)month);
+ enforceValid!"days"(year, cast(Month)month, day);
+
+ _year = cast(short)year;
+ _month = cast(Month)month;
+ _day = cast(ubyte)day;
+ }
+
+ unittest
+ {
+ assertPred!"=="(Date(1, 1, 1), Date.init);
+
+ static void testDate(in Date date, int year, int month, int day, size_t line = __LINE__)
+ {
+ assertPred!"=="(date._year, year, "", __FILE__, line);
+ assertPred!"=="(date._month, month, "", __FILE__, line);
+ assertPred!"=="(date._day, day, "", __FILE__, line);
+ }
+
+ testDate(Date(1999, 1 , 1), 1999, Month.jan, 1);
+ testDate(Date(1999, 7 , 1), 1999, Month.jul, 1);
+ testDate(Date(1999, 7 , 6), 1999, Month.jul, 6);
+
+ //Test A.D.
+ assertThrown!DateTimeException(Date(1, 0, 1));
+ assertThrown!DateTimeException(Date(1, 1, 0));
+ assertThrown!DateTimeException(Date(1999, 13, 1));
+ assertThrown!DateTimeException(Date(1999, 1, 32));
+ assertThrown!DateTimeException(Date(1999, 2, 29));
+ assertThrown!DateTimeException(Date(2000, 2, 30));
+ assertThrown!DateTimeException(Date(1999, 3, 32));
+ assertThrown!DateTimeException(Date(1999, 4, 31));
+ assertThrown!DateTimeException(Date(1999, 5, 32));
+ assertThrown!DateTimeException(Date(1999, 6, 31));
+ assertThrown!DateTimeException(Date(1999, 7, 32));
+ assertThrown!DateTimeException(Date(1999, 8, 32));
+ assertThrown!DateTimeException(Date(1999, 9, 31));
+ assertThrown!DateTimeException(Date(1999, 10, 32));
+ assertThrown!DateTimeException(Date(1999, 11, 31));
+ assertThrown!DateTimeException(Date(1999, 12, 32));
+
+ assertNotThrown!DateTimeException(Date(1999, 1, 31));
+ assertNotThrown!DateTimeException(Date(1999, 2, 28));
+ assertNotThrown!DateTimeException(Date(2000, 2, 29));
+ assertNotThrown!DateTimeException(Date(1999, 3, 31));
+ assertNotThrown!DateTimeException(Date(1999, 4, 30));
+ assertNotThrown!DateTimeException(Date(1999, 5, 31));
+ assertNotThrown!DateTimeException(Date(1999, 6, 30));
+ assertNotThrown!DateTimeException(Date(1999, 7, 31));
+ assertNotThrown!DateTimeException(Date(1999, 8, 31));
+ assertNotThrown!DateTimeException(Date(1999, 9, 30));
+ assertNotThrown!DateTimeException(Date(1999, 10, 31));
+ assertNotThrown!DateTimeException(Date(1999, 11, 30));
+ assertNotThrown!DateTimeException(Date(1999, 12, 31));
+
+ //Test B.C.
+ assertNotThrown!DateTimeException(Date(0, 1, 1));
+ assertNotThrown!DateTimeException(Date(-1, 1, 1));
+ assertNotThrown!DateTimeException(Date(-1, 12, 31));
+ assertNotThrown!DateTimeException(Date(-1, 2, 28));
+ assertNotThrown!DateTimeException(Date(-4, 2, 29));
+
+ assertThrown!DateTimeException(Date(-1, 2, 29));
+ assertThrown!DateTimeException(Date(-2, 2, 29));
+ assertThrown!DateTimeException(Date(-3, 2, 29));
+ }
+
+
+ /++
+ Params:
+ day = The Xth day of the Gregorian Calendar that the constructed Date
+ will be for.
+ +/
+ this(int day) pure nothrow
+ {
+ if(day > 0)
+ {
+ int years = (day / daysIn400Years) * 400 + 1;
+ day %= daysIn400Years;
+
+ years += (day / daysIn100Years) * 100;
+ day %= daysIn100Years;
+
+ years += (day / daysIn4Years) * 4;
+ day %= daysIn4Years;
+
+ years += day / daysInYear;
+ day %= daysInYear;
+
+ if(day == 0)
+ {
+ _year = cast(short)(years - 1);
+ _month = Month.dec;
+ _day = 31;
+ }
+ else
+ {
+ _year = cast(short)years;
+
+ try
+ dayOfYear = day;
+ catch(Exception e)
+ assert(0, "dayOfYear assignment threw.");
+ }
+ }
+ else if(day <= 0 && -day < daysInLeapYear)
+ {
+ _year = 0;
+
+ try
+ dayOfYear = (daysInLeapYear + day);
+ catch(Exception e)
+ assert(0, "dayOfYear assignment threw.");
+ }
+ else
+ {
+ day += daysInLeapYear - 1;
+ int years = (day / daysIn400Years) * 400 - 1;
+ day %= daysIn400Years;
+
+ years += (day / daysIn100Years) * 100;
+ day %= daysIn100Years;
+
+ years += (day / daysIn4Years) * 4;
+ day %= daysIn4Years;
+
+ years += day / daysInYear;
+ day %= daysInYear;
+
+ if(day == 0)
+ {
+ _year = cast(short)(years + 1);
+ _month = Month.jan;
+ _day = 1;
+ }
+ else
+ {
+ _year = cast(short)years;
+ immutable newDoY = (yearIsLeapYear(_year) ? daysInLeapYear : daysInYear) + day + 1;
+
+ try
+ dayOfYear = newDoY;
+ catch(Exception e)
+ assert(0, "dayOfYear assignment threw.");
+ }
+ }
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(Date(1), Date(1, 1, 1));
+ assertPred!"=="(Date(2), Date(1, 1, 2));
+ assertPred!"=="(Date(32), Date(1, 2, 1));
+ assertPred!"=="(Date(366), Date(2, 1, 1));
+ assertPred!"=="(Date(731), Date(3, 1, 1));
+ assertPred!"=="(Date(1096), Date(4, 1, 1));
+ assertPred!"=="(Date(1462), Date(5, 1, 1));
+ assertPred!"=="(Date(17_898), Date(50, 1, 1));
+ assertPred!"=="(Date(35_065), Date(97, 1, 1));
+ assertPred!"=="(Date(36_160), Date(100, 1, 1));
+ assertPred!"=="(Date(36_525), Date(101, 1, 1));
+ assertPred!"=="(Date(37_986), Date(105, 1, 1));
+ assertPred!"=="(Date(72_684), Date(200, 1, 1));
+ assertPred!"=="(Date(73_049), Date(201, 1, 1));
+ assertPred!"=="(Date(109_208), Date(300, 1, 1));
+ assertPred!"=="(Date(109_573), Date(301, 1, 1));
+ assertPred!"=="(Date(145_732), Date(400, 1, 1));
+ assertPred!"=="(Date(146_098), Date(401, 1, 1));
+ assertPred!"=="(Date(182_257), Date(500, 1, 1));
+ assertPred!"=="(Date(182_622), Date(501, 1, 1));
+ assertPred!"=="(Date(364_878), Date(1000, 1, 1));
+ assertPred!"=="(Date(365_243), Date(1001, 1, 1));
+ assertPred!"=="(Date(584_023), Date(1600, 1, 1));
+ assertPred!"=="(Date(584_389), Date(1601, 1, 1));
+ assertPred!"=="(Date(693_596), Date(1900, 1, 1));
+ assertPred!"=="(Date(693_961), Date(1901, 1, 1));
+ assertPred!"=="(Date(729_755), Date(1999, 1, 1));
+ assertPred!"=="(Date(730_120), Date(2000, 1, 1));
+ assertPred!"=="(Date(730_486), Date(2001, 1, 1));
+
+ assertPred!"=="(Date(733_773), Date(2010, 1, 1));
+ assertPred!"=="(Date(733_803), Date(2010, 1, 31));
+ assertPred!"=="(Date(733_804), Date(2010, 2, 1));
+ assertPred!"=="(Date(733_831), Date(2010, 2, 28));
+ assertPred!"=="(Date(733_832), Date(2010, 3, 1));
+ assertPred!"=="(Date(733_862), Date(2010, 3, 31));
+ assertPred!"=="(Date(733_863), Date(2010, 4, 1));
+ assertPred!"=="(Date(733_892), Date(2010, 4, 30));
+ assertPred!"=="(Date(733_893), Date(2010, 5, 1));
+ assertPred!"=="(Date(733_923), Date(2010, 5, 31));
+ assertPred!"=="(Date(733_924), Date(2010, 6, 1));
+ assertPred!"=="(Date(733_953), Date(2010, 6, 30));
+ assertPred!"=="(Date(733_954), Date(2010, 7, 1));
+ assertPred!"=="(Date(733_984), Date(2010, 7, 31));
+ assertPred!"=="(Date(733_985), Date(2010, 8, 1));
+ assertPred!"=="(Date(734_015), Date(2010, 8, 31));
+ assertPred!"=="(Date(734_016), Date(2010, 9, 1));
+ assertPred!"=="(Date(734_045), Date(2010, 9, 30));
+ assertPred!"=="(Date(734_046), Date(2010, 10, 1));
+ assertPred!"=="(Date(734_076), Date(2010, 10, 31));
+ assertPred!"=="(Date(734_077), Date(2010, 11, 1));
+ assertPred!"=="(Date(734_106), Date(2010, 11, 30));
+ assertPred!"=="(Date(734_107), Date(2010, 12, 1));
+ assertPred!"=="(Date(734_137), Date(2010, 12, 31));
+
+ assertPred!"=="(Date(734_534), Date(2012, 2, 1));
+ assertPred!"=="(Date(734_561), Date(2012, 2, 28));
+ assertPred!"=="(Date(734_562), Date(2012, 2, 29));
+ assertPred!"=="(Date(734_563), Date(2012, 3, 1));
+
+ assertPred!"=="(Date(734_534), Date(2012, 2, 1));
+
+ assertPred!"=="(Date(734_561), Date(2012, 2, 28));
+ assertPred!"=="(Date(734_562), Date(2012, 2, 29));
+ assertPred!"=="(Date(734_563), Date(2012, 3, 1));
+
+ //Test B.C.
+ assertPred!"=="(Date(0), Date(0, 12, 31));
+ assertPred!"=="(Date(-1), Date(0, 12, 30));
+ assertPred!"=="(Date(-30), Date(0, 12, 1));
+ assertPred!"=="(Date(-31), Date(0, 11, 30));
+
+ assertPred!"=="(Date(-366), Date(-1, 12, 31));
+ assertPred!"=="(Date(-367), Date(-1, 12, 30));
+ assertPred!"=="(Date(-730), Date(-1, 1, 1));
+ assertPred!"=="(Date(-731), Date(-2, 12, 31));
+ assertPred!"=="(Date(-1095), Date(-2, 1, 1));
+ assertPred!"=="(Date(-1096), Date(-3, 12, 31));
+ assertPred!"=="(Date(-1460), Date(-3, 1, 1));
+ assertPred!"=="(Date(-1461), Date(-4, 12, 31));
+ assertPred!"=="(Date(-1826), Date(-4, 1, 1));
+ assertPred!"=="(Date(-1827), Date(-5, 12, 31));
+ assertPred!"=="(Date(-2191), Date(-5, 1, 1));
+ assertPred!"=="(Date(-3652), Date(-9, 1, 1));
+
+ assertPred!"=="(Date(-18_262), Date(-49, 1, 1));
+ assertPred!"=="(Date(-18_627), Date(-50, 1, 1));
+ assertPred!"=="(Date(-35_794), Date(-97, 1, 1));
+ assertPred!"=="(Date(-36_160), Date(-99, 12, 31));
+ assertPred!"=="(Date(-36_524), Date(-99, 1, 1));
+ assertPred!"=="(Date(-36_889), Date(-100, 1, 1));
+ assertPred!"=="(Date(-37_254), Date(-101, 1, 1));
+ assertPred!"=="(Date(-38_715), Date(-105, 1, 1));
+ assertPred!"=="(Date(-73_413), Date(-200, 1, 1));
+ assertPred!"=="(Date(-73_778), Date(-201, 1, 1));
+ assertPred!"=="(Date(-109_937), Date(-300, 1, 1));
+ assertPred!"=="(Date(-110_302), Date(-301, 1, 1));
+ assertPred!"=="(Date(-146_097), Date(-400, 12, 31));
+ assertPred!"=="(Date(-146_462), Date(-400, 1, 1));
+ assertPred!"=="(Date(-146_827), Date(-401, 1, 1));
+ assertPred!"=="(Date(-182_621), Date(-499, 1, 1));
+ assertPred!"=="(Date(-182_986), Date(-500, 1, 1));
+ assertPred!"=="(Date(-183_351), Date(-501, 1, 1));
+ assertPred!"=="(Date(-365_607), Date(-1000, 1, 1));
+ assertPred!"=="(Date(-365_972), Date(-1001, 1, 1));
+ assertPred!"=="(Date(-584_387), Date(-1599, 1, 1));
+ assertPred!"=="(Date(-584_388), Date(-1600, 12, 31));
+ assertPred!"=="(Date(-584_753), Date(-1600, 1, 1));
+ assertPred!"=="(Date(-585_118), Date(-1601, 1, 1));
+ assertPred!"=="(Date(-694_325), Date(-1900, 1, 1));
+ assertPred!"=="(Date(-694_690), Date(-1901, 1, 1));
+ assertPred!"=="(Date(-730_484), Date(-1999, 1, 1));
+ assertPred!"=="(Date(-730_485), Date(-2000, 12, 31));
+ assertPred!"=="(Date(-730_850), Date(-2000, 1, 1));
+ assertPred!"=="(Date(-731_215), Date(-2001, 1, 1));
+
+ assertPred!"=="(Date(-734_502), Date(-2010, 1, 1));
+ assertPred!"=="(Date(-734_472), Date(-2010, 1, 31));
+ assertPred!"=="(Date(-734_471), Date(-2010, 2, 1));
+ assertPred!"=="(Date(-734_444), Date(-2010, 2, 28));
+ assertPred!"=="(Date(-734_443), Date(-2010, 3, 1));
+ assertPred!"=="(Date(-734_413), Date(-2010, 3, 31));
+ assertPred!"=="(Date(-734_412), Date(-2010, 4, 1));
+ assertPred!"=="(Date(-734_383), Date(-2010, 4, 30));
+ assertPred!"=="(Date(-734_382), Date(-2010, 5, 1));
+ assertPred!"=="(Date(-734_352), Date(-2010, 5, 31));
+ assertPred!"=="(Date(-734_351), Date(-2010, 6, 1));
+ assertPred!"=="(Date(-734_322), Date(-2010, 6, 30));
+ assertPred!"=="(Date(-734_321), Date(-2010, 7, 1));
+ assertPred!"=="(Date(-734_291), Date(-2010, 7, 31));
+ assertPred!"=="(Date(-734_290), Date(-2010, 8, 1));
+ assertPred!"=="(Date(-734_260), Date(-2010, 8, 31));
+ assertPred!"=="(Date(-734_259), Date(-2010, 9, 1));
+ assertPred!"=="(Date(-734_230), Date(-2010, 9, 30));
+ assertPred!"=="(Date(-734_229), Date(-2010, 10, 1));
+ assertPred!"=="(Date(-734_199), Date(-2010, 10, 31));
+ assertPred!"=="(Date(-734_198), Date(-2010, 11, 1));
+ assertPred!"=="(Date(-734_169), Date(-2010, 11, 30));
+ assertPred!"=="(Date(-734_168), Date(-2010, 12, 1));
+ assertPred!"=="(Date(-734_138), Date(-2010, 12, 31));
+
+ assertPred!"=="(Date(-735_202), Date(-2012, 2, 1));
+ assertPred!"=="(Date(-735_175), Date(-2012, 2, 28));
+ assertPred!"=="(Date(-735_174), Date(-2012, 2, 29));
+ assertPred!"=="(Date(-735_173), Date(-2012, 3, 1));
+
+ assertPred!"=="(Date(-1_373_427), Date(-3760, 9, 7)); //Start of the Hebrew Calendar
+ }
+
+
+ /++
+ Compares this Date with the given Date.
+
+ Returns:
+ $(TABLE
+ $(TR $(TD this < rhs) $(TD < 0))
+ $(TR $(TD this == rhs) $(TD 0))
+ $(TR $(TD this > rhs) $(TD > 0))
+ )
+ +/
+ int opCmp(in Date rhs) const pure nothrow
+ {
+ if(_year < rhs._year)
+ return -1;
+ if(_year > rhs._year)
+ return 1;
+
+ if(_month < rhs._month)
+ return -1;
+ if(_month > rhs._month)
+ return 1;
+
+ if(_day < rhs._day)
+ return -1;
+ if(_day > rhs._day)
+ return 1;
+
+ return 0;
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!("opCmp", "==")(Date(1, 1, 1), Date.init);
+
+ assertPred!("opCmp", "==")(Date(1999, 1, 1), Date(1999, 1, 1));
+ assertPred!("opCmp", "==")(Date(1, 7, 1), Date(1, 7, 1));
+ assertPred!("opCmp", "==")(Date(1, 1, 6), Date(1, 1, 6));
+
+ assertPred!("opCmp", "==")(Date(1999, 7, 1), Date(1999, 7, 1));
+ assertPred!("opCmp", "==")(Date(1999, 7, 6), Date(1999, 7, 6));
+
+ assertPred!("opCmp", "==")(Date(1, 7, 6), Date(1, 7, 6));
+
+ assertPred!("opCmp", "<")(Date(1999, 7, 6), Date(2000, 7, 6));
+ assertPred!("opCmp", ">")(Date(2000, 7, 6), Date(1999, 7, 6));
+ assertPred!("opCmp", "<")(Date(1999, 7, 6), Date(1999, 8, 6));
+ assertPred!("opCmp", ">")(Date(1999, 8, 6), Date(1999, 7, 6));
+ assertPred!("opCmp", "<")(Date(1999, 7, 6), Date(1999, 7, 7));
+ assertPred!("opCmp", ">")(Date(1999, 7, 7), Date(1999, 7, 6));
+
+ assertPred!("opCmp", "<")(Date(1999, 8, 7), Date(2000, 7, 6));
+ assertPred!("opCmp", ">")(Date(2000, 8, 6), Date(1999, 7, 7));
+ assertPred!("opCmp", "<")(Date(1999, 7, 7), Date(2000, 7, 6));
+ assertPred!("opCmp", ">")(Date(2000, 7, 6), Date(1999, 7, 7));
+ assertPred!("opCmp", "<")(Date(1999, 7, 7), Date(1999, 8, 6));
+ assertPred!("opCmp", ">")(Date(1999, 8, 6), Date(1999, 7, 7));
+
+ //Test B.C.
+ assertPred!("opCmp", "==")(Date(0, 1, 1), Date(0, 1, 1));
+ assertPred!("opCmp", "==")(Date(-1, 1, 1), Date(-1, 1, 1));
+ assertPred!("opCmp", "==")(Date(-1, 7, 1), Date(-1, 7, 1));
+ assertPred!("opCmp", "==")(Date(-1, 1, 6), Date(-1, 1, 6));
+
+ assertPred!("opCmp", "==")(Date(-1999, 7, 1), Date(-1999, 7, 1));
+ assertPred!("opCmp", "==")(Date(-1999, 7, 6), Date(-1999, 7, 6));
+
+ assertPred!("opCmp", "==")(Date(-1, 7, 6), Date(-1, 7, 6));
+
+ assertPred!("opCmp", "<")(Date(-2000, 7, 6), Date(-1999, 7, 6));
+ assertPred!("opCmp", ">")(Date(-1999, 7, 6), Date(-2000, 7, 6));
+ assertPred!("opCmp", "<")(Date(-1999, 7, 6), Date(-1999, 8, 6));
+ assertPred!("opCmp", ">")(Date(-1999, 8, 6), Date(-1999, 7, 6));
+ assertPred!("opCmp", "<")(Date(-1999, 7, 6), Date(-1999, 7, 7));
+ assertPred!("opCmp", ">")(Date(-1999, 7, 7), Date(-1999, 7, 6));
+
+ assertPred!("opCmp", "<")(Date(-2000, 8, 6), Date(-1999, 7, 7));
+ assertPred!("opCmp", ">")(Date(-1999, 8, 7), Date(-2000, 7, 6));
+ assertPred!("opCmp", "<")(Date(-2000, 7, 6), Date(-1999, 7, 7));
+ assertPred!("opCmp", ">")(Date(-1999, 7, 7), Date(-2000, 7, 6));
+ assertPred!("opCmp", "<")(Date(-1999, 7, 7), Date(-1999, 8, 6));
+ assertPred!("opCmp", ">")(Date(-1999, 8, 6), Date(-1999, 7, 7));
+
+ //Test Both
+ assertPred!("opCmp", "<")(Date(-1999, 7, 6), Date(1999, 7, 6));
+ assertPred!("opCmp", ">")(Date(1999, 7, 6), Date(-1999, 7, 6));
+
+ assertPred!("opCmp", "<")(Date(-1999, 8, 6), Date(1999, 7, 6));
+ assertPred!("opCmp", ">")(Date(1999, 7, 6), Date(-1999, 8, 6));
+
+ assertPred!("opCmp", "<")(Date(-1999, 7, 7), Date(1999, 7, 6));
+ assertPred!("opCmp", ">")(Date(1999, 7, 6), Date(-1999, 7, 7));
+
+ assertPred!("opCmp", "<")(Date(-1999, 8, 7), Date(1999, 7, 6));
+ assertPred!("opCmp", ">")(Date(1999, 7, 6), Date(-1999, 8, 7));
+
+ assertPred!("opCmp", "<")(Date(-1999, 8, 6), Date(1999, 6, 6));
+ assertPred!("opCmp", ">")(Date(1999, 6, 8), Date(-1999, 7, 6));
+
+ auto date = Date(1999, 7, 6);
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, date.opCmp(date)));
+ static assert(__traits(compiles, date.opCmp(cdate)));
+ static assert(__traits(compiles, date.opCmp(idate)));
+ static assert(__traits(compiles, cdate.opCmp(date)));
+ static assert(__traits(compiles, cdate.opCmp(cdate)));
+ static assert(__traits(compiles, cdate.opCmp(idate)));
+ static assert(__traits(compiles, idate.opCmp(date)));
+ static assert(__traits(compiles, idate.opCmp(cdate)));
+ static assert(__traits(compiles, idate.opCmp(idate)));
+ }
+
+
+ /++
+ Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
+ are B.C.
+
+ Examples:
+--------------------
+assert(Date(1999, 7, 6).year == 1999);
+assert(Date(2010, 10, 4).year == 2010);
+assert(Date(-7, 4, 5).year == -7);
+--------------------
+ +/
+ @property short year() const pure nothrow
+ {
+ return _year;
+ }
+
+ unittest
+ {
+ assertPred!"=="(Date.init.year, 1);
+ assertPred!"=="(Date(1999, 7, 6).year, 1999);
+ assertPred!"=="(Date(-1999, 7, 6).year, -1999);
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, cdate.year == 1999));
+ static assert(__traits(compiles, idate.year == 1999));
+
+ //Verify Examples.
+ assert(Date(1999, 7, 6).year == 1999);
+ assert(Date(2010, 10, 4).year == 2010);
+ assert(Date(-7, 4, 5).year == -7);
+ }
+
+ /++
+ Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
+ are B.C.
+
+ Params:
+ year = The year to set this Date's year to.
+
+ Throws:
+ DateTimeException if the new year is not a leap year and the resulting
+ date would be on February 29th.
+ +/
+ @property void year(int year) pure
+ {
+ enforceValid!"days"(year, _month, _day);
+ _year = cast(short)year;
+ }
+
+ unittest
+ {
+ static void testDateInvalid(Date date, int year)
+ {
+ date.year = year;
+ }
+
+ static void testDate(Date date, int year, in Date expected, size_t line = __LINE__)
+ {
+ date.year = year;
+ assertPred!"=="(date, expected, "", __FILE__, line);
+ }
+
+ assertThrown!DateTimeException(testDateInvalid(Date(4, 2, 29), 1));
+
+ testDate(Date(1, 1, 1), 1999, Date(1999, 1, 1));
+ testDate(Date(1, 1, 1), 0, Date(0, 1, 1));
+ testDate(Date(1, 1, 1), -1999, Date(-1999, 1, 1));
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(!__traits(compiles, cdate.year = 1999));
+ static assert(!__traits(compiles, idate.year = 1999));
+
+ //Verify Examples.
+ assert(Date(1999, 7, 6).year == 1999);
+ assert(Date(2010, 10, 4).year == 2010);
+ assert(Date(-7, 4, 5).year == -7);
+ }
+
+
+ /++
+ Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
+
+ Throws:
+ DateTimeException if $(D isAD) is true.
+
+ Examples:
+--------------------
+assert(Date(0, 1, 1).yearBC == 1);
+assert(Date(-1, 1, 1).yearBC == 2);
+assert(Date(-100, 1, 1).yearBC == 101);
+--------------------
+ +/
+ @property ushort yearBC() const pure
+ {
+ if(isAD)
+ throw new DateTimeException("Year " ~ numToString(_year) ~ " is A.D.");
+ //Once format is pure, this would be a better error message.
+ //throw new DateTimeException(format("%s is A.D.", this));
+
+ return cast(ushort)((_year * -1) + 1);
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException((in Date date){date.yearBC;}(Date(1, 1, 1)));
+
+ auto date = Date(0, 7, 6);
+ const cdate = Date(0, 7, 6);
+ immutable idate = Date(0, 7, 6);
+ static assert(__traits(compiles, date.yearBC));
+ static assert(__traits(compiles, cdate.yearBC));
+ static assert(__traits(compiles, idate.yearBC));
+
+ //Verify Examples.
+ assert(Date(0, 1, 1).yearBC == 1);
+ assert(Date(-1, 1, 1).yearBC == 2);
+ assert(Date(-100, 1, 1).yearBC == 101);
+ }
+
+
+ /++
+ Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
+
+ Params:
+ year = The year B.C. to set this Date's year to.
+
+ Throws:
+ DateTimeException if a non-positive value is given.
+
+ Examples:
+--------------------
+auto date = Date(2010, 1, 1);
+date.yearBC = 1;
+assert(date == Date(0, 1, 1));
+
+date.yearBC = 10;
+assert(date == Date(-9, 1, 1));
+--------------------
+ +/
+ @property void yearBC(int year) pure
+ {
+ if(year <= 0)
+ throw new DateTimeException("The given year is not a year B.C.");
+
+ _year = cast(short)((year - 1) * -1);
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException((Date date){date.yearBC = -1;}(Date(1, 1, 1)));
+
+ {
+ auto date = Date(0, 7, 6);
+ const cdate = Date(0, 7, 6);
+ immutable idate = Date(0, 7, 6);
+ static assert(__traits(compiles, date.yearBC = 7));
+ static assert(!__traits(compiles, cdate.yearBC = 7));
+ static assert(!__traits(compiles, idate.yearBC = 7));
+ }
+
+ //Verify Examples.
+ {
+ auto date = Date(2010, 1, 1);
+ date.yearBC = 1;
+ assert(date == Date(0, 1, 1));
+
+ date.yearBC = 10;
+ assert(date == Date(-9, 1, 1));
+ }
+ }
+
+
+ /++
+ Month of a Gregorian Year.
+
+ Examples:
+--------------------
+assert(Date(1999, 7, 6).month == 7);
+assert(Date(2010, 10, 4).month == 10);
+assert(Date(-7, 4, 5).month == 4);
+--------------------
+ +/
+ @property Month month() const pure nothrow
+ {
+ return _month;
+ }
+
+ unittest
+ {
+ assertPred!"=="(Date.init.month, 1);
+ assertPred!"=="(Date(1999, 7, 6).month, 7);
+ assertPred!"=="(Date(-1999, 7, 6).month, 7);
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, cdate.month == 7));
+ static assert(__traits(compiles, idate.month == 7));
+
+ //Verify Examples.
+ assert(Date(1999, 7, 6).month == 7);
+ assert(Date(2010, 10, 4).month == 10);
+ assert(Date(-7, 4, 5).month == 4);
+ }
+
+ /++
+ Month of a Gregorian Year.
+
+ Params:
+ month = The month to set this Date's month to.
+
+ Throws:
+ DateTimeException if the given month is not a valid month or if
+ the current day would not be valid in the given month.
+ +/
+ @property void month(Month month) pure
+ {
+ enforceValid!"months"(month);
+ enforceValid!"days"(_year, month, _day);
+ _month = cast(Month)month;
+ }
+
+ unittest
+ {
+ static void testDate(Date date, Month month, in Date expected = Date.init, size_t line = __LINE__)
+ {
+ date.month = month;
+ assert(expected != Date.init);
+ assertPred!"=="(date, expected, "", __FILE__, line);
+ }
+
+ assertThrown!DateTimeException(testDate(Date(1, 1, 1), cast(Month)0));
+ assertThrown!DateTimeException(testDate(Date(1, 1, 1), cast(Month)13));
+ assertThrown!DateTimeException(testDate(Date(1, 1, 29), cast(Month)2));
+ assertThrown!DateTimeException(testDate(Date(0, 1, 30), cast(Month)2));
+
+ testDate(Date(1, 1, 1), cast(Month)7, Date(1, 7, 1));
+ testDate(Date(-1, 1, 1), cast(Month)7, Date(-1, 7, 1));
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(!__traits(compiles, cdate.month = 7));
+ static assert(!__traits(compiles, idate.month = 7));
+ }
+
+
+ /++
+ Day of a Gregorian Month.
+
+ Examples:
+--------------------
+assert(Date(1999, 7, 6).day == 6);
+assert(Date(2010, 10, 4).day == 4);
+assert(Date(-7, 4, 5).day == 5);
+--------------------
+ +/
+ @property ubyte day() const pure nothrow
+ {
+ return _day;
+ }
+
+ unittest
+ {
+ assertPred!"=="(Date.init.day, 1);
+ assertPred!"=="(Date(1999, 7, 6).day, 6);
+ assertPred!"=="(Date(-1999, 7, 6).day, 6);
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, cdate.day == 6));
+ static assert(__traits(compiles, idate.day == 6));
+
+ //Verify Examples.
+ assert(Date(1999, 7, 6).day == 6);
+ assert(Date(2010, 10, 4).day == 4);
+ assert(Date(-7, 4, 5).day == 5);
+ }
+
+ /++
+ Day of a Gregorian Month.
+
+ Params:
+ day = The day of the month to set this Date's day to.
+
+ Throws:
+ DateTimeException if the given day is not a valid day of the current month.
+ +/
+ @property void day(int day) pure
+ {
+ enforceValid!"days"(_year, _month, day);
+ _day = cast(ubyte)day;
+ }
+
+ unittest
+ {
+ static void testDate(Date date, int day)
+ {
+ date.day = day;
+ }
+
+ //Test A.D.
+ assertThrown!DateTimeException(testDate(Date(1, 1, 1), 0));
+ assertThrown!DateTimeException(testDate(Date(1, 1, 1), 32));
+ assertThrown!DateTimeException(testDate(Date(1, 2, 1), 29));
+ assertThrown!DateTimeException(testDate(Date(4, 2, 1), 30));
+ assertThrown!DateTimeException(testDate(Date(1, 3, 1), 32));
+ assertThrown!DateTimeException(testDate(Date(1, 4, 1), 31));
+ assertThrown!DateTimeException(testDate(Date(1, 5, 1), 32));
+ assertThrown!DateTimeException(testDate(Date(1, 6, 1), 31));
+ assertThrown!DateTimeException(testDate(Date(1, 7, 1), 32));
+ assertThrown!DateTimeException(testDate(Date(1, 8, 1), 32));
+ assertThrown!DateTimeException(testDate(Date(1, 9, 1), 31));
+ assertThrown!DateTimeException(testDate(Date(1, 10, 1), 32));
+ assertThrown!DateTimeException(testDate(Date(1, 11, 1), 31));
+ assertThrown!DateTimeException(testDate(Date(1, 12, 1), 32));
+
+ assertNotThrown!DateTimeException(testDate(Date(1, 1, 1), 31));
+ assertNotThrown!DateTimeException(testDate(Date(1, 2, 1), 28));
+ assertNotThrown!DateTimeException(testDate(Date(4, 2, 1), 29));
+ assertNotThrown!DateTimeException(testDate(Date(1, 3, 1), 31));
+ assertNotThrown!DateTimeException(testDate(Date(1, 4, 1), 30));
+ assertNotThrown!DateTimeException(testDate(Date(1, 5, 1), 31));
+ assertNotThrown!DateTimeException(testDate(Date(1, 6, 1), 30));
+ assertNotThrown!DateTimeException(testDate(Date(1, 7, 1), 31));
+ assertNotThrown!DateTimeException(testDate(Date(1, 8, 1), 31));
+ assertNotThrown!DateTimeException(testDate(Date(1, 9, 1), 30));
+ assertNotThrown!DateTimeException(testDate(Date(1, 10, 1), 31));
+ assertNotThrown!DateTimeException(testDate(Date(1, 11, 1), 30));
+ assertNotThrown!DateTimeException(testDate(Date(1, 12, 1), 31));
+
+ {
+ auto date = Date(1, 1, 1);
+ date.day = 6;
+ assertPred!"=="(date, Date(1, 1, 6));
+ }
+
+ //Test B.C.
+ assertThrown!DateTimeException(testDate(Date(-1, 1, 1), 0));
+ assertThrown!DateTimeException(testDate(Date(-1, 1, 1), 32));
+ assertThrown!DateTimeException(testDate(Date(-1, 2, 1), 29));
+ assertThrown!DateTimeException(testDate(Date(0, 2, 1), 30));
+ assertThrown!DateTimeException(testDate(Date(-1, 3, 1), 32));
+ assertThrown!DateTimeException(testDate(Date(-1, 4, 1), 31));
+ assertThrown!DateTimeException(testDate(Date(-1, 5, 1), 32));
+ assertThrown!DateTimeException(testDate(Date(-1, 6, 1), 31));
+ assertThrown!DateTimeException(testDate(Date(-1, 7, 1), 32));
+ assertThrown!DateTimeException(testDate(Date(-1, 8, 1), 32));
+ assertThrown!DateTimeException(testDate(Date(-1, 9, 1), 31));
+ assertThrown!DateTimeException(testDate(Date(-1, 10, 1), 32));
+ assertThrown!DateTimeException(testDate(Date(-1, 11, 1), 31));
+ assertThrown!DateTimeException(testDate(Date(-1, 12, 1), 32));
+
+ assertNotThrown!DateTimeException(testDate(Date(-1, 1, 1), 31));
+ assertNotThrown!DateTimeException(testDate(Date(-1, 2, 1), 28));
+ assertNotThrown!DateTimeException(testDate(Date(0, 2, 1), 29));
+ assertNotThrown!DateTimeException(testDate(Date(-1, 3, 1), 31));
+ assertNotThrown!DateTimeException(testDate(Date(-1, 4, 1), 30));
+ assertNotThrown!DateTimeException(testDate(Date(-1, 5, 1), 31));
+ assertNotThrown!DateTimeException(testDate(Date(-1, 6, 1), 30));
+ assertNotThrown!DateTimeException(testDate(Date(-1, 7, 1), 31));
+ assertNotThrown!DateTimeException(testDate(Date(-1, 8, 1), 31));
+ assertNotThrown!DateTimeException(testDate(Date(-1, 9, 1), 30));
+ assertNotThrown!DateTimeException(testDate(Date(-1, 10, 1), 31));
+ assertNotThrown!DateTimeException(testDate(Date(-1, 11, 1), 30));
+ assertNotThrown!DateTimeException(testDate(Date(-1, 12, 1), 31));
+
+ {
+ auto date = Date(-1, 1, 1);
+ date.day = 6;
+ assertPred!"=="(date, Date(-1, 1, 6));
+ }
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(!__traits(compiles, cdate.day = 6));
+ static assert(!__traits(compiles, idate.day = 6));
+ }
+
+
+ /++
+ Adds the given number of years to this Date. A negative number will subtract.
+
+ Note that if day overflow is allowed, and the date is Febuary 29th of a
+ leap year, and the new year is not a leap year, then the date is shifted
+ to March 1st. If day overflow is not allowed, then the date is shifted to
+ February 28th.
+
+ Params:
+ years = The number of years to add to this Date.
+ allowOverflow = Whether the days should be allowed to overflow, causing
+ the month to increment.
+
+ Examples:
+--------------------
+auto date1 = Date(2010, 1, 1);
+date1.add!"years"(1);
+assert(date1 == Date(2011, 1, 1));
+
+auto date2 = Date(2010, 1, 1);
+date2.add!"years"(-1);
+assert(date2 == Date(2009, 1, 1));
+
+auto date3 = Date(2000, 2, 29);
+date3.add!"years"(1);
+assert(date3 == Date(2001, 3, 1));
+
+auto date4 = Date(2000, 2, 29);
+date4.add!"years"(1, AllowDayOverflow.no);
+assert(date4 == Date(2001, 2, 28));
+--------------------
+ +/
+ /+ref Date+/ void add(string units)(long years, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) pure nothrow
+ if(units == "years")
+ {
+ immutable newYear = _year + years;
+
+ _year += years;
+
+ if(_month == Month.feb && _day == 29 && !yearIsLeapYear(_year))
+ {
+ if(allowOverflow == AllowDayOverflow.yes)
+ {
+ _month = Month.mar;
+ _day = 1;
+ }
+ else
+ _day = 28;
+ }
+ }
+
+ //Test add!"years"() with AllowDayOverlow.yes
+ unittest
+ {
+ //Test A.D.
+ {
+ auto date = Date(1999, 7, 6);
+ date.add!"years"(7);
+ assertPred!"=="(date, Date(2006, 7, 6));
+ date.add!"years"(-9);
+ assertPred!"=="(date, Date(1997, 7, 6));
+ }
+
+ {
+ auto date = Date(1999, 2, 28);
+ date.add!"years"(1);
+ assertPred!"=="(date, Date(2000, 2, 28));
+ }
+
+ {
+ auto date = Date(2000, 2, 29);
+ date.add!"years"(-1);
+ assertPred!"=="(date, Date(1999, 3, 1));
+ }
+
+ //Test B.C.
+ {
+ auto date = Date(-1999, 7, 6);
+ date.add!"years"(-7);
+ assertPred!"=="(date, Date(-2006, 7, 6));
+ date.add!"years"(9);
+ assertPred!"=="(date, Date(-1997, 7, 6));
+ }
+
+ {
+ auto date = Date(-1999, 2, 28);
+ date.add!"years"(-1);
+ assertPred!"=="(date, Date(-2000, 2, 28));
+ }
+
+ {
+ auto date = Date(-2000, 2, 29);
+ date.add!"years"(1);
+ assertPred!"=="(date, Date(-1999, 3, 1));
+ }
+
+ //Test Both
+ {
+ auto date = Date(4, 7, 6);
+ date.add!"years"(-5);
+ assertPred!"=="(date, Date(-1, 7, 6));
+ date.add!"years"(5);
+ assertPred!"=="(date, Date(4, 7, 6));
+ }
+
+ {
+ auto date = Date(-4, 7, 6);
+ date.add!"years"(5);
+ assertPred!"=="(date, Date(1, 7, 6));
+ date.add!"years"(-5);
+ assertPred!"=="(date, Date(-4, 7, 6));
+ }
+
+ {
+ auto date = Date(4, 7, 6);
+ date.add!"years"(-8);
+ assertPred!"=="(date, Date(-4, 7, 6));
+ date.add!"years"(8);
+ assertPred!"=="(date, Date(4, 7, 6));
+ }
+
+ {
+ auto date = Date(-4, 7, 6);
+ date.add!"years"(8);
+ assertPred!"=="(date, Date(4, 7, 6));
+ date.add!"years"(-8);
+ assertPred!"=="(date, Date(-4, 7, 6));
+ }
+
+ {
+ auto date = Date(-4, 2, 29);
+ date.add!"years"(5);
+ assertPred!"=="(date, Date(1, 3, 1));
+ }
+
+ {
+ auto date = Date(4, 2, 29);
+ date.add!"years"(-5);
+ assertPred!"=="(date, Date(-1, 3, 1));
+ }
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(!__traits(compiles, cdate.add!"years"(7)));
+ static assert(!__traits(compiles, idate.add!"years"(7)));
+
+ //Verify Examples.
+ auto date1 = Date(2010, 1, 1);
+ date1.add!"years"(1);
+ assert(date1 == Date(2011, 1, 1));
+
+ auto date2 = Date(2010, 1, 1);
+ date2.add!"years"(-1);
+ assert(date2 == Date(2009, 1, 1));
+
+ auto date3 = Date(2000, 2, 29);
+ date3.add!"years"(1);
+ assert(date3 == Date(2001, 3, 1));
+
+ auto date4 = Date(2000, 2, 29);
+ date4.add!"years"(1, AllowDayOverflow.no);
+ assert(date4 == Date(2001, 2, 28));
+ }
+
+ //Test add!"years"() with AllowDayOverlow.no
+ unittest
+ {
+ //Test A.D.
+ {
+ auto date = Date(1999, 7, 6);
+ date.add!"years"(7, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(2006, 7, 6));
+ date.add!"years"(-9, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1997, 7, 6));
+ }
+
+ {
+ auto date = Date(1999, 2, 28);
+ date.add!"years"(1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(2000, 2, 28));
+ }
+
+ {
+ auto date = Date(2000, 2, 29);
+ date.add!"years"(-1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 2, 28));
+ }
+
+ //Test B.C.
+ {
+ auto date = Date(-1999, 7, 6);
+ date.add!"years"(-7, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-2006, 7, 6));
+ date.add!"years"(9, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1997, 7, 6));
+ }
+
+ {
+ auto date = Date(-1999, 2, 28);
+ date.add!"years"(-1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-2000, 2, 28));
+ }
+
+ {
+ auto date = Date(-2000, 2, 29);
+ date.add!"years"(1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 2, 28));
+ }
+
+ //Test Both
+ {
+ auto date = Date(4, 7, 6);
+ date.add!"years"(-5, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1, 7, 6));
+ date.add!"years"(5, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(4, 7, 6));
+ }
+
+ {
+ auto date = Date(-4, 7, 6);
+ date.add!"years"(5, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1, 7, 6));
+ date.add!"years"(-5, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-4, 7, 6));
+ }
+
+ {
+ auto date = Date(4, 7, 6);
+ date.add!"years"(-8, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-4, 7, 6));
+ date.add!"years"(8, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(4, 7, 6));
+ }
+
+ {
+ auto date = Date(-4, 7, 6);
+ date.add!"years"(8, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(4, 7, 6));
+ date.add!"years"(-8, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-4, 7, 6));
+ }
+
+ {
+ auto date = Date(-4, 2, 29);
+ date.add!"years"(5, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1, 2, 28));
+ }
+
+ {
+ auto date = Date(4, 2, 29);
+ date.add!"years"(-5, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1, 2, 28));
+ }
+ }
+
+
+ /++
+ Adds the given number of months to this Date. A negative number will subtract.
+
+ The year will be adjusted along with the month if the number of months added
+ (or subtracted) would overflow (or underflow) the current year.
+
+ Note that if day overflow is allowed, and the date with the adjusted month
+ overflows the number of days in the new month, then the month will be
+ incremented by one, and the days set to the number of days overflowed.
+ (e.g. if the day were 31 and the new month were June, then the month would
+ be incremented to July, and the new day would be 1). If day overflow is
+ not allowed, then the day will be set to the last valid day in the month
+ (e.g. June 31st would become June 30th).
+
+ Params:
+ months = The number of months to add to this Date.
+ allowOverflow = Whether the days should be allowed to overflow, causing
+ the month to increment.
+
+ Examples:
+--------------------
+auto date1 = Date(2010, 1, 1);
+date1.add!"months"(1);
+assert(date1 == Date(2010, 2, 1));
+
+auto date2 = Date(2010, 1, 1);
+date2.add!"months"(-1);
+assert(date2 == Date(2009, 12, 1));
+
+auto date3 = Date(1999, 1, 29);
+date3.add!"months"(1);
+assert(date3 == Date(1999, 3, 1));
+
+auto date4 = Date(1999, 1, 29);
+date4.add!"months"(1, AllowDayOverflow.no);
+assert(date4 == Date(1999, 2, 28));
+--------------------
+ +/
+ /+ref Date+/ void add(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) pure nothrow
+ if(units == "months")
+ {
+ auto years = months / 12;
+ months %= 12;
+ auto newMonth = _month + months;
+
+ if(months < 0)
+ {
+ if(newMonth < 1)
+ {
+ newMonth += 12;
+ --years;
+ }
+ }
+ else if(newMonth > 12)
+ {
+ newMonth -= 12;
+ ++years;
+ }
+
+ _year += years;
+ _month = cast(Month)newMonth;
+
+ immutable currMaxDay = maxDay(_year, _month);
+ immutable overflow = _day - currMaxDay;
+
+ if(overflow > 0)
+ {
+ if(allowOverflow == AllowDayOverflow.yes)
+ {
+ ++_month;
+ _day = cast(ubyte)overflow;
+ }
+ else
+ _day = cast(ubyte)currMaxDay;
+ }
+ }
+
+ //Test add!"months"() with AllowDayOverlow.yes
+ unittest
+ {
+ //Test A.D.
+ {
+ auto date = Date(1999, 7, 6);
+ date.add!"months"(3);
+ assertPred!"=="(date, Date(1999, 10, 6));
+ date.add!"months"(-4);
+ assertPred!"=="(date, Date(1999, 6, 6));
+ }
+
+ {
+ auto date = Date(1999, 7, 6);
+ date.add!"months"(6);
+ assertPred!"=="(date, Date(2000, 1, 6));
+ date.add!"months"(-6);
+ assertPred!"=="(date, Date(1999, 7, 6));
+ }
+
+ {
+ auto date = Date(1999, 7, 6);
+ date.add!"months"(27);
+ assertPred!"=="(date, Date(2001, 10, 6));
+ date.add!"months"(-28);
+ assertPred!"=="(date, Date(1999, 6, 6));
+ }
+
+ {
+ auto date = Date(1999, 5, 31);
+ date.add!"months"(1);
+ assertPred!"=="(date, Date(1999, 7, 1));
+ }
+
+ {
+ auto date = Date(1999, 5, 31);
+ date.add!"months"(-1);
+ assertPred!"=="(date, Date(1999, 5, 1));
+ }
+
+ {
+ auto date = Date(1999, 2, 28);
+ date.add!"months"(12);
+ assertPred!"=="(date, Date(2000, 2, 28));
+ }
+
+ {
+ auto date = Date(2000, 2, 29);
+ date.add!"months"(12);
+ assertPred!"=="(date, Date(2001, 3, 1));
+ }
+
+ {
+ auto date = Date(1999, 7, 31);
+ date.add!"months"(1);
+ assertPred!"=="(date, Date(1999, 8, 31));
+ date.add!"months"(1);
+ assertPred!"=="(date, Date(1999, 10, 1));
+ }
+
+ {
+ auto date = Date(1998, 8, 31);
+ date.add!"months"(13);
+ assertPred!"=="(date, Date(1999, 10, 1));
+ date.add!"months"(-13);
+ assertPred!"=="(date, Date(1998, 9, 1));
+ }
+
+ {
+ auto date = Date(1997, 12, 31);
+ date.add!"months"(13);
+ assertPred!"=="(date, Date(1999, 1, 31));
+ date.add!"months"(-13);
+ assertPred!"=="(date, Date(1997, 12, 31));
+ }
+
+ {
+ auto date = Date(1997, 12, 31);
+ date.add!"months"(14);
+ assertPred!"=="(date, Date(1999, 3, 3));
+ date.add!"months"(-14);
+ assertPred!"=="(date, Date(1998, 1, 3));
+ }
+
+ {
+ auto date = Date(1998, 12, 31);
+ date.add!"months"(14);
+ assertPred!"=="(date, Date(2000, 3, 2));
+ date.add!"months"(-14);
+ assertPred!"=="(date, Date(1999, 1, 2));
+ }
+
+ {
+ auto date = Date(1999, 12, 31);
+ date.add!"months"(14);
+ assertPred!"=="(date, Date(2001, 3, 3));
+ date.add!"months"(-14);
+ assertPred!"=="(date, Date(2000, 1, 3));
+ }
+
+ //Test B.C.
+ {
+ auto date = Date(-1999, 7, 6);
+ date.add!"months"(3);
+ assertPred!"=="(date, Date(-1999, 10, 6));
+ date.add!"months"(-4);
+ assertPred!"=="(date, Date(-1999, 6, 6));
+ }
+
+ {
+ auto date = Date(-1999, 7, 6);
+ date.add!"months"(6);
+ assertPred!"=="(date, Date(-1998, 1, 6));
+ date.add!"months"(-6);
+ assertPred!"=="(date, Date(-1999, 7, 6));
+ }
+
+ {
+ auto date = Date(-1999, 7, 6);
+ date.add!"months"(-27);
+ assertPred!"=="(date, Date(-2001, 4, 6));
+ date.add!"months"(28);
+ assertPred!"=="(date, Date(-1999, 8, 6));
+ }
+
+ {
+ auto date = Date(-1999, 5, 31);
+ date.add!"months"(1);
+ assertPred!"=="(date, Date(-1999, 7, 1));
+ }
+
+ {
+ auto date = Date(-1999, 5, 31);
+ date.add!"months"(-1);
+ assertPred!"=="(date, Date(-1999, 5, 1));
+ }
+
+ {
+ auto date = Date(-1999, 2, 28);
+ date.add!"months"(-12);
+ assertPred!"=="(date, Date(-2000, 2, 28));
+ }
+
+ {
+ auto date = Date(-2000, 2, 29);
+ date.add!"months"(-12);
+ assertPred!"=="(date, Date(-2001, 3, 1));
+ }
+
+ {
+ auto date = Date(-1999, 7, 31);
+ date.add!"months"(1);
+ assertPred!"=="(date, Date(-1999, 8, 31));
+ date.add!"months"(1);
+ assertPred!"=="(date, Date(-1999, 10, 1));
+ }
+
+ {
+ auto date = Date(-1998, 8, 31);
+ date.add!"months"(13);
+ assertPred!"=="(date, Date(-1997, 10, 1));
+ date.add!"months"(-13);
+ assertPred!"=="(date, Date(-1998, 9, 1));
+ }
+
+ {
+ auto date = Date(-1997, 12, 31);
+ date.add!"months"(13);
+ assertPred!"=="(date, Date(-1995, 1, 31));
+ date.add!"months"(-13);
+ assertPred!"=="(date, Date(-1997, 12, 31));
+ }
+
+ {
+ auto date = Date(-1997, 12, 31);
+ date.add!"months"(14);
+ assertPred!"=="(date, Date(-1995, 3, 3));
+ date.add!"months"(-14);
+ assertPred!"=="(date, Date(-1996, 1, 3));
+ }
+
+ {
+ auto date = Date(-2002, 12, 31);
+ date.add!"months"(14);
+ assertPred!"=="(date, Date(-2000, 3, 2));
+ date.add!"months"(-14);
+ assertPred!"=="(date, Date(-2001, 1, 2));
+ }
+
+ {
+ auto date = Date(-2001, 12, 31);
+ date.add!"months"(14);
+ assertPred!"=="(date, Date(-1999, 3, 3));
+ date.add!"months"(-14);
+ assertPred!"=="(date, Date(-2000, 1, 3));
+ }
+
+ //Test Both
+ {
+ auto date = Date(1, 1, 1);
+ date.add!"months"(-1);
+ assertPred!"=="(date, Date(0, 12, 1));
+ date.add!"months"(1);
+ assertPred!"=="(date, Date(1, 1, 1));
+ }
+
+ {
+ auto date = Date(4, 1, 1);
+ date.add!"months"(-48);
+ assertPred!"=="(date, Date(0, 1, 1));
+ date.add!"months"(48);
+ assertPred!"=="(date, Date(4, 1, 1));
+ }
+
+ {
+ auto date = Date(4, 3, 31);
+ date.add!"months"(-49);
+ assertPred!"=="(date, Date(0, 3, 2));
+ date.add!"months"(49);
+ assertPred!"=="(date, Date(4, 4, 2));
+ }
+
+ {
+ auto date = Date(4, 3, 31);
+ date.add!"months"(-85);
+ assertPred!"=="(date, Date(-3, 3, 3));
+ date.add!"months"(85);
+ assertPred!"=="(date, Date(4, 4, 3));
+ }
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(!__traits(compiles, cdate.add!"months"(3)));
+ static assert(!__traits(compiles, idate.add!"months"(3)));
+
+ //Verify Examples.
+ auto date1 = Date(2010, 1, 1);
+ date1.add!"months"(1);
+ assert(date1 == Date(2010, 2, 1));
+
+ auto date2 = Date(2010, 1, 1);
+ date2.add!"months"(-1);
+ assert(date2 == Date(2009, 12, 1));
+
+ auto date3 = Date(1999, 1, 29);
+ date3.add!"months"(1);
+ assert(date3 == Date(1999, 3, 1));
+
+ auto date4 = Date(1999, 1, 29);
+ date4.add!"months"(1, AllowDayOverflow.no);
+ assert(date4 == Date(1999, 2, 28));
+ }
+
+ //Test add!"months"() with AllowDayOverlow.no
+ unittest
+ {
+ //Test A.D.
+ {
+ auto date = Date(1999, 7, 6);
+ date.add!"months"(3, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 10, 6));
+ date.add!"months"(-4, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 6, 6));
+ }
+
+ {
+ auto date = Date(1999, 7, 6);
+ date.add!"months"(6, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(2000, 1, 6));
+ date.add!"months"(-6, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 7, 6));
+ }
+
+ {
+ auto date = Date(1999, 7, 6);
+ date.add!"months"(27, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(2001, 10, 6));
+ date.add!"months"(-28, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 6, 6));
+ }
+
+ {
+ auto date = Date(1999, 5, 31);
+ date.add!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 6, 30));
+ }
+
+ {
+ auto date = Date(1999, 5, 31);
+ date.add!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 4, 30));
+ }
+
+ {
+ auto date = Date(1999, 2, 28);
+ date.add!"months"(12, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(2000, 2, 28));
+ }
+
+ {
+ auto date = Date(2000, 2, 29);
+ date.add!"months"(12, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(2001, 2, 28));
+ }
+
+ {
+ auto date = Date(1999, 7, 31);
+ date.add!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 8, 31));
+ date.add!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 9, 30));
+ }
+
+ {
+ auto date = Date(1998, 8, 31);
+ date.add!"months"(13, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 9, 30));
+ date.add!"months"(-13, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1998, 8, 30));
+ }
+
+ {
+ auto date = Date(1997, 12, 31);
+ date.add!"months"(13, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 1, 31));
+ date.add!"months"(-13, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1997, 12, 31));
+ }
+
+ {
+ auto date = Date(1997, 12, 31);
+ date.add!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 2, 28));
+ date.add!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1997, 12, 28));
+ }
+
+ {
+ auto date = Date(1998, 12, 31);
+ date.add!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(2000, 2, 29));
+ date.add!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1998, 12, 29));
+ }
+
+ {
+ auto date = Date(1999, 12, 31);
+ date.add!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(2001, 2, 28));
+ date.add!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 12, 28));
+ }
+
+ //Test B.C.
+ {
+ auto date = Date(-1999, 7, 6);
+ date.add!"months"(3, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 10, 6));
+ date.add!"months"(-4, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 6, 6));
+ }
+
+ {
+ auto date = Date(-1999, 7, 6);
+ date.add!"months"(6, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1998, 1, 6));
+ date.add!"months"(-6, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 7, 6));
+ }
+
+ {
+ auto date = Date(-1999, 7, 6);
+ date.add!"months"(-27, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-2001, 4, 6));
+ date.add!"months"(28, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 8, 6));
+ }
+
+ {
+ auto date = Date(-1999, 5, 31);
+ date.add!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 6, 30));
+ }
+
+ {
+ auto date = Date(-1999, 5, 31);
+ date.add!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 4, 30));
+ }
+
+ {
+ auto date = Date(-1999, 2, 28);
+ date.add!"months"(-12, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-2000, 2, 28));
+ }
+
+ {
+ auto date = Date(-2000, 2, 29);
+ date.add!"months"(-12, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-2001, 2, 28));
+ }
+
+ {
+ auto date = Date(-1999, 7, 31);
+ date.add!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 8, 31));
+ date.add!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 9, 30));
+ }
+
+ {
+ auto date = Date(-1998, 8, 31);
+ date.add!"months"(13, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1997, 9, 30));
+ date.add!"months"(-13, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1998, 8, 30));
+ }
+
+ {
+ auto date = Date(-1997, 12, 31);
+ date.add!"months"(13, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1995, 1, 31));
+ date.add!"months"(-13, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1997, 12, 31));
+ }
+
+ {
+ auto date = Date(-1997, 12, 31);
+ date.add!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1995, 2, 28));
+ date.add!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1997, 12, 28));
+ }
+
+ {
+ auto date = Date(-2002, 12, 31);
+ date.add!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-2000, 2, 29));
+ date.add!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-2002, 12, 29));
+ }
+
+ {
+ auto date = Date(-2001, 12, 31);
+ date.add!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 2, 28));
+ date.add!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-2001, 12, 28));
+ }
+
+ //Test Both
+ {
+ auto date = Date(1, 1, 1);
+ date.add!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(0, 12, 1));
+ date.add!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1, 1, 1));
+ }
+
+ {
+ auto date = Date(4, 1, 1);
+ date.add!"months"(-48, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(0, 1, 1));
+ date.add!"months"(48, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(4, 1, 1));
+ }
+
+ {
+ auto date = Date(4, 3, 31);
+ date.add!"months"(-49, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(0, 2, 29));
+ date.add!"months"(49, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(4, 3, 29));
+ }
+
+ {
+ auto date = Date(4, 3, 31);
+ date.add!"months"(-85, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-3, 2, 28));
+ date.add!"months"(85, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(4, 3, 28));
+ }
+ }
+
+
+ /++
+ Adds the given number of years to this Date. A negative number will subtract.
+
+ For years, because they are the largest unit in Date, there is no difference
+ between adding or rolling.
+
+ Params:
+ years = The number of years to add to this Date.
+ allowOverflow = Whether the days should be allowed to overflow, causing
+ the month to increment.
+ +/
+ /+ref Date+/ void roll(string units)(long years, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) pure nothrow
+ if(units == "years")
+ {
+ add!"years"(years, allowOverflow);
+ }
+
+ unittest
+ {
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(!__traits(compiles, cdate.roll!"years"(3)));
+ static assert(!__traits(compiles, idate.rolYears(3)));
+ }
+
+
+ /++
+ Adds the given number of months to this Date. A negative number will subtract.
+
+ The difference between rolling and adding is that rolling does not affect
+ larger units. So, if you roll the Date 12 months, you get the exact same
+ Date. However, the days can still be affected due to the differing number
+ of days in each month.
+
+ Params:
+ months = The number of months to add to this Date.
+ allowOverflow = Whether the days should be allowed to overflow, causing
+ the month to increment.
+
+ Examples:
+--------------------
+auto date1 = Date(2010, 1, 1);
+date1.roll!"months"(1);
+assert(date1 == Date(2010, 2, 1));
+
+auto date2 = Date(2010, 1, 1);
+date2.roll!"months"(-1);
+assert(date2 == Date(2010, 12, 1));
+
+auto date3 = Date(1999, 1, 29);
+date3.roll!"months"(1);
+assert(date3 == Date(1999, 3, 1));
+
+auto date4 = Date(1999, 1, 29);
+date4.roll!"months"(1, AllowDayOverflow.no);
+assert(date4 == Date(1999, 2, 28));
+--------------------
+ +/
+ /+ref Date+/ void roll(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) pure nothrow
+ if(units == "months")
+ {
+ months %= 12;
+ auto newMonth = _month + months;
+
+ if(months < 0)
+ {
+ if(newMonth < 1)
+ newMonth += 12;
+ }
+ else
+ {
+ if(newMonth > 12)
+ newMonth -= 12;
+ }
+
+ _month = cast(Month)newMonth;
+
+ immutable currMaxDay = maxDay(_year, _month);
+ immutable overflow = _day - currMaxDay;
+
+ if(overflow > 0)
+ {
+ if(allowOverflow == AllowDayOverflow.yes)
+ {
+ ++_month;
+ _day = cast(ubyte)overflow;
+ }
+ else
+ _day = cast(ubyte)currMaxDay;
+ }
+ }
+
+ //Test roll!"months"() with AllowDayOverlow.yes
+ unittest
+ {
+ //Test A.D.
+ {
+ auto date = Date(1999, 7, 6);
+ date.roll!"months"(3);
+ assertPred!"=="(date, Date(1999, 10, 6));
+ date.roll!"months"(-4);
+ assertPred!"=="(date, Date(1999, 6, 6));
+ }
+
+ {
+ auto date = Date(1999, 7, 6);
+ date.roll!"months"(6);
+ assertPred!"=="(date, Date(1999, 1, 6));
+ date.roll!"months"(-6);
+ assertPred!"=="(date, Date(1999, 7, 6));
+ }
+
+ {
+ auto date = Date(1999, 7, 6);
+ date.roll!"months"(27);
+ assertPred!"=="(date, Date(1999, 10, 6));
+ date.roll!"months"(-28);
+ assertPred!"=="(date, Date(1999, 6, 6));
+ }
+
+ {
+ auto date = Date(1999, 5, 31);
+ date.roll!"months"(1);
+ assertPred!"=="(date, Date(1999, 7, 1));
+ }
+
+ {
+ auto date = Date(1999, 5, 31);
+ date.roll!"months"(-1);
+ assertPred!"=="(date, Date(1999, 5, 1));
+ }
+
+ {
+ auto date = Date(1999, 2, 28);
+ date.roll!"months"(12);
+ assertPred!"=="(date, Date(1999, 2, 28));
+ }
+
+ {
+ auto date = Date(2000, 2, 29);
+ date.roll!"months"(12);
+ assertPred!"=="(date, Date(2000, 2, 29));
+ }
+
+ {
+ auto date = Date(1999, 7, 31);
+ date.roll!"months"(1);
+ assertPred!"=="(date, Date(1999, 8, 31));
+ date.roll!"months"(1);
+ assertPred!"=="(date, Date(1999, 10, 1));
+ }
+
+ {
+ auto date = Date(1998, 8, 31);
+ date.roll!"months"(13);
+ assertPred!"=="(date, Date(1998, 10, 1));
+ date.roll!"months"(-13);
+ assertPred!"=="(date, Date(1998, 9, 1));
+ }
+
+ {
+ auto date = Date(1997, 12, 31);
+ date.roll!"months"(13);
+ assertPred!"=="(date, Date(1997, 1, 31));
+ date.roll!"months"(-13);
+ assertPred!"=="(date, Date(1997, 12, 31));
+ }
+
+ {
+ auto date = Date(1997, 12, 31);
+ date.roll!"months"(14);
+ assertPred!"=="(date, Date(1997, 3, 3));
+ date.roll!"months"(-14);
+ assertPred!"=="(date, Date(1997, 1, 3));
+ }
+
+ {
+ auto date = Date(1998, 12, 31);
+ date.roll!"months"(14);
+ assertPred!"=="(date, Date(1998, 3, 3));
+ date.roll!"months"(-14);
+ assertPred!"=="(date, Date(1998, 1, 3));
+ }
+
+ {
+ auto date = Date(1999, 12, 31);
+ date.roll!"months"(14);
+ assertPred!"=="(date, Date(1999, 3, 3));
+ date.roll!"months"(-14);
+ assertPred!"=="(date, Date(1999, 1, 3));
+ }
+
+ //Test B.C.
+ {
+ auto date = Date(-1999, 7, 6);
+ date.roll!"months"(3);
+ assertPred!"=="(date, Date(-1999, 10, 6));
+ date.roll!"months"(-4);
+ assertPred!"=="(date, Date(-1999, 6, 6));
+ }
+
+ {
+ auto date = Date(-1999, 7, 6);
+ date.roll!"months"(6);
+ assertPred!"=="(date, Date(-1999, 1, 6));
+ date.roll!"months"(-6);
+ assertPred!"=="(date, Date(-1999, 7, 6));
+ }
+
+ {
+ auto date = Date(-1999, 7, 6);
+ date.roll!"months"(-27);
+ assertPred!"=="(date, Date(-1999, 4, 6));
+ date.roll!"months"(28);
+ assertPred!"=="(date, Date(-1999, 8, 6));
+ }
+
+ {
+ auto date = Date(-1999, 5, 31);
+ date.roll!"months"(1);
+ assertPred!"=="(date, Date(-1999, 7, 1));
+ }
+
+ {
+ auto date = Date(-1999, 5, 31);
+ date.roll!"months"(-1);
+ assertPred!"=="(date, Date(-1999, 5, 1));
+ }
+
+ {
+ auto date = Date(-1999, 2, 28);
+ date.roll!"months"(-12);
+ assertPred!"=="(date, Date(-1999, 2, 28));
+ }
+
+ {
+ auto date = Date(-2000, 2, 29);
+ date.roll!"months"(-12);
+ assertPred!"=="(date, Date(-2000, 2, 29));
+ }
+
+ {
+ auto date = Date(-1999, 7, 31);
+ date.roll!"months"(1);
+ assertPred!"=="(date, Date(-1999, 8, 31));
+ date.roll!"months"(1);
+ assertPred!"=="(date, Date(-1999, 10, 1));
+ }
+
+ {
+ auto date = Date(-1998, 8, 31);
+ date.roll!"months"(13);
+ assertPred!"=="(date, Date(-1998, 10, 1));
+ date.roll!"months"(-13);
+ assertPred!"=="(date, Date(-1998, 9, 1));
+ }
+
+ {
+ auto date = Date(-1997, 12, 31);
+ date.roll!"months"(13);
+ assertPred!"=="(date, Date(-1997, 1, 31));
+ date.roll!"months"(-13);
+ assertPred!"=="(date, Date(-1997, 12, 31));
+ }
+
+ {
+ auto date = Date(-1997, 12, 31);
+ date.roll!"months"(14);
+ assertPred!"=="(date, Date(-1997, 3, 3));
+ date.roll!"months"(-14);
+ assertPred!"=="(date, Date(-1997, 1, 3));
+ }
+
+ {
+ auto date = Date(-2002, 12, 31);
+ date.roll!"months"(14);
+ assertPred!"=="(date, Date(-2002, 3, 3));
+ date.roll!"months"(-14);
+ assertPred!"=="(date, Date(-2002, 1, 3));
+ }
+
+ {
+ auto date = Date(-2001, 12, 31);
+ date.roll!"months"(14);
+ assertPred!"=="(date, Date(-2001, 3, 3));
+ date.roll!"months"(-14);
+ assertPred!"=="(date, Date(-2001, 1, 3));
+ }
+
+ //Test Both
+ {
+ auto date = Date(1, 1, 1);
+ date.roll!"months"(-1);
+ assertPred!"=="(date, Date(1, 12, 1));
+ date.roll!"months"(1);
+ assertPred!"=="(date, Date(1, 1, 1));
+ }
+
+ {
+ auto date = Date(4, 1, 1);
+ date.roll!"months"(-48);
+ assertPred!"=="(date, Date(4, 1, 1));
+ date.roll!"months"(48);
+ assertPred!"=="(date, Date(4, 1, 1));
+ }
+
+ {
+ auto date = Date(4, 3, 31);
+ date.roll!"months"(-49);
+ assertPred!"=="(date, Date(4, 3, 2));
+ date.roll!"months"(49);
+ assertPred!"=="(date, Date(4, 4, 2));
+ }
+
+ {
+ auto date = Date(4, 3, 31);
+ date.roll!"months"(-85);
+ assertPred!"=="(date, Date(4, 3, 2));
+ date.roll!"months"(85);
+ assertPred!"=="(date, Date(4, 4, 2));
+ }
+
+ {
+ auto date = Date(-1, 1, 1);
+ date.roll!"months"(-1);
+ assertPred!"=="(date, Date(-1, 12, 1));
+ date.roll!"months"(1);
+ assertPred!"=="(date, Date(-1, 1, 1));
+ }
+
+ {
+ auto date = Date(-4, 1, 1);
+ date.roll!"months"(-48);
+ assertPred!"=="(date, Date(-4, 1, 1));
+ date.roll!"months"(48);
+ assertPred!"=="(date, Date(-4, 1, 1));
+ }
+
+ {
+ auto date = Date(-4, 3, 31);
+ date.roll!"months"(-49);
+ assertPred!"=="(date, Date(-4, 3, 2));
+ date.roll!"months"(49);
+ assertPred!"=="(date, Date(-4, 4, 2));
+ }
+
+ {
+ auto date = Date(-4, 3, 31);
+ date.roll!"months"(-85);
+ assertPred!"=="(date, Date(-4, 3, 2));
+ date.roll!"months"(85);
+ assertPred!"=="(date, Date(-4, 4, 2));
+ }
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(!__traits(compiles, cdate.roll!"months"(3)));
+ static assert(!__traits(compiles, idate.roll!"months"(3)));
+
+ //Verify Examples.
+ auto date1 = Date(2010, 1, 1);
+ date1.roll!"months"(1);
+ assert(date1 == Date(2010, 2, 1));
+
+ auto date2 = Date(2010, 1, 1);
+ date2.roll!"months"(-1);
+ assert(date2 == Date(2010, 12, 1));
+
+ auto date3 = Date(1999, 1, 29);
+ date3.roll!"months"(1);
+ assert(date3 == Date(1999, 3, 1));
+
+ auto date4 = Date(1999, 1, 29);
+ date4.roll!"months"(1, AllowDayOverflow.no);
+ assert(date4 == Date(1999, 2, 28));
+ }
+
+ //Test roll!"months"() with AllowDayOverlow.no
+ unittest
+ {
+ //Test A.D.
+ {
+ auto date = Date(1999, 7, 6);
+ date.roll!"months"(3, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 10, 6));
+ date.roll!"months"(-4, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 6, 6));
+ }
+
+ {
+ auto date = Date(1999, 7, 6);
+ date.roll!"months"(6, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 1, 6));
+ date.roll!"months"(-6, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 7, 6));
+ }
+
+ {
+ auto date = Date(1999, 7, 6);
+ date.roll!"months"(27, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 10, 6));
+ date.roll!"months"(-28, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 6, 6));
+ }
+
+ {
+ auto date = Date(1999, 5, 31);
+ date.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 6, 30));
+ }
+
+ {
+ auto date = Date(1999, 5, 31);
+ date.roll!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 4, 30));
+ }
+
+ {
+ auto date = Date(1999, 2, 28);
+ date.roll!"months"(12, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 2, 28));
+ }
+
+ {
+ auto date = Date(2000, 2, 29);
+ date.roll!"months"(12, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(2000, 2, 29));
+ }
+
+ {
+ auto date = Date(1999, 7, 31);
+ date.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 8, 31));
+ date.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 9, 30));
+ }
+
+ {
+ auto date = Date(1998, 8, 31);
+ date.roll!"months"(13, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1998, 9, 30));
+ date.roll!"months"(-13, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1998, 8, 30));
+ }
+
+ {
+ auto date = Date(1997, 12, 31);
+ date.roll!"months"(13, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1997, 1, 31));
+ date.roll!"months"(-13, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1997, 12, 31));
+ }
+
+ {
+ auto date = Date(1997, 12, 31);
+ date.roll!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1997, 2, 28));
+ date.roll!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1997, 12, 28));
+ }
+
+ {
+ auto date = Date(1998, 12, 31);
+ date.roll!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1998, 2, 28));
+ date.roll!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1998, 12, 28));
+ }
+
+ {
+ auto date = Date(1999, 12, 31);
+ date.roll!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 2, 28));
+ date.roll!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1999, 12, 28));
+ }
+
+ //Test B.C.
+ {
+ auto date = Date(-1999, 7, 6);
+ date.roll!"months"(3, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 10, 6));
+ date.roll!"months"(-4, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 6, 6));
+ }
+
+ {
+ auto date = Date(-1999, 7, 6);
+ date.roll!"months"(6, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 1, 6));
+ date.roll!"months"(-6, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 7, 6));
+ }
+
+ {
+ auto date = Date(-1999, 7, 6);
+ date.roll!"months"(-27, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 4, 6));
+ date.roll!"months"(28, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 8, 6));
+ }
+
+ {
+ auto date = Date(-1999, 5, 31);
+ date.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 6, 30));
+ }
+
+ {
+ auto date = Date(-1999, 5, 31);
+ date.roll!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 4, 30));
+ }
+
+ {
+ auto date = Date(-1999, 2, 28);
+ date.roll!"months"(-12, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 2, 28));
+ }
+
+ {
+ auto date = Date(-2000, 2, 29);
+ date.roll!"months"(-12, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-2000, 2, 29));
+ }
+
+ {
+ auto date = Date(-1999, 7, 31);
+ date.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 8, 31));
+ date.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1999, 9, 30));
+ }
+
+ {
+ auto date = Date(-1998, 8, 31);
+ date.roll!"months"(13, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1998, 9, 30));
+ date.roll!"months"(-13, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1998, 8, 30));
+ }
+
+ {
+ auto date = Date(-1997, 12, 31);
+ date.roll!"months"(13, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1997, 1, 31));
+ date.roll!"months"(-13, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1997, 12, 31));
+ }
+
+ {
+ auto date = Date(-1997, 12, 31);
+ date.roll!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1997, 2, 28));
+ date.roll!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1997, 12, 28));
+ }
+
+ {
+ auto date = Date(-2002, 12, 31);
+ date.roll!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-2002, 2, 28));
+ date.roll!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-2002, 12, 28));
+ }
+
+ {
+ auto date = Date(-2001, 12, 31);
+ date.roll!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-2001, 2, 28));
+ date.roll!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-2001, 12, 28));
+ }
+
+ //Test Both
+ {
+ auto date = Date(1, 1, 1);
+ date.roll!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1, 12, 1));
+ date.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(1, 1, 1));
+ }
+
+ {
+ auto date = Date(4, 1, 1);
+ date.roll!"months"(-48, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(4, 1, 1));
+ date.roll!"months"(48, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(4, 1, 1));
+ }
+
+ {
+ auto date = Date(4, 3, 31);
+ date.roll!"months"(-49, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(4, 2, 29));
+ date.roll!"months"(49, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(4, 3, 29));
+ }
+
+ {
+ auto date = Date(4, 3, 31);
+ date.roll!"months"(-85, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(4, 2, 29));
+ date.roll!"months"(85, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(4, 3, 29));
+ }
+
+ {
+ auto date = Date(-1, 1, 1);
+ date.roll!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1, 12, 1));
+ date.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-1, 1, 1));
+ }
+
+ {
+ auto date = Date(-4, 1, 1);
+ date.roll!"months"(-48, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-4, 1, 1));
+ date.roll!"months"(48, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-4, 1, 1));
+ }
+
+ {
+ auto date = Date(-4, 3, 31);
+ date.roll!"months"(-49, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-4, 2, 29));
+ date.roll!"months"(49, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-4, 3, 29));
+ }
+
+ {
+ auto date = Date(-4, 3, 31);
+ date.roll!"months"(-85, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-4, 2, 29));
+ date.roll!"months"(85, AllowDayOverflow.no);
+ assertPred!"=="(date, Date(-4, 3, 29));
+ }
+ }
+
+
+ /++
+ Adds the given number of days to this Date. A negative number will subtract.
+
+ The difference between rolling and adding is that rolling does not affect
+ larger units. So, if you roll the Date one year's worth of days, then you
+ get the exact same Date.
+
+ Note that there is no $(D add!"days"()) because you can add days to a Date by
+ adding a duration to it.
+
+ Params:
+ days = The number of days to add to this Date.
+
+ Examples:
+--------------------
+auto date = Date(2010, 1, 1);
+date.roll!"days"(1);
+assert(date == Date(2010, 1, 2));
+date.roll!"days"(365);
+assert(date == Date(2010, 1, 26));
+date.roll!"days"(-32);
+assert(date == Date(2010, 1, 25));
+--------------------
+ +/
+ /+ref Date+/ void roll(string units)(long days) pure nothrow
+ if(units == "days")
+ {
+ immutable limit = maxDay(_year, _month);
+ days %= limit;
+ auto newDay = _day + days;
+
+ if(days < 0)
+ {
+ if(newDay < 1)
+ newDay += limit;
+ }
+ else if(newDay > limit)
+ newDay -= limit;
+
+ _day = cast(ubyte)newDay;
+ }
+
+ unittest
+ {
+ //Test A.D.
+ {
+ auto date = Date(1999, 2, 28);
+ date.roll!"days"(1);
+ assertPred!"=="(date, Date(1999, 2, 1));
+ date.roll!"days"(-1);
+ assertPred!"=="(date, Date(1999, 2, 28));
+ }
+
+ {
+ auto date = Date(2000, 2, 28);
+ date.roll!"days"(1);
+ assertPred!"=="(date, Date(2000, 2, 29));
+ date.roll!"days"(1);
+ assertPred!"=="(date, Date(2000, 2, 1));
+ date.roll!"days"(-1);
+ assertPred!"=="(date, Date(2000, 2, 29));
+ }
+
+ {
+ auto date = Date(1999, 6, 30);
+ date.roll!"days"(1);
+ assertPred!"=="(date, Date(1999, 6, 1));
+ date.roll!"days"(-1);
+ assertPred!"=="(date, Date(1999, 6, 30));
+ }
+
+ {
+ auto date = Date(1999, 7, 31);
+ date.roll!"days"(1);
+ assertPred!"=="(date, Date(1999, 7, 1));
+ date.roll!"days"(-1);
+ assertPred!"=="(date, Date(1999, 7, 31));
+ }
+
+ {
+ auto date = Date(1999, 1, 1);
+ date.roll!"days"(-1);
+ assertPred!"=="(date, Date(1999, 1, 31));
+ date.roll!"days"(1);
+ assertPred!"=="(date, Date(1999, 1, 1));
+ }
+
+ {
+ auto date = Date(1999, 7, 6);
+ date.roll!"days"(9);
+ assertPred!"=="(date, Date(1999, 7, 15));
+ date.roll!"days"(-11);
+ assertPred!"=="(date, Date(1999, 7, 4));
+ date.roll!"days"(30);
+ assertPred!"=="(date, Date(1999, 7, 3));
+ date.roll!"days"(-3);
+ assertPred!"=="(date, Date(1999, 7, 31));
+ }
+
+ {
+ auto date = Date(1999, 7, 6);
+ date.roll!"days"(365);
+ assertPred!"=="(date, Date(1999, 7, 30));
+ date.roll!"days"(-365);
+ assertPred!"=="(date, Date(1999, 7, 6));
+ date.roll!"days"(366);
+ assertPred!"=="(date, Date(1999, 7, 31));
+ date.roll!"days"(730);
+ assertPred!"=="(date, Date(1999, 7, 17));
+ date.roll!"days"(-1096);
+ assertPred!"=="(date, Date(1999, 7, 6));
+ }
+
+ {
+ auto date = Date(1999, 2, 6);
+ date.roll!"days"(365);
+ assertPred!"=="(date, Date(1999, 2, 7));
+ date.roll!"days"(-365);
+ assertPred!"=="(date, Date(1999, 2, 6));
+ date.roll!"days"(366);
+ assertPred!"=="(date, Date(1999, 2, 8));
+ date.roll!"days"(730);
+ assertPred!"=="(date, Date(1999, 2, 10));
+ date.roll!"days"(-1096);
+ assertPred!"=="(date, Date(1999, 2, 6));
+ }
+
+ //Test B.C.
+ {
+ auto date = Date(-1999, 2, 28);
+ date.roll!"days"(1);
+ assertPred!"=="(date, Date(-1999, 2, 1));
+ date.roll!"days"(-1);
+ assertPred!"=="(date, Date(-1999, 2, 28));
+ }
+
+ {
+ auto date = Date(-2000, 2, 28);
+ date.roll!"days"(1);
+ assertPred!"=="(date, Date(-2000, 2, 29));
+ date.roll!"days"(1);
+ assertPred!"=="(date, Date(-2000, 2, 1));
+ date.roll!"days"(-1);
+ assertPred!"=="(date, Date(-2000, 2, 29));
+ }
+
+ {
+ auto date = Date(-1999, 6, 30);
+ date.roll!"days"(1);
+ assertPred!"=="(date, Date(-1999, 6, 1));
+ date.roll!"days"(-1);
+ assertPred!"=="(date, Date(-1999, 6, 30));
+ }
+
+ {
+ auto date = Date(-1999, 7, 31);
+ date.roll!"days"(1);
+ assertPred!"=="(date, Date(-1999, 7, 1));
+ date.roll!"days"(-1);
+ assertPred!"=="(date, Date(-1999, 7, 31));
+ }
+
+ {
+ auto date = Date(-1999, 1, 1);
+ date.roll!"days"(-1);
+ assertPred!"=="(date, Date(-1999, 1, 31));
+ date.roll!"days"(1);
+ assertPred!"=="(date, Date(-1999, 1, 1));
+ }
+
+ {
+ auto date = Date(-1999, 7, 6);
+ date.roll!"days"(9);
+ assertPred!"=="(date, Date(-1999, 7, 15));
+ date.roll!"days"(-11);
+ assertPred!"=="(date, Date(-1999, 7, 4));
+ date.roll!"days"(30);
+ assertPred!"=="(date, Date(-1999, 7, 3));
+ date.roll!"days"(-3);
+ assertPred!"=="(date, Date(-1999, 7, 31));
+ }
+
+ {
+ auto date = Date(-1999, 7, 6);
+ date.roll!"days"(365);
+ assertPred!"=="(date, Date(-1999, 7, 30));
+ date.roll!"days"(-365);
+ assertPred!"=="(date, Date(-1999, 7, 6));
+ date.roll!"days"(366);
+ assertPred!"=="(date, Date(-1999, 7, 31));
+ date.roll!"days"(730);
+ assertPred!"=="(date, Date(-1999, 7, 17));
+ date.roll!"days"(-1096);
+ assertPred!"=="(date, Date(-1999, 7, 6));
+ }
+
+ //Test Both
+ {
+ auto date = Date(1, 7, 6);
+ date.roll!"days"(-365);
+ assertPred!"=="(date, Date(1, 7, 13));
+ date.roll!"days"(365);
+ assertPred!"=="(date, Date(1, 7, 6));
+ date.roll!"days"(-731);
+ assertPred!"=="(date, Date(1, 7, 19));
+ date.roll!"days"(730);
+ assertPred!"=="(date, Date(1, 7, 5));
+ }
+
+ {
+ auto date = Date(0, 7, 6);
+ date.roll!"days"(-365);
+ assertPred!"=="(date, Date(0, 7, 13));
+ date.roll!"days"(365);
+ assertPred!"=="(date, Date(0, 7, 6));
+ date.roll!"days"(-731);
+ assertPred!"=="(date, Date(0, 7, 19));
+ date.roll!"days"(730);
+ assertPred!"=="(date, Date(0, 7, 5));
+ }
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(!__traits(compiles, cdate.roll!"days"(12)));
+ static assert(!__traits(compiles, idate.roll!"days"(12)));
+
+ //Verify Examples.
+ auto date = Date(2010, 1, 1);
+ date.roll!"days"(1);
+ assert(date == Date(2010, 1, 2));
+ date.roll!"days"(365);
+ assert(date == Date(2010, 1, 26));
+ date.roll!"days"(-32);
+ assert(date == Date(2010, 1, 25));
+ }
+
+
+ /++
+ Gives the result of adding or subtracting a duration from this Date.
+
+ The legal types of arithmetic for Date using this operator are
+
+ $(TABLE
+ $(TR $(TD Date) $(TD +) $(TD duration) $(TD -->) $(TD Date))
+ $(TR $(TD Date) $(TD -) $(TD duration) $(TD -->) $(TD Date))
+ )
+
+ Params:
+ duration = The duration to add to or subtract from this Date.
+ +/
+ Date opBinary(string op, D)(in D duration) const pure nothrow
+ if((op == "+" || op == "-") &&
+ (is(Unqual!D == Duration) ||
+ is(Unqual!D == TickDuration)))
+ {
+ Date retval = this;
+
+ static if(is(Unqual!D == Duration))
+ immutable days = duration.total!"days";
+ else static if(is(Unqual!D == TickDuration))
+ immutable days = convert!("hnsecs", "days")(duration.hnsecs);
+
+ //Ideally, this would just be
+ //return retval.addDays(unaryFun!(op ~ "a")(days));
+ //But there isn't currently a pure version of unaryFun!().
+
+ static if(op == "+")
+ immutable signedDays = days;
+ else static if(op == "-")
+ immutable signedDays = -days;
+ else
+ static assert(0);
+
+ return retval.addDays(signedDays);
+ }
+
+ unittest
+ {
+ auto date = Date(1999, 7, 6);
+
+ assertPred!"=="(date + dur!"weeks"(7), Date(1999, 8, 24));
+ assertPred!"=="(date + dur!"weeks"(-7), Date(1999, 5, 18));
+ assertPred!"=="(date + dur!"days"(7), Date(1999, 7, 13));
+ assertPred!"=="(date + dur!"days"(-7), Date(1999, 6, 29));
+
+ assertPred!"=="(date + dur!"hours"(24), Date(1999, 7, 7));
+ assertPred!"=="(date + dur!"hours"(-24), Date(1999, 7, 5));
+ assertPred!"=="(date + dur!"minutes"(1440), Date(1999, 7, 7));
+ assertPred!"=="(date + dur!"minutes"(-1440), Date(1999, 7, 5));
+ assertPred!"=="(date + dur!"seconds"(86_400), Date(1999, 7, 7));
+ assertPred!"=="(date + dur!"seconds"(-86_400), Date(1999, 7, 5));
+ assertPred!"=="(date + dur!"msecs"(86_400_000), Date(1999, 7, 7));
+ assertPred!"=="(date + dur!"msecs"(-86_400_000), Date(1999, 7, 5));
+ assertPred!"=="(date + dur!"usecs"(86_400_000_000), Date(1999, 7, 7));
+ assertPred!"=="(date + dur!"usecs"(-86_400_000_000), Date(1999, 7, 5));
+ assertPred!"=="(date + dur!"hnsecs"(864_000_000_000), Date(1999, 7, 7));
+ assertPred!"=="(date + dur!"hnsecs"(-864_000_000_000), Date(1999, 7, 5));
+
+ //This probably only runs in cases where gettimeofday() is used, but it's
+ //hard to do this test correctly with variable ticksPerSec.
+ if(TickDuration.ticksPerSec == 1_000_000)
+ {
+ assertPred!"=="(date + TickDuration.from!"usecs"(86_400_000_000), Date(1999, 7, 7));
+ assertPred!"=="(date + TickDuration.from!"usecs"(-86_400_000_000), Date(1999, 7, 5));
+ }
+
+ assertPred!"=="(date - dur!"weeks"(-7), Date(1999, 8, 24));
+ assertPred!"=="(date - dur!"weeks"(7), Date(1999, 5, 18));
+ assertPred!"=="(date - dur!"days"(-7), Date(1999, 7, 13));
+ assertPred!"=="(date - dur!"days"(7), Date(1999, 6, 29));
+
+ assertPred!"=="(date - dur!"hours"(-24), Date(1999, 7, 7));
+ assertPred!"=="(date - dur!"hours"(24), Date(1999, 7, 5));
+ assertPred!"=="(date - dur!"minutes"(-1440), Date(1999, 7, 7));
+ assertPred!"=="(date - dur!"minutes"(1440), Date(1999, 7, 5));
+ assertPred!"=="(date - dur!"seconds"(-86_400), Date(1999, 7, 7));
+ assertPred!"=="(date - dur!"seconds"(86_400), Date(1999, 7, 5));
+ assertPred!"=="(date - dur!"msecs"(-86_400_000), Date(1999, 7, 7));
+ assertPred!"=="(date - dur!"msecs"(86_400_000), Date(1999, 7, 5));
+ assertPred!"=="(date - dur!"usecs"(-86_400_000_000), Date(1999, 7, 7));
+ assertPred!"=="(date - dur!"usecs"(86_400_000_000), Date(1999, 7, 5));
+ assertPred!"=="(date - dur!"hnsecs"(-864_000_000_000), Date(1999, 7, 7));
+ assertPred!"=="(date - dur!"hnsecs"(864_000_000_000), Date(1999, 7, 5));
+
+ //This probably only runs in cases where gettimeofday() is used, but it's
+ //hard to do this test correctly with variable ticksPerSec.
+ if(TickDuration.ticksPerSec == 1_000_000)
+ {
+ assertPred!"=="(date - TickDuration.from!"usecs"(-86_400_000_000), Date(1999, 7, 7));
+ assertPred!"=="(date - TickDuration.from!"usecs"(86_400_000_000), Date(1999, 7, 5));
+ }
+
+ auto duration = dur!"days"(12);
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, date + duration));
+ static assert(__traits(compiles, cdate + duration));
+ static assert(__traits(compiles, idate + duration));
+
+ static assert(__traits(compiles, date - duration));
+ static assert(__traits(compiles, cdate - duration));
+ static assert(__traits(compiles, idate - duration));
+ }
+
+
+ /++
+ Gives the result of adding or subtracting a duration from this Date, as
+ well as assigning the result to this Date.
+
+ The legal types of arithmetic for Date using this operator are
+
+ $(TABLE
+ $(TR $(TD Date) $(TD +) $(TD duration) $(TD -->) $(TD Date))
+ $(TR $(TD Date) $(TD -) $(TD duration) $(TD -->) $(TD Date))
+ )
+
+ Params:
+ duration = The duration to add to or subtract from this Date.
+ +/
+ /+ref+/ Date opOpAssign(string op, D)(in D duration) pure nothrow
+ if((op == "+" || op == "-") &&
+ (is(Unqual!D == Duration) ||
+ is(Unqual!D == TickDuration)))
+ {
+ static if(is(Unqual!D == Duration))
+ immutable days = duration.total!"days";
+ else static if(is(Unqual!D == TickDuration))
+ immutable days = convert!("hnsecs", "days")(duration.hnsecs);
+
+ //Ideally, this would just be
+ //return addDays(unaryFun!(op ~ "a")(days));
+ //But there isn't currently a pure version of unaryFun!().
+
+ static if(op == "+")
+ immutable signedDays = days;
+ else static if(op == "-")
+ immutable signedDays = -days;
+ else
+ static assert(0);
+
+ return addDays(signedDays);
+ }
+
+ unittest
+ {
+ assertPred!"+="(Date(1999, 7, 6), dur!"weeks"(7), Date(1999, 8, 24));
+ assertPred!"+="(Date(1999, 7, 6), dur!"weeks"(-7), Date(1999, 5, 18));
+ assertPred!"+="(Date(1999, 7, 6), dur!"days"(7), Date(1999, 7, 13));
+ assertPred!"+="(Date(1999, 7, 6), dur!"days"(-7), Date(1999, 6, 29));
+
+ assertPred!"+="(Date(1999, 7, 6), dur!"hours"(24), Date(1999, 7, 7));
+ assertPred!"+="(Date(1999, 7, 6), dur!"hours"(-24), Date(1999, 7, 5));
+ assertPred!"+="(Date(1999, 7, 6), dur!"minutes"(1440), Date(1999, 7, 7));
+ assertPred!"+="(Date(1999, 7, 6), dur!"minutes"(-1440), Date(1999, 7, 5));
+ assertPred!"+="(Date(1999, 7, 6), dur!"seconds"(86_400), Date(1999, 7, 7));
+ assertPred!"+="(Date(1999, 7, 6), dur!"seconds"(-86_400), Date(1999, 7, 5));
+ assertPred!"+="(Date(1999, 7, 6), dur!"msecs"(86_400_000), Date(1999, 7, 7));
+ assertPred!"+="(Date(1999, 7, 6), dur!"msecs"(-86_400_000), Date(1999, 7, 5));
+ assertPred!"+="(Date(1999, 7, 6), dur!"usecs"(86_400_000_000), Date(1999, 7, 7));
+ assertPred!"+="(Date(1999, 7, 6), dur!"usecs"(-86_400_000_000), Date(1999, 7, 5));
+ assertPred!"+="(Date(1999, 7, 6), dur!"hnsecs"(864_000_000_000), Date(1999, 7, 7));
+ assertPred!"+="(Date(1999, 7, 6), dur!"hnsecs"(-864_000_000_000), Date(1999, 7, 5));
+
+ assertPred!"-="(Date(1999, 7, 6), dur!"weeks"(-7), Date(1999, 8, 24));
+ assertPred!"-="(Date(1999, 7, 6), dur!"weeks"(7), Date(1999, 5, 18));
+ assertPred!"-="(Date(1999, 7, 6), dur!"days"(-7), Date(1999, 7, 13));
+ assertPred!"-="(Date(1999, 7, 6), dur!"days"(7), Date(1999, 6, 29));
+
+ assertPred!"-="(Date(1999, 7, 6), dur!"hours"(-24), Date(1999, 7, 7));
+ assertPred!"-="(Date(1999, 7, 6), dur!"hours"(24), Date(1999, 7, 5));
+ assertPred!"-="(Date(1999, 7, 6), dur!"minutes"(-1440), Date(1999, 7, 7));
+ assertPred!"-="(Date(1999, 7, 6), dur!"minutes"(1440), Date(1999, 7, 5));
+ assertPred!"-="(Date(1999, 7, 6), dur!"seconds"(-86_400), Date(1999, 7, 7));
+ assertPred!"-="(Date(1999, 7, 6), dur!"seconds"(86_400), Date(1999, 7, 5));
+ assertPred!"-="(Date(1999, 7, 6), dur!"msecs"(-86_400_000), Date(1999, 7, 7));
+ assertPred!"-="(Date(1999, 7, 6), dur!"msecs"(86_400_000), Date(1999, 7, 5));
+ assertPred!"-="(Date(1999, 7, 6), dur!"usecs"(-86_400_000_000), Date(1999, 7, 7));
+ assertPred!"-="(Date(1999, 7, 6), dur!"usecs"(86_400_000_000), Date(1999, 7, 5));
+ assertPred!"-="(Date(1999, 7, 6), dur!"hnsecs"(-864_000_000_000), Date(1999, 7, 7));
+ assertPred!"-="(Date(1999, 7, 6), dur!"hnsecs"(864_000_000_000), Date(1999, 7, 5));
+
+ auto duration = dur!"days"(12);
+ auto date = Date(1999, 7, 6);
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, date += duration));
+ static assert(!__traits(compiles, cdate += duration));
+ static assert(!__traits(compiles, idate += duration));
+
+ static assert(__traits(compiles, date -= duration));
+ static assert(!__traits(compiles, cdate -= duration));
+ static assert(!__traits(compiles, idate -= duration));
+ }
+
+
+ /++
+ Gives the difference between two Dates.
+
+ The legal types of arithmetic for Date using this operator are
+
+ $(TABLE
+ $(TR $(TD Date) $(TD -) $(TD Date) $(TD -->) $(TD duration))
+ )
+ +/
+ Duration opBinary(string op)(in Date rhs) const pure nothrow
+ if(op == "-")
+ {
+ return dur!"days"(this.dayOfGregorianCal - rhs.dayOfGregorianCal);
+ }
+
+ unittest
+ {
+ auto date = Date(1999, 7, 6);
+
+ assertPred!"=="(Date(1999, 7, 6) - Date(1998, 7, 6), dur!"days"(365));
+ assertPred!"=="(Date(1998, 7, 6) - Date(1999, 7, 6), dur!"days"(-365));
+ assertPred!"=="(Date(1999, 6, 6) - Date(1999, 5, 6), dur!"days"(31));
+ assertPred!"=="(Date(1999, 5, 6) - Date(1999, 6, 6), dur!"days"(-31));
+ assertPred!"=="(Date(1999, 1, 1) - Date(1998, 12, 31), dur!"days"(1));
+ assertPred!"=="(Date(1998, 12, 31) - Date(1999, 1, 1), dur!"days"(-1));
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, date - date));
+ static assert(__traits(compiles, cdate - date));
+ static assert(__traits(compiles, idate - date));
+
+ static assert(__traits(compiles, date - cdate));
+ static assert(__traits(compiles, cdate - cdate));
+ static assert(__traits(compiles, idate - cdate));
+
+ static assert(__traits(compiles, date - idate));
+ static assert(__traits(compiles, cdate - idate));
+ static assert(__traits(compiles, idate - idate));
+ }
+
+
+ /++
+ Returns the difference between the two Dates in months.
+
+ You can get the difference in years by subtracting the year property
+ of two Dates, and you can get the difference in days or weeks by
+ subtracting the Dates themselves and using the Duration that results,
+ but because you cannot convert between months and smaller units without
+ a specific date (which Durations don't have), you cannot get the difference
+ in months without doing some math using both the year and month properties,
+ so this is a convenience function for getting the difference in months.
+
+ Note that the number of days in the months or how far into the month either
+ date is is irrelevant. It is the difference in the month property combined
+ with the difference in years * 12. So, for instance, December 31st and
+ January 1st are one month apart just as December 1st and January 31st are
+ one month apart.
+
+ Params:
+ rhs = The Date to subtract from this one.
+
+ Examples:
+--------------------
+assert(Date(1999, 2, 1).diffMonths(Date(1999, 1, 31)) == 1);
+assert(Date(1999, 1, 31).diffMonths(Date(1999, 2, 1)) == -1);
+assert(Date(1999, 3, 1).diffMonths(Date(1999, 1, 1)) == 2);
+assert(Date(1999, 1, 1).diffMonths(Date(1999, 3, 31)) == -2);
+--------------------
+ +/
+ int diffMonths(in Date rhs) const pure nothrow
+ {
+ immutable yearDiff = _year - rhs._year;
+ immutable monthDiff = _month - rhs._month;
+
+ return yearDiff * 12 + monthDiff;
+ }
+
+ unittest
+ {
+ auto date = Date(1999, 7, 6);
+
+ //Test A.D.
+ assertPred!"=="(date.diffMonths(Date(1998, 6, 5)), 13);
+ assertPred!"=="(date.diffMonths(Date(1998, 7, 5)), 12);
+ assertPred!"=="(date.diffMonths(Date(1998, 8, 5)), 11);
+ assertPred!"=="(date.diffMonths(Date(1998, 9, 5)), 10);
+ assertPred!"=="(date.diffMonths(Date(1998, 10, 5)), 9);
+ assertPred!"=="(date.diffMonths(Date(1998, 11, 5)), 8);
+ assertPred!"=="(date.diffMonths(Date(1998, 12, 5)), 7);
+ assertPred!"=="(date.diffMonths(Date(1999, 1, 5)), 6);
+ assertPred!"=="(date.diffMonths(Date(1999, 2, 6)), 5);
+ assertPred!"=="(date.diffMonths(Date(1999, 3, 6)), 4);
+ assertPred!"=="(date.diffMonths(Date(1999, 4, 6)), 3);
+ assertPred!"=="(date.diffMonths(Date(1999, 5, 6)), 2);
+ assertPred!"=="(date.diffMonths(Date(1999, 6, 6)), 1);
+ assertPred!"=="(date.diffMonths(date), 0);
+ assertPred!"=="(date.diffMonths(Date(1999, 8, 6)), -1);
+ assertPred!"=="(date.diffMonths(Date(1999, 9, 6)), -2);
+ assertPred!"=="(date.diffMonths(Date(1999, 10, 6)), -3);
+ assertPred!"=="(date.diffMonths(Date(1999, 11, 6)), -4);
+ assertPred!"=="(date.diffMonths(Date(1999, 12, 6)), -5);
+ assertPred!"=="(date.diffMonths(Date(2000, 1, 6)), -6);
+ assertPred!"=="(date.diffMonths(Date(2000, 2, 6)), -7);
+ assertPred!"=="(date.diffMonths(Date(2000, 3, 6)), -8);
+ assertPred!"=="(date.diffMonths(Date(2000, 4, 6)), -9);
+ assertPred!"=="(date.diffMonths(Date(2000, 5, 6)), -10);
+ assertPred!"=="(date.diffMonths(Date(2000, 6, 6)), -11);
+ assertPred!"=="(date.diffMonths(Date(2000, 7, 6)), -12);
+ assertPred!"=="(date.diffMonths(Date(2000, 8, 6)), -13);
+
+ assertPred!"=="(Date(1998, 6, 5).diffMonths(date), -13);
+ assertPred!"=="(Date(1998, 7, 5).diffMonths(date), -12);
+ assertPred!"=="(Date(1998, 8, 5).diffMonths(date), -11);
+ assertPred!"=="(Date(1998, 9, 5).diffMonths(date), -10);
+ assertPred!"=="(Date(1998, 10, 5).diffMonths(date), -9);
+ assertPred!"=="(Date(1998, 11, 5).diffMonths(date), -8);
+ assertPred!"=="(Date(1998, 12, 5).diffMonths(date), -7);
+ assertPred!"=="(Date(1999, 1, 5).diffMonths(date), -6);
+ assertPred!"=="(Date(1999, 2, 6).diffMonths(date), -5);
+ assertPred!"=="(Date(1999, 3, 6).diffMonths(date), -4);
+ assertPred!"=="(Date(1999, 4, 6).diffMonths(date), -3);
+ assertPred!"=="(Date(1999, 5, 6).diffMonths(date), -2);
+ assertPred!"=="(Date(1999, 6, 6).diffMonths(date), -1);
+ assertPred!"=="(Date(1999, 8, 6).diffMonths(date), 1);
+ assertPred!"=="(Date(1999, 9, 6).diffMonths(date), 2);
+ assertPred!"=="(Date(1999, 10, 6).diffMonths(date), 3);
+ assertPred!"=="(Date(1999, 11, 6).diffMonths(date), 4);
+ assertPred!"=="(Date(1999, 12, 6).diffMonths(date), 5);
+ assertPred!"=="(Date(2000, 1, 6).diffMonths(date), 6);
+ assertPred!"=="(Date(2000, 2, 6).diffMonths(date), 7);
+ assertPred!"=="(Date(2000, 3, 6).diffMonths(date), 8);
+ assertPred!"=="(Date(2000, 4, 6).diffMonths(date), 9);
+ assertPred!"=="(Date(2000, 5, 6).diffMonths(date), 10);
+ assertPred!"=="(Date(2000, 6, 6).diffMonths(date), 11);
+ assertPred!"=="(Date(2000, 7, 6).diffMonths(date), 12);
+ assertPred!"=="(Date(2000, 8, 6).diffMonths(date), 13);
+
+ assertPred!"=="(date.diffMonths(Date(1999, 6, 30)), 1);
+ assertPred!"=="(date.diffMonths(Date(1999, 7, 1)), 0);
+ assertPred!"=="(date.diffMonths(Date(1999, 7, 6)), 0);
+ assertPred!"=="(date.diffMonths(Date(1999, 7, 11)), 0);
+ assertPred!"=="(date.diffMonths(Date(1999, 7, 16)), 0);
+ assertPred!"=="(date.diffMonths(Date(1999, 7, 21)), 0);
+ assertPred!"=="(date.diffMonths(Date(1999, 7, 26)), 0);
+ assertPred!"=="(date.diffMonths(Date(1999, 7, 31)), 0);
+ assertPred!"=="(date.diffMonths(Date(1999, 8, 1)), -1);
+
+ assertPred!"=="(date.diffMonths(Date(1990, 6, 30)), 109);
+ assertPred!"=="(date.diffMonths(Date(1990, 7, 1)), 108);
+ assertPred!"=="(date.diffMonths(Date(1990, 7, 6)), 108);
+ assertPred!"=="(date.diffMonths(Date(1990, 7, 11)), 108);
+ assertPred!"=="(date.diffMonths(Date(1990, 7, 16)), 108);
+ assertPred!"=="(date.diffMonths(Date(1990, 7, 21)), 108);
+ assertPred!"=="(date.diffMonths(Date(1990, 7, 26)), 108);
+ assertPred!"=="(date.diffMonths(Date(1990, 7, 31)), 108);
+ assertPred!"=="(date.diffMonths(Date(1990, 8, 1)), 107);
+
+ assertPred!"=="(Date(1999, 6, 30).diffMonths(date), -1);
+ assertPred!"=="(Date(1999, 7, 1).diffMonths(date), 0);
+ assertPred!"=="(Date(1999, 7, 6).diffMonths(date), 0);
+ assertPred!"=="(Date(1999, 7, 11).diffMonths(date), 0);
+ assertPred!"=="(Date(1999, 7, 16).diffMonths(date), 0);
+ assertPred!"=="(Date(1999, 7, 21).diffMonths(date), 0);
+ assertPred!"=="(Date(1999, 7, 26).diffMonths(date), 0);
+ assertPred!"=="(Date(1999, 7, 31).diffMonths(date), 0);
+ assertPred!"=="(Date(1999, 8, 1).diffMonths(date), 1);
+
+ assertPred!"=="(Date(1990, 6, 30).diffMonths(date), -109);
+ assertPred!"=="(Date(1990, 7, 1).diffMonths(date), -108);
+ assertPred!"=="(Date(1990, 7, 6).diffMonths(date), -108);
+ assertPred!"=="(Date(1990, 7, 11).diffMonths(date), -108);
+ assertPred!"=="(Date(1990, 7, 16).diffMonths(date), -108);
+ assertPred!"=="(Date(1990, 7, 21).diffMonths(date), -108);
+ assertPred!"=="(Date(1990, 7, 26).diffMonths(date), -108);
+ assertPred!"=="(Date(1990, 7, 31).diffMonths(date), -108);
+ assertPred!"=="(Date(1990, 8, 1).diffMonths(date), -107);
+
+ //Test B.C.
+ auto dateBC = Date(-1999, 7, 6);
+
+ assertPred!"=="(dateBC.diffMonths(Date(-2000, 6, 5)), 13);
+ assertPred!"=="(dateBC.diffMonths(Date(-2000, 7, 5)), 12);
+ assertPred!"=="(dateBC.diffMonths(Date(-2000, 8, 5)), 11);
+ assertPred!"=="(dateBC.diffMonths(Date(-2000, 9, 5)), 10);
+ assertPred!"=="(dateBC.diffMonths(Date(-2000, 10, 5)), 9);
+ assertPred!"=="(dateBC.diffMonths(Date(-2000, 11, 5)), 8);
+ assertPred!"=="(dateBC.diffMonths(Date(-2000, 12, 5)), 7);
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 1, 5)), 6);
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 2, 6)), 5);
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 3, 6)), 4);
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 4, 6)), 3);
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 5, 6)), 2);
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 6, 6)), 1);
+ assertPred!"=="(dateBC.diffMonths(dateBC), 0);
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 8, 6)), -1);
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 9, 6)), -2);
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 10, 6)), -3);
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 11, 6)), -4);
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 12, 6)), -5);
+ assertPred!"=="(dateBC.diffMonths(Date(-1998, 1, 6)), -6);
+ assertPred!"=="(dateBC.diffMonths(Date(-1998, 2, 6)), -7);
+ assertPred!"=="(dateBC.diffMonths(Date(-1998, 3, 6)), -8);
+ assertPred!"=="(dateBC.diffMonths(Date(-1998, 4, 6)), -9);
+ assertPred!"=="(dateBC.diffMonths(Date(-1998, 5, 6)), -10);
+ assertPred!"=="(dateBC.diffMonths(Date(-1998, 6, 6)), -11);
+ assertPred!"=="(dateBC.diffMonths(Date(-1998, 7, 6)), -12);
+ assertPred!"=="(dateBC.diffMonths(Date(-1998, 8, 6)), -13);
+
+ assertPred!"=="(Date(-2000, 6, 5).diffMonths(dateBC), -13);
+ assertPred!"=="(Date(-2000, 7, 5).diffMonths(dateBC), -12);
+ assertPred!"=="(Date(-2000, 8, 5).diffMonths(dateBC), -11);
+ assertPred!"=="(Date(-2000, 9, 5).diffMonths(dateBC), -10);
+ assertPred!"=="(Date(-2000, 10, 5).diffMonths(dateBC), -9);
+ assertPred!"=="(Date(-2000, 11, 5).diffMonths(dateBC), -8);
+ assertPred!"=="(Date(-2000, 12, 5).diffMonths(dateBC), -7);
+ assertPred!"=="(Date(-1999, 1, 5).diffMonths(dateBC), -6);
+ assertPred!"=="(Date(-1999, 2, 6).diffMonths(dateBC), -5);
+ assertPred!"=="(Date(-1999, 3, 6).diffMonths(dateBC), -4);
+ assertPred!"=="(Date(-1999, 4, 6).diffMonths(dateBC), -3);
+ assertPred!"=="(Date(-1999, 5, 6).diffMonths(dateBC), -2);
+ assertPred!"=="(Date(-1999, 6, 6).diffMonths(dateBC), -1);
+ assertPred!"=="(Date(-1999, 8, 6).diffMonths(dateBC), 1);
+ assertPred!"=="(Date(-1999, 9, 6).diffMonths(dateBC), 2);
+ assertPred!"=="(Date(-1999, 10, 6).diffMonths(dateBC), 3);
+ assertPred!"=="(Date(-1999, 11, 6).diffMonths(dateBC), 4);
+ assertPred!"=="(Date(-1999, 12, 6).diffMonths(dateBC), 5);
+ assertPred!"=="(Date(-1998, 1, 6).diffMonths(dateBC), 6);
+ assertPred!"=="(Date(-1998, 2, 6).diffMonths(dateBC), 7);
+ assertPred!"=="(Date(-1998, 3, 6).diffMonths(dateBC), 8);
+ assertPred!"=="(Date(-1998, 4, 6).diffMonths(dateBC), 9);
+ assertPred!"=="(Date(-1998, 5, 6).diffMonths(dateBC), 10);
+ assertPred!"=="(Date(-1998, 6, 6).diffMonths(dateBC), 11);
+ assertPred!"=="(Date(-1998, 7, 6).diffMonths(dateBC), 12);
+ assertPred!"=="(Date(-1998, 8, 6).diffMonths(dateBC), 13);
+
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 6, 30)), 1);
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 7, 1)), 0);
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 7, 6)), 0);
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 7, 11)), 0);
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 7, 16)), 0);
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 7, 21)), 0);
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 7, 26)), 0);
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 7, 31)), 0);
+ assertPred!"=="(dateBC.diffMonths(Date(-1999, 8, 1)), -1);
+
+ assertPred!"=="(dateBC.diffMonths(Date(-2008, 6, 30)), 109);
+ assertPred!"=="(dateBC.diffMonths(Date(-2008, 7, 1)), 108);
+ assertPred!"=="(dateBC.diffMonths(Date(-2008, 7, 6)), 108);
+ assertPred!"=="(dateBC.diffMonths(Date(-2008, 7, 11)), 108);
+ assertPred!"=="(dateBC.diffMonths(Date(-2008, 7, 16)), 108);
+ assertPred!"=="(dateBC.diffMonths(Date(-2008, 7, 21)), 108);
+ assertPred!"=="(dateBC.diffMonths(Date(-2008, 7, 26)), 108);
+ assertPred!"=="(dateBC.diffMonths(Date(-2008, 7, 31)), 108);
+ assertPred!"=="(dateBC.diffMonths(Date(-2008, 8, 1)), 107);
+
+ assertPred!"=="(Date(-1999, 6, 30).diffMonths(dateBC), -1);
+ assertPred!"=="(Date(-1999, 7, 1).diffMonths(dateBC), 0);
+ assertPred!"=="(Date(-1999, 7, 6).diffMonths(dateBC), 0);
+ assertPred!"=="(Date(-1999, 7, 11).diffMonths(dateBC), 0);
+ assertPred!"=="(Date(-1999, 7, 16).diffMonths(dateBC), 0);
+ assertPred!"=="(Date(-1999, 7, 21).diffMonths(dateBC), 0);
+ assertPred!"=="(Date(-1999, 7, 26).diffMonths(dateBC), 0);
+ assertPred!"=="(Date(-1999, 7, 31).diffMonths(dateBC), 0);
+ assertPred!"=="(Date(-1999, 8, 1).diffMonths(dateBC), 1);
+
+ assertPred!"=="(Date(-2008, 6, 30).diffMonths(dateBC), -109);
+ assertPred!"=="(Date(-2008, 7, 1).diffMonths(dateBC), -108);
+ assertPred!"=="(Date(-2008, 7, 6).diffMonths(dateBC), -108);
+ assertPred!"=="(Date(-2008, 7, 11).diffMonths(dateBC), -108);
+ assertPred!"=="(Date(-2008, 7, 16).diffMonths(dateBC), -108);
+ assertPred!"=="(Date(-2008, 7, 21).diffMonths(dateBC), -108);
+ assertPred!"=="(Date(-2008, 7, 26).diffMonths(dateBC), -108);
+ assertPred!"=="(Date(-2008, 7, 31).diffMonths(dateBC), -108);
+ assertPred!"=="(Date(-2008, 8, 1).diffMonths(dateBC), -107);
+
+ //Test Both
+ assertPred!"=="(Date(3, 3, 3).diffMonths(Date(-5, 5, 5)), 94);
+ assertPred!"=="(Date(-5, 5, 5).diffMonths(Date(3, 3, 3)), -94);
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, date.diffMonths(date)));
+ static assert(__traits(compiles, cdate.diffMonths(date)));
+ static assert(__traits(compiles, idate.diffMonths(date)));
+
+ static assert(__traits(compiles, date.diffMonths(cdate)));
+ static assert(__traits(compiles, cdate.diffMonths(cdate)));
+ static assert(__traits(compiles, idate.diffMonths(cdate)));
+
+ static assert(__traits(compiles, date.diffMonths(idate)));
+ static assert(__traits(compiles, cdate.diffMonths(idate)));
+ static assert(__traits(compiles, idate.diffMonths(idate)));
+
+ //Verify Examples.
+ assert(Date(1999, 2, 1).diffMonths(Date(1999, 1, 31)) == 1);
+ assert(Date(1999, 1, 31).diffMonths(Date(1999, 2, 1)) == -1);
+ assert(Date(1999, 3, 1).diffMonths(Date(1999, 1, 1)) == 2);
+ assert(Date(1999, 1, 1).diffMonths(Date(1999, 3, 31)) == -2);
+ }
+
+
+ /++
+ Whether this Date is in a leap year.
+ +/
+ @property bool isLeapYear() const pure nothrow
+ {
+ return yearIsLeapYear(_year);
+ }
+
+ unittest
+ {
+ auto date = Date(1999, 7, 6);
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(!__traits(compiles, date.isLeapYear = true));
+ static assert(!__traits(compiles, cdate.isLeapYear = true));
+ static assert(!__traits(compiles, idate.isLeapYear = true));
+ }
+
+
+ /++
+ Day of the week this Date is on.
+ +/
+ @property DayOfWeek dayOfWeek() const pure nothrow
+ {
+ return getDayOfWeek(dayOfGregorianCal);
+ }
+
+ unittest
+ {
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, cdate.dayOfWeek == DayOfWeek.sun));
+ static assert(!__traits(compiles, cdate.dayOfWeek = DayOfWeek.sun));
+ static assert(__traits(compiles, idate.dayOfWeek == DayOfWeek.sun));
+ static assert(!__traits(compiles, idate.dayOfWeek = DayOfWeek.sun));
+ }
+
+
+ /++
+ Day of the year this Date is on.
+
+ Examples:
+--------------------
+assert(Date(1999, 1, 1).dayOfYear == 1);
+assert(Date(1999, 12, 31).dayOfYear == 365);
+assert(Date(2000, 12, 31).dayOfYear == 366);
+--------------------
+ +/
+ @property ushort dayOfYear() const pure nothrow
+ {
+ switch(_month)
+ {
+ case Month.jan:
+ return _day;
+ case Month.feb:
+ return cast(ushort)(31 + _day);
+ case Month.mar:
+ return cast(ushort)((isLeapYear ? 60 : 59) + _day);
+ case Month.apr:
+ return cast(ushort)((isLeapYear ? 91 : 90) + _day);
+ case Month.may:
+ return cast(ushort)((isLeapYear ? 121 : 120) + _day);
+ case Month.jun:
+ return cast(ushort)((isLeapYear ? 152 : 151) + _day);
+ case Month.jul:
+ return cast(ushort)((isLeapYear ? 182 : 181) + _day);
+ case Month.aug:
+ return cast(ushort)((isLeapYear ? 213 : 212) + _day);
+ case Month.sep:
+ return cast(ushort)((isLeapYear ? 244 : 243) + _day);
+ case Month.oct:
+ return cast(ushort)((isLeapYear ? 274 : 273) + _day);
+ case Month.nov:
+ return cast(ushort)((isLeapYear ? 305 : 304) + _day);
+ case Month.dec:
+ return cast(ushort)((isLeapYear ? 335 : 334) + _day);
+ default:
+ assert(0, "Invalid month.");
+ }
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(Date(1999, 1, 1).dayOfYear, 1);
+ assertPred!"=="(Date(1999, 1, 2).dayOfYear, 2);
+ assertPred!"=="(Date(1999, 1, 3).dayOfYear, 3);
+ assertPred!"=="(Date(1999, 1, 31).dayOfYear, 31);
+ assertPred!"=="(Date(1999, 2, 1).dayOfYear, 32);
+ assertPred!"=="(Date(1999, 2, 28).dayOfYear, 59);
+ assertPred!"=="(Date(1999, 3, 1).dayOfYear, 60);
+ assertPred!"=="(Date(1999, 3, 31).dayOfYear, 90);
+ assertPred!"=="(Date(1999, 4, 1).dayOfYear, 91);
+ assertPred!"=="(Date(1999, 4, 30).dayOfYear, 120);
+ assertPred!"=="(Date(1999, 5, 1).dayOfYear, 121);
+ assertPred!"=="(Date(1999, 5, 31).dayOfYear, 151);
+ assertPred!"=="(Date(1999, 6, 1).dayOfYear, 152);
+ assertPred!"=="(Date(1999, 6, 30).dayOfYear, 181);
+ assertPred!"=="(Date(1999, 7, 1).dayOfYear, 182);
+ assertPred!"=="(Date(1999, 7, 31).dayOfYear, 212);
+ assertPred!"=="(Date(1999, 8, 1).dayOfYear, 213);
+ assertPred!"=="(Date(1999, 8, 31).dayOfYear, 243);
+ assertPred!"=="(Date(1999, 9, 1).dayOfYear, 244);
+ assertPred!"=="(Date(1999, 9, 30).dayOfYear, 273);
+ assertPred!"=="(Date(1999, 10, 1).dayOfYear, 274);
+ assertPred!"=="(Date(1999, 10, 31).dayOfYear, 304);
+ assertPred!"=="(Date(1999, 11, 1).dayOfYear, 305);
+ assertPred!"=="(Date(1999, 11, 30).dayOfYear, 334);
+ assertPred!"=="(Date(1999, 12, 1).dayOfYear, 335);
+ assertPred!"=="(Date(1999, 12, 31).dayOfYear, 365);
+
+ assertPred!"=="(Date(2000, 1, 1).dayOfYear, 1);
+ assertPred!"=="(Date(2000, 2, 1).dayOfYear, 32);
+ assertPred!"=="(Date(2000, 2, 29).dayOfYear, 60);
+ assertPred!"=="(Date(2000, 3, 1).dayOfYear, 61);
+ assertPred!"=="(Date(2000, 3, 31).dayOfYear, 91);
+ assertPred!"=="(Date(2000, 4, 1).dayOfYear, 92);
+ assertPred!"=="(Date(2000, 4, 30).dayOfYear, 121);
+ assertPred!"=="(Date(2000, 5, 1).dayOfYear, 122);
+ assertPred!"=="(Date(2000, 5, 31).dayOfYear, 152);
+ assertPred!"=="(Date(2000, 6, 1).dayOfYear, 153);
+ assertPred!"=="(Date(2000, 6, 30).dayOfYear, 182);
+ assertPred!"=="(Date(2000, 7, 1).dayOfYear, 183);
+ assertPred!"=="(Date(2000, 7, 31).dayOfYear, 213);
+ assertPred!"=="(Date(2000, 8, 1).dayOfYear, 214);
+ assertPred!"=="(Date(2000, 8, 31).dayOfYear, 244);
+ assertPred!"=="(Date(2000, 9, 1).dayOfYear, 245);
+ assertPred!"=="(Date(2000, 9, 30).dayOfYear, 274);
+ assertPred!"=="(Date(2000, 10, 1).dayOfYear, 275);
+ assertPred!"=="(Date(2000, 10, 31).dayOfYear, 305);
+ assertPred!"=="(Date(2000, 11, 1).dayOfYear, 306);
+ assertPred!"=="(Date(2000, 11, 30).dayOfYear, 335);
+ assertPred!"=="(Date(2000, 12, 1).dayOfYear, 336);
+ assertPred!"=="(Date(2000, 12, 31).dayOfYear, 366);
+
+ //Test B.C.
+ assertPred!"=="(Date(0, 1, 1).dayOfYear, 1);
+ assertPred!"=="(Date(0, 12, 31).dayOfYear, 366);
+ assertPred!"=="(Date(1, 1, 1).dayOfYear, 1);
+ assertPred!"=="(Date(1, 12, 31).dayOfYear, 365);
+ assertPred!"=="(Date(-1, 1, 1).dayOfYear, 1);
+ assertPred!"=="(Date(-1, 12, 31).dayOfYear, 365);
+ assertPred!"=="(Date(4, 1, 1).dayOfYear, 1);
+ assertPred!"=="(Date(4, 12, 31).dayOfYear, 366);
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, cdate.dayOfYear == 187));
+ static assert(__traits(compiles, idate.dayOfYear == 187));
+
+ //Verify Examples.
+ assert(Date(1999, 1, 1).dayOfYear == 1);
+ assert(Date(1999, 12, 31).dayOfYear == 365);
+ assert(Date(2000, 12, 31).dayOfYear == 366);
+ }
+
+ /++
+ Day of the year.
+
+ Params:
+ day = The day of the year to set which day of the year this Date is on.
+
+ Throws:
+ DateTimeException if the given day is an invalid day of the year.
+ +/
+ @property void dayOfYear(int day) pure
+ {
+ if(isLeapYear)
+ {
+ if(day <= 0 || day > daysInLeapYear)
+ throw new DateTimeException("Invalid day of the year.");
+
+ switch(day)
+ {
+ case 1: .. case 31:
+ {
+ _month = Month.jan;
+ _day = cast(ubyte)day;
+ break;
+ }
+ case 32: .. case 60:
+ {
+ _month = Month.feb;
+ _day = cast(ubyte)(day - 31);
+ break;
+ }
+ case 61: .. case 91:
+ {
+ _month = Month.mar;
+ _day = cast(ubyte)(day - 60);
+ break;
+ }
+ case 92: .. case 121:
+ {
+ _month = Month.apr;
+ _day = cast(ubyte)(day - 91);
+ break;
+ }
+ case 122: .. case 152:
+ {
+ _month = Month.may;
+ _day = cast(ubyte)(day - 121);
+ break;
+ }
+ case 153: .. case 182:
+ {
+ _month = Month.jun;
+ _day = cast(ubyte)(day - 152);
+ break;
+ }
+ case 183: .. case 213:
+ {
+ _month = Month.jul;
+ _day = cast(ubyte)(day - 182);
+ break;
+ }
+ case 214: .. case 244:
+ {
+ _month = Month.aug;
+ _day = cast(ubyte)(day - 213);
+ break;
+ }
+ case 245: .. case 274:
+ {
+ _month = Month.sep;
+ _day = cast(ubyte)(day - 244);
+ break;
+ }
+ case 275: .. case 305:
+ {
+ _month = Month.oct;
+ _day = cast(ubyte)(day - 274);
+ break;
+ }
+ case 306: .. case 335:
+ {
+ _month = Month.nov;
+ _day = cast(ubyte)(day - 305);
+ break;
+ }
+ case 336: .. case 366:
+ {
+ _month = Month.dec;
+ _day = cast(ubyte)(day - 335);
+ break;
+ }
+ default:
+ assert(0, "Invalid day of the year.");
+ }
+ }
+ else
+ {
+ if(day <= 0 || day > daysInYear)
+ throw new DateTimeException("Invalid day of the year.");
+
+ switch(day)
+ {
+ case 1: .. case 31:
+ {
+ _month = Month.jan;
+ _day = cast(ubyte)day;
+ break;
+ }
+ case 32: .. case 59:
+ {
+ _month = Month.feb;
+ _day = cast(ubyte)(day - 31);
+ break;
+ }
+ case 60: .. case 90:
+ {
+ _month = Month.mar;
+ _day = cast(ubyte)(day - 59);
+ break;
+ }
+ case 91: .. case 120:
+ {
+ _month = Month.apr;
+ _day = cast(ubyte)(day - 90);
+ break;
+ }
+ case 121: .. case 151:
+ {
+ _month = Month.may;
+ _day = cast(ubyte)(day - 120);
+ break;
+ }
+ case 152: .. case 181:
+ {
+ _month = Month.jun;
+ _day = cast(ubyte)(day - 151);
+ break;
+ }
+ case 182: .. case 212:
+ {
+ _month = Month.jul;
+ _day = cast(ubyte)(day - 181);
+ break;
+ }
+ case 213: .. case 243:
+ {
+ _month = Month.aug;
+ _day = cast(ubyte)(day - 212);
+ break;
+ }
+ case 244: .. case 273:
+ {
+ _month = Month.sep;
+ _day = cast(ubyte)(day - 243);
+ break;
+ }
+ case 274: .. case 304:
+ {
+ _month = Month.oct;
+ _day = cast(ubyte)(day - 273);
+ break;
+ }
+ case 305: .. case 334:
+ {
+ _month = Month.nov;
+ _day = cast(ubyte)(day - 304);
+ break;
+ }
+ case 335: .. case 365:
+ {
+ _month = Month.dec;
+ _day = cast(ubyte)(day - 334);
+ break;
+ }
+ default:
+ assert(0, "Invalid day of the year.");
+ }
+ }
+ }
+
+ unittest
+ {
+ auto date = Date(1999, 1, 1);
+
+ void testFunc(int day, int expectedMonth, int expectedDay, size_t line = __LINE__)
+ {
+ date.dayOfYear = day;
+ assertPred!"=="(date.month, expectedMonth, "", __FILE__, line);
+ assertPred!"=="(date.day, expectedDay, "", __FILE__, line);
+ }
+
+ //Test A.D.
+ testFunc(1, 1, 1);
+ testFunc(2, 1, 2);
+ testFunc(3, 1, 3);
+ testFunc(31, 1, 31);
+
+ testFunc(32, 2, 1);
+ testFunc(59, 2, 28);
+ testFunc(60, 3, 1);
+ testFunc(90, 3, 31);
+ testFunc(91, 4, 1);
+ testFunc(120, 4, 30);
+ testFunc(121, 5, 1);
+ testFunc(151, 5, 31);
+ testFunc(152, 6, 1);
+ testFunc(181, 6, 30);
+ testFunc(182, 7, 1);
+ testFunc(212, 7, 31);
+ testFunc(213, 8, 1);
+ testFunc(243, 8, 31);
+ testFunc(244, 9, 1);
+ testFunc(273, 9, 30);
+ testFunc(274, 10, 1);
+ testFunc(304, 10, 31);
+ testFunc(305, 11, 1);
+ testFunc(334, 11, 30);
+ testFunc(335, 12, 1);
+ testFunc(365, 12, 31);
+
+ date.year = 2000;
+ testFunc(1, 1, 1);
+ testFunc(32, 2, 1);
+ testFunc(60, 2, 29);
+ testFunc(61, 3, 1);
+ testFunc(91, 3, 31);
+ testFunc(92, 4, 1);
+ testFunc(121, 4, 30);
+ testFunc(122, 5, 1);
+ testFunc(152, 5, 31);
+ testFunc(153, 6, 1);
+ testFunc(182, 6, 30);
+ testFunc(183, 7, 1);
+ testFunc(213, 7, 31);
+ testFunc(214, 8, 1);
+ testFunc(244, 8, 31);
+ testFunc(245, 9, 1);
+ testFunc(274, 9, 30);
+ testFunc(275, 10, 1);
+ testFunc(305, 10, 31);
+ testFunc(306, 11, 1);
+ testFunc(335, 11, 30);
+ testFunc(336, 12, 1);
+ testFunc(366, 12, 31);
+
+ //Test B.C.
+ date.year = 0;
+ testFunc(1, 1, 1);
+ testFunc(32, 2, 1);
+ testFunc(60, 2, 29);
+ testFunc(61, 3, 1);
+ testFunc(91, 3, 31);
+ testFunc(92, 4, 1);
+ testFunc(121, 4, 30);
+ testFunc(122, 5, 1);
+ testFunc(152, 5, 31);
+ testFunc(153, 6, 1);
+ testFunc(182, 6, 30);
+ testFunc(183, 7, 1);
+ testFunc(213, 7, 31);
+ testFunc(214, 8, 1);
+ testFunc(244, 8, 31);
+ testFunc(245, 9, 1);
+ testFunc(274, 9, 30);
+ testFunc(275, 10, 1);
+ testFunc(305, 10, 31);
+ testFunc(306, 11, 1);
+ testFunc(335, 11, 30);
+ testFunc(336, 12, 1);
+ testFunc(366, 12, 31);
+
+ date.year = -1;
+ testFunc(1, 1, 1);
+ testFunc(2, 1, 2);
+ testFunc(3, 1, 3);
+ testFunc(31, 1, 31);
+
+ testFunc(32, 2, 1);
+ testFunc(59, 2, 28);
+ testFunc(60, 3, 1);
+ testFunc(90, 3, 31);
+ testFunc(91, 4, 1);
+ testFunc(120, 4, 30);
+ testFunc(121, 5, 1);
+ testFunc(151, 5, 31);
+ testFunc(152, 6, 1);
+ testFunc(181, 6, 30);
+ testFunc(182, 7, 1);
+ testFunc(212, 7, 31);
+ testFunc(213, 8, 1);
+ testFunc(243, 8, 31);
+ testFunc(244, 9, 1);
+ testFunc(273, 9, 30);
+ testFunc(274, 10, 1);
+ testFunc(304, 10, 31);
+ testFunc(305, 11, 1);
+ testFunc(334, 11, 30);
+ testFunc(335, 12, 1);
+ testFunc(365, 12, 31);
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(!__traits(compiles, cdate.dayOfYear = 187));
+ static assert(!__traits(compiles, idate.dayOfYear = 187));
+ }
+
+
+ /++
+ The Xth day of the Gregorian Calendar that this Date is on.
+
+ Examples:
+--------------------
+assert(Date(1, 1, 1).dayOfGregorianCal == 1);
+assert(Date(1, 12, 31).dayOfGregorianCal == 365);
+assert(Date(2, 1, 1).dayOfGregorianCal == 366);
+
+assert(Date(0, 12, 31).dayOfGregorianCal == 0);
+assert(Date(0, 1, 1).dayOfGregorianCal == -365);
+assert(Date(-1, 12, 31).dayOfGregorianCal == -366);
+
+assert(Date(2000, 1, 1).dayOfGregorianCal == 730_120);
+assert(Date(2010, 12, 31).dayOfGregorianCal == 734_137);
+--------------------
+ +/
+ @property int dayOfGregorianCal() const pure nothrow
+ {
+ if(isAD)
+ {
+ if(_year == 1)
+ return dayOfYear;
+
+ int years = _year - 1;
+ auto days = (years / 400) * daysIn400Years;
+ years %= 400;
+
+ days += (years / 100) * daysIn100Years;
+ years %= 100;
+
+ days += (years / 4) * daysIn4Years;
+ years %= 4;
+
+ days += years * daysInYear;
+
+ days += dayOfYear;
+
+ return days;
+ }
+ else if(_year == 0)
+ return dayOfYear - daysInLeapYear;
+ else
+ {
+ int years = _year;
+ auto days = (years / 400) * daysIn400Years;
+ years %= 400;
+
+ days += (years / 100) * daysIn100Years;
+ years %= 100;
+
+ days += (years / 4) * daysIn4Years;
+ years %= 4;
+
+ if(years < 0)
+ {
+ days -= daysInLeapYear;
+ ++years;
+
+ days += years * daysInYear;
+
+ days -= daysInYear - dayOfYear;
+ }
+ else
+ days -= daysInLeapYear - dayOfYear;
+
+ return days;
+ }
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(Date(1, 1, 1).dayOfGregorianCal, 1);
+ assertPred!"=="(Date(1, 1, 2).dayOfGregorianCal, 2);
+ assertPred!"=="(Date(1, 2, 1).dayOfGregorianCal, 32);
+ assertPred!"=="(Date(2, 1, 1).dayOfGregorianCal, 366);
+ assertPred!"=="(Date(3, 1, 1).dayOfGregorianCal, 731);
+ assertPred!"=="(Date(4, 1, 1).dayOfGregorianCal, 1096);
+ assertPred!"=="(Date(5, 1, 1).dayOfGregorianCal, 1462);
+ assertPred!"=="(Date(50, 1, 1).dayOfGregorianCal, 17_898);
+ assertPred!"=="(Date(97, 1, 1).dayOfGregorianCal, 35_065);
+ assertPred!"=="(Date(100, 1, 1).dayOfGregorianCal, 36_160);
+ assertPred!"=="(Date(101, 1, 1).dayOfGregorianCal, 36_525);
+ assertPred!"=="(Date(105, 1, 1).dayOfGregorianCal, 37_986);
+ assertPred!"=="(Date(200, 1, 1).dayOfGregorianCal, 72_684);
+ assertPred!"=="(Date(201, 1, 1).dayOfGregorianCal, 73_049);
+ assertPred!"=="(Date(300, 1, 1).dayOfGregorianCal, 109_208);
+ assertPred!"=="(Date(301, 1, 1).dayOfGregorianCal, 109_573);
+ assertPred!"=="(Date(400, 1, 1).dayOfGregorianCal, 145_732);
+ assertPred!"=="(Date(401, 1, 1).dayOfGregorianCal, 146_098);
+ assertPred!"=="(Date(500, 1, 1).dayOfGregorianCal, 182_257);
+ assertPred!"=="(Date(501, 1, 1).dayOfGregorianCal, 182_622);
+ assertPred!"=="(Date(1000, 1, 1).dayOfGregorianCal, 364_878);
+ assertPred!"=="(Date(1001, 1, 1).dayOfGregorianCal, 365_243);
+ assertPred!"=="(Date(1600, 1, 1).dayOfGregorianCal, 584_023);
+ assertPred!"=="(Date(1601, 1, 1).dayOfGregorianCal, 584_389);
+ assertPred!"=="(Date(1900, 1, 1).dayOfGregorianCal, 693_596);
+ assertPred!"=="(Date(1901, 1, 1).dayOfGregorianCal, 693_961);
+ assertPred!"=="(Date(1945, 11, 12).dayOfGregorianCal, 710_347);
+ assertPred!"=="(Date(1999, 1, 1).dayOfGregorianCal, 729_755);
+ assertPred!"=="(Date(2000, 1, 1).dayOfGregorianCal, 730_120);
+ assertPred!"=="(Date(2001, 1, 1).dayOfGregorianCal, 730_486);
+
+ assertPred!"=="(Date(2010, 1, 1).dayOfGregorianCal, 733_773);
+ assertPred!"=="(Date(2010, 1, 31).dayOfGregorianCal, 733_803);
+ assertPred!"=="(Date(2010, 2, 1).dayOfGregorianCal, 733_804);
+ assertPred!"=="(Date(2010, 2, 28).dayOfGregorianCal, 733_831);
+ assertPred!"=="(Date(2010, 3, 1).dayOfGregorianCal, 733_832);
+ assertPred!"=="(Date(2010, 3, 31).dayOfGregorianCal, 733_862);
+ assertPred!"=="(Date(2010, 4, 1).dayOfGregorianCal, 733_863);
+ assertPred!"=="(Date(2010, 4, 30).dayOfGregorianCal, 733_892);
+ assertPred!"=="(Date(2010, 5, 1).dayOfGregorianCal, 733_893);
+ assertPred!"=="(Date(2010, 5, 31).dayOfGregorianCal, 733_923);
+ assertPred!"=="(Date(2010, 6, 1).dayOfGregorianCal, 733_924);
+ assertPred!"=="(Date(2010, 6, 30).dayOfGregorianCal, 733_953);
+ assertPred!"=="(Date(2010, 7, 1).dayOfGregorianCal, 733_954);
+ assertPred!"=="(Date(2010, 7, 31).dayOfGregorianCal, 733_984);
+ assertPred!"=="(Date(2010, 8, 1).dayOfGregorianCal, 733_985);
+ assertPred!"=="(Date(2010, 8, 31).dayOfGregorianCal, 734_015);
+ assertPred!"=="(Date(2010, 9, 1).dayOfGregorianCal, 734_016);
+ assertPred!"=="(Date(2010, 9, 30).dayOfGregorianCal, 734_045);
+ assertPred!"=="(Date(2010, 10, 1).dayOfGregorianCal, 734_046);
+ assertPred!"=="(Date(2010, 10, 31).dayOfGregorianCal, 734_076);
+ assertPred!"=="(Date(2010, 11, 1).dayOfGregorianCal, 734_077);
+ assertPred!"=="(Date(2010, 11, 30).dayOfGregorianCal, 734_106);
+ assertPred!"=="(Date(2010, 12, 1).dayOfGregorianCal, 734_107);
+ assertPred!"=="(Date(2010, 12, 31).dayOfGregorianCal, 734_137);
+
+ assertPred!"=="(Date(2012, 2, 1).dayOfGregorianCal, 734_534);
+ assertPred!"=="(Date(2012, 2, 28).dayOfGregorianCal, 734_561);
+ assertPred!"=="(Date(2012, 2, 29).dayOfGregorianCal, 734_562);
+ assertPred!"=="(Date(2012, 3, 1).dayOfGregorianCal, 734_563);
+
+ //Test B.C.
+ assertPred!"=="(Date(0, 12, 31).dayOfGregorianCal, 0);
+ assertPred!"=="(Date(0, 12, 30).dayOfGregorianCal, -1);
+ assertPred!"=="(Date(0, 12, 1).dayOfGregorianCal, -30);
+ assertPred!"=="(Date(0, 11, 30).dayOfGregorianCal, -31);
+
+ assertPred!"=="(Date(-1, 12, 31).dayOfGregorianCal, -366);
+ assertPred!"=="(Date(-1, 12, 30).dayOfGregorianCal, -367);
+ assertPred!"=="(Date(-1, 1, 1).dayOfGregorianCal, -730);
+ assertPred!"=="(Date(-2, 12, 31).dayOfGregorianCal, -731);
+ assertPred!"=="(Date(-2, 1, 1).dayOfGregorianCal, -1095);
+ assertPred!"=="(Date(-3, 12, 31).dayOfGregorianCal, -1096);
+ assertPred!"=="(Date(-3, 1, 1).dayOfGregorianCal, -1460);
+ assertPred!"=="(Date(-4, 12, 31).dayOfGregorianCal, -1461);
+ assertPred!"=="(Date(-4, 1, 1).dayOfGregorianCal, -1826);
+ assertPred!"=="(Date(-5, 12, 31).dayOfGregorianCal, -1827);
+ assertPred!"=="(Date(-5, 1, 1).dayOfGregorianCal, -2191);
+ assertPred!"=="(Date(-9, 1, 1).dayOfGregorianCal, -3652);
+
+ assertPred!"=="(Date(-49, 1, 1).dayOfGregorianCal, -18_262);
+ assertPred!"=="(Date(-50, 1, 1).dayOfGregorianCal, -18_627);
+ assertPred!"=="(Date(-97, 1, 1).dayOfGregorianCal, -35_794);
+ assertPred!"=="(Date(-99, 12, 31).dayOfGregorianCal, -36_160);
+ assertPred!"=="(Date(-99, 1, 1).dayOfGregorianCal, -36_524);
+ assertPred!"=="(Date(-100, 1, 1).dayOfGregorianCal, -36_889);
+ assertPred!"=="(Date(-101, 1, 1).dayOfGregorianCal, -37_254);
+ assertPred!"=="(Date(-105, 1, 1).dayOfGregorianCal, -38_715);
+ assertPred!"=="(Date(-200, 1, 1).dayOfGregorianCal, -73_413);
+ assertPred!"=="(Date(-201, 1, 1).dayOfGregorianCal, -73_778);
+ assertPred!"=="(Date(-300, 1, 1).dayOfGregorianCal, -109_937);
+ assertPred!"=="(Date(-301, 1, 1).dayOfGregorianCal, -110_302);
+ assertPred!"=="(Date(-400, 12, 31).dayOfGregorianCal, -146_097);
+ assertPred!"=="(Date(-400, 1, 1).dayOfGregorianCal, -146_462);
+ assertPred!"=="(Date(-401, 1, 1).dayOfGregorianCal, -146_827);
+ assertPred!"=="(Date(-499, 1, 1).dayOfGregorianCal, -182_621);
+ assertPred!"=="(Date(-500, 1, 1).dayOfGregorianCal, -182_986);
+ assertPred!"=="(Date(-501, 1, 1).dayOfGregorianCal, -183_351);
+ assertPred!"=="(Date(-1000, 1, 1).dayOfGregorianCal, -365_607);
+ assertPred!"=="(Date(-1001, 1, 1).dayOfGregorianCal, -365_972);
+ assertPred!"=="(Date(-1599, 1, 1).dayOfGregorianCal, -584_387);
+ assertPred!"=="(Date(-1600, 12, 31).dayOfGregorianCal, -584_388);
+ assertPred!"=="(Date(-1600, 1, 1).dayOfGregorianCal, -584_753);
+ assertPred!"=="(Date(-1601, 1, 1).dayOfGregorianCal, -585_118);
+ assertPred!"=="(Date(-1900, 1, 1).dayOfGregorianCal, -694_325);
+ assertPred!"=="(Date(-1901, 1, 1).dayOfGregorianCal, -694_690);
+ assertPred!"=="(Date(-1999, 1, 1).dayOfGregorianCal, -730_484);
+ assertPred!"=="(Date(-2000, 12, 31).dayOfGregorianCal, -730_485);
+ assertPred!"=="(Date(-2000, 1, 1).dayOfGregorianCal, -730_850);
+ assertPred!"=="(Date(-2001, 1, 1).dayOfGregorianCal, -731_215);
+
+ assertPred!"=="(Date(-2010, 1, 1).dayOfGregorianCal, -734_502);
+ assertPred!"=="(Date(-2010, 1, 31).dayOfGregorianCal, -734_472);
+ assertPred!"=="(Date(-2010, 2, 1).dayOfGregorianCal, -734_471);
+ assertPred!"=="(Date(-2010, 2, 28).dayOfGregorianCal, -734_444);
+ assertPred!"=="(Date(-2010, 3, 1).dayOfGregorianCal, -734_443);
+ assertPred!"=="(Date(-2010, 3, 31).dayOfGregorianCal, -734_413);
+ assertPred!"=="(Date(-2010, 4, 1).dayOfGregorianCal, -734_412);
+ assertPred!"=="(Date(-2010, 4, 30).dayOfGregorianCal, -734_383);
+ assertPred!"=="(Date(-2010, 5, 1).dayOfGregorianCal, -734_382);
+ assertPred!"=="(Date(-2010, 5, 31).dayOfGregorianCal, -734_352);
+ assertPred!"=="(Date(-2010, 6, 1).dayOfGregorianCal, -734_351);
+ assertPred!"=="(Date(-2010, 6, 30).dayOfGregorianCal, -734_322);
+ assertPred!"=="(Date(-2010, 7, 1).dayOfGregorianCal, -734_321);
+ assertPred!"=="(Date(-2010, 7, 31).dayOfGregorianCal, -734_291);
+ assertPred!"=="(Date(-2010, 8, 1).dayOfGregorianCal, -734_290);
+ assertPred!"=="(Date(-2010, 8, 31).dayOfGregorianCal, -734_260);
+ assertPred!"=="(Date(-2010, 9, 1).dayOfGregorianCal, -734_259);
+ assertPred!"=="(Date(-2010, 9, 30).dayOfGregorianCal, -734_230);
+ assertPred!"=="(Date(-2010, 10, 1).dayOfGregorianCal, -734_229);
+ assertPred!"=="(Date(-2010, 10, 31).dayOfGregorianCal, -734_199);
+ assertPred!"=="(Date(-2010, 11, 1).dayOfGregorianCal, -734_198);
+ assertPred!"=="(Date(-2010, 11, 30).dayOfGregorianCal, -734_169);
+ assertPred!"=="(Date(-2010, 12, 1).dayOfGregorianCal, -734_168);
+ assertPred!"=="(Date(-2010, 12, 31).dayOfGregorianCal, -734_138);
+
+ assertPred!"=="(Date(-2012, 2, 1).dayOfGregorianCal, -735_202);
+ assertPred!"=="(Date(-2012, 2, 28).dayOfGregorianCal, -735_175);
+ assertPred!"=="(Date(-2012, 2, 29).dayOfGregorianCal, -735_174);
+ assertPred!"=="(Date(-2012, 3, 1).dayOfGregorianCal, -735_173);
+
+ assertPred!"=="(Date(-3760, 9, 7).dayOfGregorianCal, -1_373_427); //Start of Hebrew Calendar
+
+ auto date = Date(1999, 7, 6);
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, date.dayOfGregorianCal));
+ static assert(__traits(compiles, cdate.dayOfGregorianCal));
+ static assert(__traits(compiles, idate.dayOfGregorianCal));
+
+ //Verify Examples.
+ assert(Date(1, 1, 1).dayOfGregorianCal == 1);
+ assert(Date(1, 12, 31).dayOfGregorianCal == 365);
+ assert(Date(2, 1, 1).dayOfGregorianCal == 366);
+
+ assert(Date(0, 12, 31).dayOfGregorianCal == 0);
+ assert(Date(0, 1, 1).dayOfGregorianCal == -365);
+ assert(Date(-1, 12, 31).dayOfGregorianCal == -366);
+
+ assert(Date(2000, 1, 1).dayOfGregorianCal == 730_120);
+ assert(Date(2010, 12, 31).dayOfGregorianCal == 734_137);
+ }
+
+ /++
+ The Xth day of the Gregorian Calendar that this Date is on.
+
+ Params:
+ day = The day of the Gregorian Calendar to set this Date to.
+
+ Examples:
+--------------------
+auto date = Date.init;
+date.dayOfGregorianCal = 1;
+assert(date == Date(1, 1, 1));
+
+date.dayOfGregorianCal = 365;
+assert(date == Date(1, 12, 31));
+
+date.dayOfGregorianCal = 366;
+assert(date == Date(2, 1, 1));
+
+date.dayOfGregorianCal = 0;
+assert(date == Date(0, 12, 31));
+
+date.dayOfGregorianCal = -365;
+assert(date == Date(-0, 1, 1));
+
+date.dayOfGregorianCal = -366;
+assert(date == Date(-1, 12, 31));
+
+date.dayOfGregorianCal = 730_120;
+assert(date == Date(2000, 1, 1));
+
+date.dayOfGregorianCal = 734_137;
+assert(date == Date(2010, 12, 31));
+--------------------
+ +/
+ @property void dayOfGregorianCal(int day) pure nothrow
+ {
+ this = Date(day);
+ }
+
+ unittest
+ {
+ {
+ auto date = Date(1999, 7, 6);
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, date.dayOfGregorianCal = 187));
+ static assert(!__traits(compiles, cdate.dayOfGregorianCal = 187));
+ static assert(!__traits(compiles, idate.dayOfGregorianCal = 187));
+ }
+
+ //Verify Examples.
+ {
+ auto date = Date.init;
+ date.dayOfGregorianCal = 1;
+ assert(date == Date(1, 1, 1));
+
+ date.dayOfGregorianCal = 365;
+ assert(date == Date(1, 12, 31));
+
+ date.dayOfGregorianCal = 366;
+ assert(date == Date(2, 1, 1));
+
+ date.dayOfGregorianCal = 0;
+ assert(date == Date(0, 12, 31));
+
+ date.dayOfGregorianCal = -365;
+ assert(date == Date(-0, 1, 1));
+
+ date.dayOfGregorianCal = -366;
+ assert(date == Date(-1, 12, 31));
+
+ date.dayOfGregorianCal = 730_120;
+ assert(date == Date(2000, 1, 1));
+
+ date.dayOfGregorianCal = 734_137;
+ assert(date == Date(2010, 12, 31));
+ }
+ }
+
+
+ /++
+ The ISO 8601 week of the year that this Date is in.
+
+ See_Also:
+ ISO Week Date
+ +/
+ @property ubyte isoWeek() const pure nothrow
+ {
+ immutable weekday = dayOfWeek;
+ immutable adjustedWeekday = weekday == DayOfWeek.sun ? 7 : weekday;
+ immutable week = (dayOfYear - adjustedWeekday + 10) / 7;
+
+ try
+ {
+ if(week == 53)
+ {
+ switch(Date(_year + 1, 1, 1).dayOfWeek)
+ {
+ case DayOfWeek.mon:
+ case DayOfWeek.tue:
+ case DayOfWeek.wed:
+ case DayOfWeek.thu:
+ return 1;
+ case DayOfWeek.fri:
+ case DayOfWeek.sat:
+ case DayOfWeek.sun:
+ return 53;
+ default:
+ assert(0, "Invalid ISO Week");
+ }
+ }
+ else if(week > 0)
+ return cast(ubyte)week;
+ else
+ return Date(_year - 1, 12, 31).isoWeek;
+ }
+ catch(Exception e)
+ assert(0, "Date's constructor threw.");
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(Date(2009, 12, 28).isoWeek, 53);
+ assertPred!"=="(Date(2009, 12, 29).isoWeek, 53);
+ assertPred!"=="(Date(2009, 12, 30).isoWeek, 53);
+ assertPred!"=="(Date(2009, 12, 31).isoWeek, 53);
+ assertPred!"=="(Date(2010, 1, 1).isoWeek, 53);
+ assertPred!"=="(Date(2010, 1, 2).isoWeek, 53);
+ assertPred!"=="(Date(2010, 1, 3).isoWeek, 53);
+ assertPred!"=="(Date(2010, 1, 4).isoWeek, 1);
+ assertPred!"=="(Date(2010, 1, 5).isoWeek, 1);
+ assertPred!"=="(Date(2010, 1, 6).isoWeek, 1);
+ assertPred!"=="(Date(2010, 1, 7).isoWeek, 1);
+ assertPred!"=="(Date(2010, 1, 8).isoWeek, 1);
+ assertPred!"=="(Date(2010, 1, 9).isoWeek, 1);
+ assertPred!"=="(Date(2010, 1, 10).isoWeek, 1);
+ assertPred!"=="(Date(2010, 1, 11).isoWeek, 2);
+ assertPred!"=="(Date(2010, 12, 31).isoWeek, 52);
+
+ assertPred!"=="(Date(2004, 12, 26).isoWeek, 52);
+ assertPred!"=="(Date(2004, 12, 27).isoWeek, 53);
+ assertPred!"=="(Date(2004, 12, 28).isoWeek, 53);
+ assertPred!"=="(Date(2004, 12, 29).isoWeek, 53);
+ assertPred!"=="(Date(2004, 12, 30).isoWeek, 53);
+ assertPred!"=="(Date(2004, 12, 31).isoWeek, 53);
+ assertPred!"=="(Date(2005, 1, 1).isoWeek, 53);
+ assertPred!"=="(Date(2005, 1, 2).isoWeek, 53);
+
+ assertPred!"=="(Date(2005, 12, 31).isoWeek, 52);
+ assertPred!"=="(Date(2007, 1, 1).isoWeek, 1);
+
+ assertPred!"=="(Date(2007, 12, 30).isoWeek, 52);
+ assertPred!"=="(Date(2007, 12, 31).isoWeek, 1);
+ assertPred!"=="(Date(2008, 1, 1).isoWeek, 1);
+
+ assertPred!"=="(Date(2008, 12, 28).isoWeek, 52);
+ assertPred!"=="(Date(2008, 12, 29).isoWeek, 1);
+ assertPred!"=="(Date(2008, 12, 30).isoWeek, 1);
+ assertPred!"=="(Date(2008, 12, 31).isoWeek, 1);
+ assertPred!"=="(Date(2009, 1, 1).isoWeek, 1);
+ assertPred!"=="(Date(2009, 1, 2).isoWeek, 1);
+ assertPred!"=="(Date(2009, 1, 3).isoWeek, 1);
+ assertPred!"=="(Date(2009, 1, 4).isoWeek, 1);
+
+ //Test B.C.
+ //The algorithm should work identically for both A.D. and B.C. since
+ //it doesn't really take the year into account, so B.C. testing
+ //probably isn't really needed.
+ assertPred!"=="(Date(0, 12, 31).isoWeek, 52);
+ assertPred!"=="(Date(0, 1, 4).isoWeek, 1);
+ assertPred!"=="(Date(0, 1, 1).isoWeek, 52);
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, cdate.isoWeek == 3));
+ static assert(!__traits(compiles, cdate.isoWeek = 3));
+ static assert(__traits(compiles, idate.isoWeek == 3));
+ static assert(!__traits(compiles, idate.isoWeek = 3));
+ }
+
+
+ /++
+ Date for the last day in the month that this Date is in.
+
+ Examples:
+--------------------
+assert(Date(1999, 1, 6).endOfMonth == Date(1999, 1, 31));
+assert(Date(1999, 2, 7).endOfMonth == Date(1999, 2, 28));
+assert(Date(2000, 2, 7).endOfMonth == Date(1999, 2, 29));
+assert(Date(2000, 6, 4).endOfMonth == Date(1999, 6, 30));
+--------------------
+ +/
+ @property Date endOfMonth() const pure nothrow
+ {
+ try
+ return Date(_year, _month, maxDay(_year, _month));
+ catch(Exception e)
+ assert(0, "Date's constructor threw.");
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(Date(1999, 1, 1).endOfMonth, Date(1999, 1, 31));
+ assertPred!"=="(Date(1999, 2, 1).endOfMonth, Date(1999, 2, 28));
+ assertPred!"=="(Date(2000, 2, 1).endOfMonth, Date(2000, 2, 29));
+ assertPred!"=="(Date(1999, 3, 1).endOfMonth, Date(1999, 3, 31));
+ assertPred!"=="(Date(1999, 4, 1).endOfMonth, Date(1999, 4, 30));
+ assertPred!"=="(Date(1999, 5, 1).endOfMonth, Date(1999, 5, 31));
+ assertPred!"=="(Date(1999, 6, 1).endOfMonth, Date(1999, 6, 30));
+ assertPred!"=="(Date(1999, 7, 1).endOfMonth, Date(1999, 7, 31));
+ assertPred!"=="(Date(1999, 8, 1).endOfMonth, Date(1999, 8, 31));
+ assertPred!"=="(Date(1999, 9, 1).endOfMonth, Date(1999, 9, 30));
+ assertPred!"=="(Date(1999, 10, 1).endOfMonth, Date(1999, 10, 31));
+ assertPred!"=="(Date(1999, 11, 1).endOfMonth, Date(1999, 11, 30));
+ assertPred!"=="(Date(1999, 12, 1).endOfMonth, Date(1999, 12, 31));
+
+ //Test B.C.
+ assertPred!"=="(Date(-1999, 1, 1).endOfMonth, Date(-1999, 1, 31));
+ assertPred!"=="(Date(-1999, 2, 1).endOfMonth, Date(-1999, 2, 28));
+ assertPred!"=="(Date(-2000, 2, 1).endOfMonth, Date(-2000, 2, 29));
+ assertPred!"=="(Date(-1999, 3, 1).endOfMonth, Date(-1999, 3, 31));
+ assertPred!"=="(Date(-1999, 4, 1).endOfMonth, Date(-1999, 4, 30));
+ assertPred!"=="(Date(-1999, 5, 1).endOfMonth, Date(-1999, 5, 31));
+ assertPred!"=="(Date(-1999, 6, 1).endOfMonth, Date(-1999, 6, 30));
+ assertPred!"=="(Date(-1999, 7, 1).endOfMonth, Date(-1999, 7, 31));
+ assertPred!"=="(Date(-1999, 8, 1).endOfMonth, Date(-1999, 8, 31));
+ assertPred!"=="(Date(-1999, 9, 1).endOfMonth, Date(-1999, 9, 30));
+ assertPred!"=="(Date(-1999, 10, 1).endOfMonth, Date(-1999, 10, 31));
+ assertPred!"=="(Date(-1999, 11, 1).endOfMonth, Date(-1999, 11, 30));
+ assertPred!"=="(Date(-1999, 12, 1).endOfMonth, Date(-1999, 12, 31));
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(!__traits(compiles, cdate.endOfMonth = Date(1999, 7, 30)));
+ static assert(!__traits(compiles, idate.endOfMonth = Date(1999, 7, 30)));
+
+ //Verify Examples.
+ assert(Date(1999, 1, 6).endOfMonth == Date(1999, 1, 31));
+ assert(Date(1999, 2, 7).endOfMonth == Date(1999, 2, 28));
+ assert(Date(2000, 2, 7).endOfMonth == Date(2000, 2, 29));
+ assert(Date(2000, 6, 4).endOfMonth == Date(2000, 6, 30));
+ }
+
+
+ /++
+ The last day in the month that this Date is in.
+
+ Examples:
+--------------------
+assert(Date(1999, 1, 6).endOfMonthDay == 31);
+assert(Date(1999, 2, 7).endOfMonthDay == 28);
+assert(Date(2000, 2, 7).endOfMonthDay == 29);
+assert(Date(2000, 6, 4).endOfMonthDay == 30);
+--------------------
+ +/
+ @property ubyte endOfMonthDay() const pure nothrow
+ {
+ return maxDay(_year, _month);
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(Date(1999, 1, 1).endOfMonthDay, 31);
+ assertPred!"=="(Date(1999, 2, 1).endOfMonthDay, 28);
+ assertPred!"=="(Date(2000, 2, 1).endOfMonthDay, 29);
+ assertPred!"=="(Date(1999, 3, 1).endOfMonthDay, 31);
+ assertPred!"=="(Date(1999, 4, 1).endOfMonthDay, 30);
+ assertPred!"=="(Date(1999, 5, 1).endOfMonthDay, 31);
+ assertPred!"=="(Date(1999, 6, 1).endOfMonthDay, 30);
+ assertPred!"=="(Date(1999, 7, 1).endOfMonthDay, 31);
+ assertPred!"=="(Date(1999, 8, 1).endOfMonthDay, 31);
+ assertPred!"=="(Date(1999, 9, 1).endOfMonthDay, 30);
+ assertPred!"=="(Date(1999, 10, 1).endOfMonthDay, 31);
+ assertPred!"=="(Date(1999, 11, 1).endOfMonthDay, 30);
+ assertPred!"=="(Date(1999, 12, 1).endOfMonthDay, 31);
+
+ //Test B.C.
+ assertPred!"=="(Date(-1999, 1, 1).endOfMonthDay, 31);
+ assertPred!"=="(Date(-1999, 2, 1).endOfMonthDay, 28);
+ assertPred!"=="(Date(-2000, 2, 1).endOfMonthDay, 29);
+ assertPred!"=="(Date(-1999, 3, 1).endOfMonthDay, 31);
+ assertPred!"=="(Date(-1999, 4, 1).endOfMonthDay, 30);
+ assertPred!"=="(Date(-1999, 5, 1).endOfMonthDay, 31);
+ assertPred!"=="(Date(-1999, 6, 1).endOfMonthDay, 30);
+ assertPred!"=="(Date(-1999, 7, 1).endOfMonthDay, 31);
+ assertPred!"=="(Date(-1999, 8, 1).endOfMonthDay, 31);
+ assertPred!"=="(Date(-1999, 9, 1).endOfMonthDay, 30);
+ assertPred!"=="(Date(-1999, 10, 1).endOfMonthDay, 31);
+ assertPred!"=="(Date(-1999, 11, 1).endOfMonthDay, 30);
+ assertPred!"=="(Date(-1999, 12, 1).endOfMonthDay, 31);
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(!__traits(compiles, cdate.endOfMonthDay = 30));
+ static assert(!__traits(compiles, idate.endOfMonthDay = 30));
+
+ //Verify Examples.
+ assert(Date(1999, 1, 6).endOfMonthDay == 31);
+ assert(Date(1999, 2, 7).endOfMonthDay == 28);
+ assert(Date(2000, 2, 7).endOfMonthDay == 29);
+ assert(Date(2000, 6, 4).endOfMonthDay == 30);
+ }
+
+
+ /++
+ Whether the current year is a date in A.D.
+
+ Examples:
+--------------------
+assert(Date(1, 1, 1).isAD);
+assert(Date(2010, 12, 31).isAD);
+assert(!Date(0, 12, 31).isAD);
+assert(!Date(-2010, 1, 1).isAD);
+--------------------
+ +/
+ @property bool isAD() const pure nothrow
+ {
+ return _year > 0;
+ }
+
+ unittest
+ {
+ assert(Date(2010, 7, 4).isAD);
+ assert(Date(1, 1, 1).isAD);
+ assert(!Date(0, 1, 1).isAD);
+ assert(!Date(-1, 1, 1).isAD);
+ assert(!Date(-2010, 7, 4).isAD);
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, cdate.isAD));
+ static assert(__traits(compiles, idate.isAD));
+
+ //Verify Examples.
+ assert(Date(1, 1, 1).isAD);
+ assert(Date(2010, 12, 31).isAD);
+ assert(!Date(0, 12, 31).isAD);
+ assert(!Date(-2010, 1, 1).isAD);
+ }
+
+
+ /++
+ The julian day for this Date at noon (since the julian day changes at noon).
+ +/
+ @property long julianDay() const pure nothrow
+ {
+ return dayOfGregorianCal + 1_721_425;
+ }
+
+ unittest
+ {
+ assertPred!"=="(Date(-4713, 11, 24).julianDay, 0);
+ assertPred!"=="(Date(0, 12, 31).julianDay, 1_721_425);
+ assertPred!"=="(Date(1, 1, 1).julianDay, 1_721_426);
+ assertPred!"=="(Date(1582, 10, 15).julianDay, 2_299_161);
+ assertPred!"=="(Date(1858, 11, 17).julianDay, 2_400_001);
+ assertPred!"=="(Date(1982, 1, 4).julianDay, 2_444_974);
+ assertPred!"=="(Date(1996, 3, 31).julianDay, 2_450_174);
+ assertPred!"=="(Date(2010, 8, 24).julianDay, 2_455_433);
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, cdate.julianDay));
+ static assert(__traits(compiles, idate.julianDay));
+ }
+
+
+ /++
+ The modified julian day for any time on this Date (since, the modified
+ julian day changes at midnight).
+ +/
+ @property long modJulianDay() const pure nothrow
+ {
+ return julianDay - 2_400_001;
+ }
+
+ unittest
+ {
+ assertPred!"=="(Date(1858, 11, 17).modJulianDay, 0);
+ assertPred!"=="(Date(2010, 8, 24).modJulianDay, 55_432);
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, cdate.modJulianDay));
+ static assert(__traits(compiles, idate.modJulianDay));
+ }
+
+
+ /++
+ Converts this Date to a string with the format YYYYMMDD.
+
+ Examples:
+--------------------
+assert(Date(2010, 7, 4).toISOString() == "20100704");
+assert(Date(1998, 12, 25).toISOString() == "19981225");
+assert(Date(0, 1, 5).toISOString() == "00000105");
+assert(Date(-4, 1, 5).toISOString() == "-00040105");
+--------------------
+ +/
+ string toISOString() const nothrow
+ {
+ try
+ {
+ if(_year >= 0)
+ {
+ if(_year < 10_000)
+ return format("%04d%02d%02d", _year, _month, _day);
+ else
+ return format("+%05d%02d%02d", _year, _month, _day);
+ }
+ else if(_year > -10_000)
+ return format("%05d%02d%02d", _year, _month, _day);
+ else
+ return format("%06d%02d%02d", _year, _month, _day);
+ }
+ catch(Exception e)
+ assert(0, "format() threw.");
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(Date(9, 12, 4).toISOString(), "00091204");
+ assertPred!"=="(Date(99, 12, 4).toISOString(), "00991204");
+ assertPred!"=="(Date(999, 12, 4).toISOString(), "09991204");
+ assertPred!"=="(Date(9999, 7, 4).toISOString(), "99990704");
+ assertPred!"=="(Date(10000, 10, 20).toISOString(), "+100001020");
+
+ //Test B.C.
+ assertPred!"=="(Date(0, 12, 4).toISOString(), "00001204");
+ assertPred!"=="(Date(-9, 12, 4).toISOString(), "-00091204");
+ assertPred!"=="(Date(-99, 12, 4).toISOString(), "-00991204");
+ assertPred!"=="(Date(-999, 12, 4).toISOString(), "-09991204");
+ assertPred!"=="(Date(-9999, 7, 4).toISOString(), "-99990704");
+ assertPred!"=="(Date(-10000, 10, 20).toISOString(), "-100001020");
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, cdate.toISOString()));
+ static assert(__traits(compiles, idate.toISOString()));
+
+ //Verify Examples.
+ assert(Date(2010, 7, 4).toISOString() == "20100704");
+ assert(Date(1998, 12, 25).toISOString() == "19981225");
+ assert(Date(0, 1, 5).toISOString() == "00000105");
+ assert(Date(-4, 1, 5).toISOString() == "-00040105");
+ }
+
+ /++
+ Converts this Date to a string with the format YYYY-MM-DD.
+
+ Examples:
+--------------------
+assert(Date(2010, 7, 4).toISOExtendedString() == "2010-07-04");
+assert(Date(1998, 12, 25).toISOExtendedString() == "1998-12-25");
+assert(Date(0, 1, 5).toISOExtendedString() == "0000-01-05");
+assert(Date(-4, 1, 5).toISOExtendedString() == "-0004-01-05");
+--------------------
+ +/
+ string toISOExtendedString() const nothrow
+ {
+ try
+ {
+ if(_year >= 0)
+ {
+ if(_year < 10_000)
+ return format("%04d-%02d-%02d", _year, _month, _day);
+ else
+ return format("+%05d-%02d-%02d", _year, _month, _day);
+ }
+ else if(_year > -10_000)
+ return format("%05d-%02d-%02d", _year, _month, _day);
+ else
+ return format("%06d-%02d-%02d", _year, _month, _day);
+ }
+ catch(Exception e)
+ assert(0, "format() threw.");
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(Date(9, 12, 4).toISOExtendedString(), "0009-12-04");
+ assertPred!"=="(Date(99, 12, 4).toISOExtendedString(), "0099-12-04");
+ assertPred!"=="(Date(999, 12, 4).toISOExtendedString(), "0999-12-04");
+ assertPred!"=="(Date(9999, 7, 4).toISOExtendedString(), "9999-07-04");
+ assertPred!"=="(Date(10000, 10, 20).toISOExtendedString(), "+10000-10-20");
+
+ //Test B.C.
+ assertPred!"=="(Date(0, 12, 4).toISOExtendedString(), "0000-12-04");
+ assertPred!"=="(Date(-9, 12, 4).toISOExtendedString(), "-0009-12-04");
+ assertPred!"=="(Date(-99, 12, 4).toISOExtendedString(), "-0099-12-04");
+ assertPred!"=="(Date(-999, 12, 4).toISOExtendedString(), "-0999-12-04");
+ assertPred!"=="(Date(-9999, 7, 4).toISOExtendedString(), "-9999-07-04");
+ assertPred!"=="(Date(-10000, 10, 20).toISOExtendedString(), "-10000-10-20");
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, cdate.toISOExtendedString()));
+ static assert(__traits(compiles, idate.toISOExtendedString()));
+
+ //Verify Examples.
+ assert(Date(2010, 7, 4).toISOExtendedString() == "2010-07-04");
+ assert(Date(1998, 12, 25).toISOExtendedString() == "1998-12-25");
+ assert(Date(0, 1, 5).toISOExtendedString() == "0000-01-05");
+ assert(Date(-4, 1, 5).toISOExtendedString() == "-0004-01-05");
+ }
+
+ /++
+ Converts this Date to a string with the format YYYY-Mon-DD.
+
+ Examples:
+--------------------
+assert(Date(2010, 7, 4).toSimpleString() == "2010-Jul-04");
+assert(Date(1998, 12, 25).toSimpleString() == "1998-Dec-25");
+assert(Date(0, 1, 5).toSimpleString() == "0000-Jan-05");
+assert(Date(-4, 1, 5).toSimpleString() == "-0004-Jan-05");
+--------------------
+ +/
+ string toSimpleString() const nothrow
+ {
+ try
+ {
+ if(_year >= 0)
+ {
+ if(_year < 10_000)
+ return format("%04d-%s-%02d", _year, monthToString(_month, false), _day);
+ else
+ return format("+%05d-%s-%02d", _year, monthToString(_month, false), _day);
+ }
+ else if(_year > -10_000)
+ return format("%05d-%s-%02d", _year, monthToString(_month, false), _day);
+ else
+ return format("%06d-%s-%02d", _year, monthToString(_month, false), _day);
+ }
+ catch(Exception e)
+ assert(0, "format() threw.");
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(Date(9, 12, 4).toSimpleString(), "0009-Dec-04");
+ assertPred!"=="(Date(99, 12, 4).toSimpleString(), "0099-Dec-04");
+ assertPred!"=="(Date(999, 12, 4).toSimpleString(), "0999-Dec-04");
+ assertPred!"=="(Date(9999, 7, 4).toSimpleString(), "9999-Jul-04");
+ assertPred!"=="(Date(10000, 10, 20).toSimpleString(), "+10000-Oct-20");
+
+ //Test B.C.
+ assertPred!"=="(Date(0, 12, 4).toSimpleString(), "0000-Dec-04");
+ assertPred!"=="(Date(-9, 12, 4).toSimpleString(), "-0009-Dec-04");
+ assertPred!"=="(Date(-99, 12, 4).toSimpleString(), "-0099-Dec-04");
+ assertPred!"=="(Date(-999, 12, 4).toSimpleString(), "-0999-Dec-04");
+ assertPred!"=="(Date(-9999, 7, 4).toSimpleString(), "-9999-Jul-04");
+ assertPred!"=="(Date(-10000, 10, 20).toSimpleString(), "-10000-Oct-20");
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, cdate.toSimpleString()));
+ static assert(__traits(compiles, idate.toSimpleString()));
+
+ //Verify Examples.
+ assert(Date(2010, 7, 4).toSimpleString() == "2010-Jul-04");
+ assert(Date(1998, 12, 25).toSimpleString() == "1998-Dec-25");
+ assert(Date(0, 1, 5).toSimpleString() == "0000-Jan-05");
+ assert(Date(-4, 1, 5).toSimpleString() == "-0004-Jan-05");
+ }
+
+ //TODO Add a function which returns a string in a user-specified format.
+
+
+ /+
+ Converts this Date to a string.
+ +/
+ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't
+ //have versions of toString() with extra modifiers, so we define one version
+ //with modifiers and one without.
+ string toString()
+ {
+ return toSimpleString();
+ }
+
+ /++
+ Converts this Date to a string.
+ +/
+ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't
+ //have versions of toString() with extra modifiers, so we define one version
+ //with modifiers and one without.
+ string toString() const nothrow
+ {
+ return toSimpleString();
+ }
+
+ unittest
+ {
+ auto date = Date(1999, 7, 6);
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(__traits(compiles, date.toString()));
+ static assert(__traits(compiles, cdate.toString()));
+ static assert(__traits(compiles, idate.toString()));
+ }
+
+
+ /++
+ Creates a Date from a string with the format YYYYMMDD. Whitespace is
+ stripped from the given string.
+
+ Params:
+ isoString = A string formatted in the ISO format for dates.
+
+ Throws:
+ DateTimeException if the given string is not in the ISO format or if
+ the resulting Date would not be valid.
+
+ Examples:
+--------------------
+assert(Date.fromISOString("20100704") == Date(2010, 7, 4));
+assert(Date.fromISOString("19981225") == Date(1998, 12, 25));
+assert(Date.fromISOString("00000105") == Date(0, 1, 5));
+assert(Date.fromISOString("-00040105") == Date(-4, 1, 5));
+assert(Date.fromISOString(" 20100704 ") == Date(2010, 7, 4));
+--------------------
+ +/
+ static Date fromISOString(S)(in S isoString)
+ if(isSomeString!S)
+ {
+ auto dstr = to!dstring(strip(isoString));
+
+ enforce(dstr.length >= 8, new DateTimeException(format("Invalid ISO String: %s", isoString)));
+
+ auto day = dstr[$-2 .. $];
+ auto month = dstr[$-4 .. $-2];
+ auto year = dstr[0 .. $-4];
+
+ enforce(!canFind!((dchar c){return !isdigit(c);})(day), new DateTimeException(format("Invalid ISO String: %s", isoString)));
+ enforce(!canFind!((dchar c){return !isdigit(c);})(month), new DateTimeException(format("Invalid ISO String: %s", isoString)));
+
+ if(year.length > 4)
+ {
+ enforce(year.startsWith("-") || year.startsWith("+"), new DateTimeException(format("Invalid ISO String: %s", isoString)));
+ enforce(!canFind!((dchar c){return !isdigit(c);})(year[1..$]), new DateTimeException(format("Invalid ISO String: %s", isoString)));
+ }
+ else
+ enforce(!canFind!((dchar c){return !isdigit(c);})(year), new DateTimeException(format("Invalid ISO String: %s", isoString)));
+
+ return Date(to!short(year), to!ubyte(month), to!ubyte(day));
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException(Date.fromISOString(""));
+ assertThrown!DateTimeException(Date.fromISOString("990704"));
+ assertThrown!DateTimeException(Date.fromISOString("0100704"));
+ assertThrown!DateTimeException(Date.fromISOString("2010070"));
+ assertThrown!DateTimeException(Date.fromISOString("2010070 "));
+ assertThrown!DateTimeException(Date.fromISOString("120100704"));
+ assertThrown!DateTimeException(Date.fromISOString("-0100704"));
+ assertThrown!DateTimeException(Date.fromISOString("+0100704"));
+ assertThrown!DateTimeException(Date.fromISOString("2010070a"));
+ assertThrown!DateTimeException(Date.fromISOString("20100a04"));
+ assertThrown!DateTimeException(Date.fromISOString("2010a704"));
+
+ assertThrown!DateTimeException(Date.fromISOString("99-07-04"));
+ assertThrown!DateTimeException(Date.fromISOString("010-07-04"));
+ assertThrown!DateTimeException(Date.fromISOString("2010-07-0"));
+ assertThrown!DateTimeException(Date.fromISOString("2010-07-0 "));
+ assertThrown!DateTimeException(Date.fromISOString("12010-07-04"));
+ assertThrown!DateTimeException(Date.fromISOString("-010-07-04"));
+ assertThrown!DateTimeException(Date.fromISOString("+010-07-04"));
+ assertThrown!DateTimeException(Date.fromISOString("2010-07-0a"));
+ assertThrown!DateTimeException(Date.fromISOString("2010-0a-04"));
+ assertThrown!DateTimeException(Date.fromISOString("2010-a7-04"));
+ assertThrown!DateTimeException(Date.fromISOString("2010/07/04"));
+ assertThrown!DateTimeException(Date.fromISOString("2010/7/04"));
+ assertThrown!DateTimeException(Date.fromISOString("2010/7/4"));
+ assertThrown!DateTimeException(Date.fromISOString("2010/07/4"));
+ assertThrown!DateTimeException(Date.fromISOString("2010-7-04"));
+ assertThrown!DateTimeException(Date.fromISOString("2010-7-4"));
+ assertThrown!DateTimeException(Date.fromISOString("2010-07-4"));
+
+ assertThrown!DateTimeException(Date.fromISOString("99Jul04"));
+ assertThrown!DateTimeException(Date.fromISOString("010Jul04"));
+ assertThrown!DateTimeException(Date.fromISOString("2010Jul0"));
+ assertThrown!DateTimeException(Date.fromISOString("2010Jul0 "));
+ assertThrown!DateTimeException(Date.fromISOString("12010Jul04"));
+ assertThrown!DateTimeException(Date.fromISOString("-010Jul04"));
+ assertThrown!DateTimeException(Date.fromISOString("+010Jul04"));
+ assertThrown!DateTimeException(Date.fromISOString("2010Jul0a"));
+ assertThrown!DateTimeException(Date.fromISOString("2010Jua04"));
+ assertThrown!DateTimeException(Date.fromISOString("2010aul04"));
+
+ assertThrown!DateTimeException(Date.fromISOString("99-Jul-04"));
+ assertThrown!DateTimeException(Date.fromISOString("010-Jul-04"));
+ assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0"));
+ assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0 "));
+ assertThrown!DateTimeException(Date.fromISOString("12010-Jul-04"));
+ assertThrown!DateTimeException(Date.fromISOString("-010-Jul-04"));
+ assertThrown!DateTimeException(Date.fromISOString("+010-Jul-04"));
+ assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0a"));
+ assertThrown!DateTimeException(Date.fromISOString("2010-Jua-04"));
+ assertThrown!DateTimeException(Date.fromISOString("2010-Jal-04"));
+ assertThrown!DateTimeException(Date.fromISOString("2010-aul-04"));
+
+ assertThrown!DateTimeException(Date.fromISOString("2010-07-04"));
+ assertThrown!DateTimeException(Date.fromISOString("2010-Jul-04"));
+
+ assertPred!"=="(Date.fromISOString("19990706"), Date(1999, 7, 6));
+ assertPred!"=="(Date.fromISOString("-19990706"), Date(-1999, 7, 6));
+ assertPred!"=="(Date.fromISOString("+019990706"), Date(1999, 7, 6));
+ assertPred!"=="(Date.fromISOString("19990706 "), Date(1999, 7, 6));
+ assertPred!"=="(Date.fromISOString(" 19990706"), Date(1999, 7, 6));
+ assertPred!"=="(Date.fromISOString(" 19990706 "), Date(1999, 7, 6));
+
+ //Verify Examples.
+ assert(Date.fromISOString("20100704") == Date(2010, 7, 4));
+ assert(Date.fromISOString("19981225") == Date(1998, 12, 25));
+ assert(Date.fromISOString("00000105") == Date(0, 1, 5));
+ assert(Date.fromISOString("-00040105") == Date(-4, 1, 5));
+ assert(Date.fromISOString(" 20100704 ") == Date(2010, 7, 4));
+ }
+
+
+ /++
+ Creates a Date from a string with the format YYYY-MM-DD. Whitespace is
+ stripped from the given string.
+
+ Params:
+ isoExtString = A string formatted in the ISO Extended format for
+ dates.
+
+ Throws:
+ DateTimeException if the given string is not in the ISO Extended
+ format or if the resulting Date would not be valid.
+
+ Examples:
+--------------------
+assert(Date.fromISOExtendedString("2010-07-04") == Date(2010, 7, 4));
+assert(Date.fromISOExtendedString("1998-12-25") == Date(1998, 12, 25));
+assert(Date.fromISOExtendedString("0000-01-05") == Date(0, 1, 5));
+assert(Date.fromISOExtendedString("-0004-01-05") == Date(-4, 1, 5));
+assert(Date.fromISOExtendedString(" 2010-07-04 ") == Date(2010, 7, 4));
+--------------------
+ +/
+ static Date fromISOExtendedString(S)(in S isoExtString)
+ if(isSomeString!(S))
+ {
+ auto dstr = to!dstring(strip(isoExtString));
+
+ enforce(dstr.length >= 10, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
+
+ auto day = dstr[$-2 .. $];
+ auto month = dstr[$-5 .. $-3];
+ auto year = dstr[0 .. $-6];
+
+ enforce(dstr[$-3] == '-', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
+ enforce(dstr[$-6] == '-', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
+ enforce(!canFind!((dchar c){return !isdigit(c);})(day), new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
+ enforce(!canFind!((dchar c){return !isdigit(c);})(month), new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
+
+ if(year.length > 4)
+ {
+ enforce(year.startsWith("-") || year.startsWith("+"), new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
+ enforce(!canFind!((dchar c){return !isdigit(c);})(year[1..$]), new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
+ }
+ else
+ enforce(!canFind!((dchar c){return !isdigit(c);})(year), new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
+
+ return Date(to!short(year), to!ubyte(month), to!ubyte(day));
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException(Date.fromISOExtendedString(""));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("990704"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("0100704"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010070"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010070 "));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("120100704"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("-0100704"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("+0100704"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010070a"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("20100a04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010a704"));
+
+ assertThrown!DateTimeException(Date.fromISOExtendedString("99-07-04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("010-07-04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010-07-0"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010-07-0 "));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("12010-07-04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("-010-07-04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("+010-07-04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010-07-0a"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010-0a-04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010-a7-04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010/07/04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010/7/04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010/7/4"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010/07/4"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010-7-04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010-7-4"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010-07-4"));
+
+ assertThrown!DateTimeException(Date.fromISOExtendedString("99Jul04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("010Jul04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010Jul0"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010-Jul-0 "));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("12010Jul04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("-010Jul04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("+010Jul04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010Jul0a"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010Jua04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010aul04"));
+
+ assertThrown!DateTimeException(Date.fromISOExtendedString("99-Jul-04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("010-Jul-04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010-Jul-0"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010Jul0 "));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("12010-Jul-04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("-010-Jul-04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("+010-Jul-04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010-Jul-0a"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010-Jua-04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010-Jal-04"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010-aul-04"));
+
+ assertThrown!DateTimeException(Date.fromISOExtendedString("20100704"));
+ assertThrown!DateTimeException(Date.fromISOExtendedString("2010-Jul-04"));
+
+ assertPred!"=="(Date.fromISOExtendedString("1999-07-06"), Date(1999, 7, 6));
+ assertPred!"=="(Date.fromISOExtendedString("-1999-07-06"), Date(-1999, 7, 6));
+ assertPred!"=="(Date.fromISOExtendedString("+01999-07-06"), Date(1999, 7, 6));
+ assertPred!"=="(Date.fromISOExtendedString("1999-07-06 "), Date(1999, 7, 6));
+ assertPred!"=="(Date.fromISOExtendedString(" 1999-07-06"), Date(1999, 7, 6));
+ assertPred!"=="(Date.fromISOExtendedString(" 1999-07-06 "), Date(1999, 7, 6));
+
+ //Verify Examples.
+ assert(Date.fromISOExtendedString("2010-07-04") == Date(2010, 7, 4));
+ assert(Date.fromISOExtendedString("1998-12-25") == Date(1998, 12, 25));
+ assert(Date.fromISOExtendedString("0000-01-05") == Date(0, 1, 5));
+ assert(Date.fromISOExtendedString("-0004-01-05") == Date(-4, 1, 5));
+ assert(Date.fromISOExtendedString(" 2010-07-04 ") == Date(2010, 7, 4));
+ }
+
+
+ /++
+ Creates a Date from a string with the format YYYY-Mon-DD. Whitespace is
+ stripped from the given string.
+
+ Params:
+ simpleString = A string formatted in the way that toSimpleString()
+ formats dates.
+
+ Throws:
+ DateTimeException if the given string is not in the correct format or
+ if the resulting Date would not be valid.
+
+ Examples:
+--------------------
+assert(Date.fromSimpleString("2010-Jul-04") == Date(2010, 7, 4));
+assert(Date.fromSimpleString("1998-Dec-25") == Date(1998, 12, 25));
+assert(Date.fromSimpleString("0000-Jan-05") == Date(0, 1, 5));
+assert(Date.fromSimpleString("-0004-Jan-05") == Date(-4, 1, 5));
+assert(Date.fromSimpleString(" 2010-Jul-04 ") == Date(2010, 7, 4));
+--------------------
+ +/
+ static Date fromSimpleString(S)(in S simpleString)
+ if(isSomeString!(S))
+ {
+ auto dstr = to!dstring(strip(simpleString));
+
+ enforce(dstr.length >= 11, new DateTimeException(format("Invalid string format: %s", simpleString)));
+
+ auto day = dstr[$-2 .. $];
+ auto month = monthFromString(to!string(dstr[$-6 .. $-3]));
+ auto year = dstr[0 .. $-7];
+
+ enforce(dstr[$-3] == '-', new DateTimeException(format("Invalid string format: %s", simpleString)));
+ enforce(dstr[$-7] == '-', new DateTimeException(format("Invalid string format: %s", simpleString)));
+ enforce(!canFind!((dchar c){return !isdigit(c);})(day), new DateTimeException(format("Invalid string format: %s", simpleString)));
+
+ if(year.length > 4)
+ {
+ enforce(year.startsWith("-") || year.startsWith("+"), new DateTimeException(format("Invalid string format: %s", simpleString)));
+ enforce(!canFind!((dchar c){return !isdigit(c);})(year[1..$]), new DateTimeException(format("Invalid string format: %s", simpleString)));
+ }
+ else
+ enforce(!canFind!((dchar c){return !isdigit(c);})(year), new DateTimeException(format("Invalid string format: %s", simpleString)));
+
+ return Date(to!short(year), month, to!ubyte(day));
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException(Date.fromSimpleString(""));
+ assertThrown!DateTimeException(Date.fromSimpleString("990704"));
+ assertThrown!DateTimeException(Date.fromSimpleString("0100704"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010070"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010070 "));
+ assertThrown!DateTimeException(Date.fromSimpleString("120100704"));
+ assertThrown!DateTimeException(Date.fromSimpleString("-0100704"));
+ assertThrown!DateTimeException(Date.fromSimpleString("+0100704"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010070a"));
+ assertThrown!DateTimeException(Date.fromSimpleString("20100a04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010a704"));
+
+ assertThrown!DateTimeException(Date.fromSimpleString("99-07-04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("010-07-04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0 "));
+ assertThrown!DateTimeException(Date.fromSimpleString("12010-07-04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("-010-07-04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("+010-07-04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0a"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010-0a-04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010-a7-04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010/07/04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010/7/04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010/7/4"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010/07/4"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010-7-04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010-7-4"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010-07-4"));
+
+ assertThrown!DateTimeException(Date.fromSimpleString("99Jul04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("010Jul04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0 "));
+ assertThrown!DateTimeException(Date.fromSimpleString("12010Jul04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("-010Jul04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("+010Jul04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0a"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010Jua04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010aul04"));
+
+ assertThrown!DateTimeException(Date.fromSimpleString("99-Jul-04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("010-Jul-04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0 "));
+ assertThrown!DateTimeException(Date.fromSimpleString("12010-Jul-04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("-010-Jul-04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("+010-Jul-04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0a"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010-Jua-04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010-Jal-04"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010-aul-04"));
+
+ assertThrown!DateTimeException(Date.fromSimpleString("20100704"));
+ assertThrown!DateTimeException(Date.fromSimpleString("2010-07-04"));
+
+ assertPred!"=="(Date.fromSimpleString("1999-Jul-06"), Date(1999, 7, 6));
+ assertPred!"=="(Date.fromSimpleString("-1999-Jul-06"), Date(-1999, 7, 6));
+ assertPred!"=="(Date.fromSimpleString("+01999-Jul-06"), Date(1999, 7, 6));
+ assertPred!"=="(Date.fromSimpleString("1999-Jul-06 "), Date(1999, 7, 6));
+ assertPred!"=="(Date.fromSimpleString(" 1999-Jul-06"), Date(1999, 7, 6));
+ assertPred!"=="(Date.fromSimpleString(" 1999-Jul-06 "), Date(1999, 7, 6));
+
+ //Verify Examples.
+ assert(Date.fromSimpleString("2010-Jul-04") == Date(2010, 7, 4));
+ assert(Date.fromSimpleString("1998-Dec-25") == Date(1998, 12, 25));
+ assert(Date.fromSimpleString("0000-Jan-05") == Date(0, 1, 5));
+ assert(Date.fromSimpleString("-0004-Jan-05") == Date(-4, 1, 5));
+ assert(Date.fromSimpleString(" 2010-Jul-04 ") == Date(2010, 7, 4));
+ }
+
+
+ //TODO Add function which takes a user-specified time format and produces a Date
+
+ //TODO Add function which takes pretty much any time-string and produces a Date
+ // Obviously, it will be less efficient, and it probably won't manage _every_
+ // possible date format, but a smart conversion function would be nice.
+
+
+ /++
+ Returns the Date farthest in the past which is representable by Date.
+ +/
+ @property static Date min() pure nothrow
+ {
+ auto date = Date.init;
+ date._year = short.min;
+ date._month = Month.jan;
+ date._day = 1;
+
+ return date;
+ }
+
+ unittest
+ {
+ assert(Date.min.year < 0);
+ assert(Date.min < Date.max);
+ }
+
+
+ /++
+ Returns the Date farthest in the future which is representable by Date.
+ +/
+ @property static Date max() pure nothrow
+ {
+ auto date = Date.init;
+ date._year = short.max;
+ date._month = Month.dec;
+ date._day = 31;
+
+ return date;
+ }
+
+ unittest
+ {
+ assert(Date.max.year > 0);
+ assert(Date.max > Date.min);
+ }
+
+
+private:
+
+ /++
+ Whether the given values form a valid date.
+
+ Params:
+ year = The year to test.
+ month = The month of the Gregorian Calendar to test.
+ day = The day of the month to test.
+ +/
+ static bool _valid(int year, int month, int day) pure nothrow
+ {
+ if(!valid!"months"(month))
+ return false;
+
+ return valid!"days"(year, month, day);
+ }
+
+ /++
+ Adds the given number of days to this Date. A negative number will subtract.
+
+ The month will be adjusted along with the day if the number of days added
+ (or subtracted) would overflow (or underflow) the current month. The year
+ will be adjusted along with the month if the increase (or decrease) to the
+ month would cause it to overflow (or underflow) the current year.
+
+ addDays(numDays) is effectively equivalent to date.dayOfGregorianCal = date.dayOfGregorianCal + days.
+
+ Params:
+ days = The number of days to add to this Date.
+ +/
+ ref Date addDays(long days) pure nothrow
+ {
+ dayOfGregorianCal = cast(int)(dayOfGregorianCal + days);
+
+ return this;
+ }
+
+ unittest
+ {
+ //Test A.D.
+ {
+ auto date = Date(1999, 2, 28);
+ date.addDays(1);
+ assertPred!"=="(date, Date(1999, 3, 1));
+ date.addDays(-1);
+ assertPred!"=="(date, Date(1999, 2, 28));
+ }
+
+ {
+ auto date = Date(2000, 2, 28);
+ date.addDays(1);
+ assertPred!"=="(date, Date(2000, 2, 29));
+ date.addDays(1);
+ assertPred!"=="(date, Date(2000, 3, 1));
+ date.addDays(-1);
+ assertPred!"=="(date, Date(2000, 2, 29));
+ }
+
+ {
+ auto date = Date(1999, 6, 30);
+ date.addDays(1);
+ assertPred!"=="(date, Date(1999, 7, 1));
+ date.addDays(-1);
+ assertPred!"=="(date, Date(1999, 6, 30));
+ }
+
+ {
+ auto date = Date(1999, 7, 31);
+ date.addDays(1);
+ assertPred!"=="(date, Date(1999, 8, 1));
+ date.addDays(-1);
+ assertPred!"=="(date, Date(1999, 7, 31));
+ }
+
+ {
+ auto date = Date(1999, 1, 1);
+ date.addDays(-1);
+ assertPred!"=="(date, Date(1998, 12, 31));
+ date.addDays(1);
+ assertPred!"=="(date, Date(1999, 1, 1));
+ }
+
+ {
+ auto date = Date(1999, 7, 6);
+ date.addDays(9);
+ assertPred!"=="(date, Date(1999, 7, 15));
+ date.addDays(-11);
+ assertPred!"=="(date, Date(1999, 7, 4));
+ date.addDays(30);
+ assertPred!"=="(date, Date(1999, 8, 3));
+ date.addDays(-3);
+ assertPred!"=="(date, Date(1999, 7, 31));
+ }
+
+ {
+ auto date = Date(1999, 7, 6);
+ date.addDays(365);
+ assertPred!"=="(date, Date(2000, 7, 5));
+ date.addDays(-365);
+ assertPred!"=="(date, Date(1999, 7, 6));
+ date.addDays(366);
+ assertPred!"=="(date, Date(2000, 7, 6));
+ date.addDays(730);
+ assertPred!"=="(date, Date(2002, 7, 6));
+ date.addDays(-1096);
+ assertPred!"=="(date, Date(1999, 7, 6));
+ }
+
+ //Test B.C.
+ {
+ auto date = Date(-1999, 2, 28);
+ date.addDays(1);
+ assertPred!"=="(date, Date(-1999, 3, 1));
+ date.addDays(-1);
+ assertPred!"=="(date, Date(-1999, 2, 28));
+ }
+
+ {
+ auto date = Date(-2000, 2, 28);
+ date.addDays(1);
+ assertPred!"=="(date, Date(-2000, 2, 29));
+ date.addDays(1);
+ assertPred!"=="(date, Date(-2000, 3, 1));
+ date.addDays(-1);
+ assertPred!"=="(date, Date(-2000, 2, 29));
+ }
+
+ {
+ auto date = Date(-1999, 6, 30);
+ date.addDays(1);
+ assertPred!"=="(date, Date(-1999, 7, 1));
+ date.addDays(-1);
+ assertPred!"=="(date, Date(-1999, 6, 30));
+ }
+
+ {
+ auto date = Date(-1999, 7, 31);
+ date.addDays(1);
+ assertPred!"=="(date, Date(-1999, 8, 1));
+ date.addDays(-1);
+ assertPred!"=="(date, Date(-1999, 7, 31));
+ }
+
+ {
+ auto date = Date(-1999, 1, 1);
+ date.addDays(-1);
+ assertPred!"=="(date, Date(-2000, 12, 31));
+ date.addDays(1);
+ assertPred!"=="(date, Date(-1999, 1, 1));
+ }
+
+ {
+ auto date = Date(-1999, 7, 6);
+ date.addDays(9);
+ assertPred!"=="(date, Date(-1999, 7, 15));
+ date.addDays(-11);
+ assertPred!"=="(date, Date(-1999, 7, 4));
+ date.addDays(30);
+ assertPred!"=="(date, Date(-1999, 8, 3));
+ date.addDays(-3);
+ }
+
+ {
+ auto date = Date(-1999, 7, 6);
+ date.addDays(365);
+ assertPred!"=="(date, Date(-1998, 7, 6));
+ date.addDays(-365);
+ assertPred!"=="(date, Date(-1999, 7, 6));
+ date.addDays(366);
+ assertPred!"=="(date, Date(-1998, 7, 7));
+ date.addDays(730);
+ assertPred!"=="(date, Date(-1996, 7, 6));
+ date.addDays(-1096);
+ assertPred!"=="(date, Date(-1999, 7, 6));
+ }
+
+ //Test Both
+ {
+ auto date = Date(1, 7, 6);
+ date.addDays(-365);
+ assertPred!"=="(date, Date(0, 7, 6));
+ date.addDays(365);
+ assertPred!"=="(date, Date(1, 7, 6));
+ date.addDays(-731);
+ assertPred!"=="(date, Date(-1, 7, 6));
+ date.addDays(730);
+ assertPred!"=="(date, Date(1, 7, 5));
+ }
+
+ const cdate = Date(1999, 7, 6);
+ immutable idate = Date(1999, 7, 6);
+ static assert(!__traits(compiles, cdate.addDays(12)));
+ static assert(!__traits(compiles, idate.addDays(12)));
+ }
+
+
+ pure invariant()
+ {
+ assert(valid!"months"(_month), "Invariant Failure: year [" ~
+ numToString(_year) ~
+ "] month [" ~
+ numToString(_month) ~
+ "] day [" ~
+ numToString(_day) ~
+ "]");
+ assert(valid!"days"(_year, _month, _day), "Invariant Failure: year [" ~
+ numToString(_year) ~
+ "] month [" ~
+ numToString(_month) ~
+ "] day [" ~
+ numToString(_day) ~
+ "]");
+ }
+
+
+ short _year = 1;
+ Month _month = Month.jan;
+ ubyte _day = 1;
+}
+
+
+
+/++
+ Represents a time of day with hours, minutes, and seconds. It uses 24 hour time.
++/
+struct TimeOfDay
+{
+public:
+
+ /++
+ Params:
+ hour = Hour of the day [0 - 24$(RPAREN).
+ minute = Minute of the hour [0 - 60$(RPAREN).
+ second = Second of the minute [0 - 60$(RPAREN).
+
+ Throws:
+ DateTimeException if the resulting TimeOfDay would be not be valid.
+ +/
+ this(int hour, int minute, int second = 0) pure
+ {
+ enforceValid!"hours"(hour);
+ enforceValid!"minutes"(minute);
+ enforceValid!"seconds"(second);
+
+ _hour = cast(ubyte)hour;
+ _minute = cast(ubyte)minute;
+ _second = cast(ubyte)second;
+ }
+
+ unittest
+ {
+ assert(TimeOfDay(0, 0) == TimeOfDay.init);
+
+ {
+ auto tod = TimeOfDay(0, 0);
+ assertPred!"=="(tod._hour, 0);
+ assertPred!"=="(tod._minute, 0);
+ assertPred!"=="(tod._second, 0);
+ }
+
+ {
+ auto tod = TimeOfDay(12, 30, 33);
+ assertPred!"=="(tod._hour, 12);
+ assertPred!"=="(tod._minute, 30);
+ assertPred!"=="(tod._second, 33);
+ }
+
+ {
+ auto tod = TimeOfDay(23, 59, 59);
+ assertPred!"=="(tod._hour, 23);
+ assertPred!"=="(tod._minute, 59);
+ assertPred!"=="(tod._second, 59);
+ }
+
+ assertThrown!DateTimeException(TimeOfDay(24, 0, 0));
+ assertThrown!DateTimeException(TimeOfDay(0, 60, 0));
+ assertThrown!DateTimeException(TimeOfDay(0, 0, 60));
+ }
+
+
+ /++
+ Compares this TimeOfDay with the given TimeOfDay.
+
+ Returns:
+ $(TABLE
+ $(TR $(TD this < rhs) $(TD < 0))
+ $(TR $(TD this == rhs) $(TD 0))
+ $(TR $(TD this > rhs) $(TD > 0))
+ )
+ +/
+ int opCmp(in TimeOfDay rhs) const pure nothrow
+ {
+ if(_hour < rhs._hour)
+ return -1;
+ if(_hour > rhs._hour)
+ return 1;
+
+ if(_minute < rhs._minute)
+ return -1;
+ if(_minute > rhs._minute)
+ return 1;
+
+ if(_second < rhs._second)
+ return -1;
+ if(_second > rhs._second)
+ return 1;
+
+ return 0;
+ }
+
+ unittest
+ {
+ assertPred!("opCmp", "==")(TimeOfDay(0, 0, 0), TimeOfDay.init);
+
+ assertPred!("opCmp", "==")(TimeOfDay(0, 0, 0), TimeOfDay(0, 0, 0));
+ assertPred!("opCmp", "==")(TimeOfDay(12, 0, 0), TimeOfDay(12, 0, 0));
+ assertPred!("opCmp", "==")(TimeOfDay(0, 30, 0), TimeOfDay(0, 30, 0));
+ assertPred!("opCmp", "==")(TimeOfDay(0, 0, 33), TimeOfDay(0, 0, 33));
+
+ assertPred!("opCmp", "==")(TimeOfDay(12, 30, 0), TimeOfDay(12, 30, 0));
+ assertPred!("opCmp", "==")(TimeOfDay(12, 30, 33), TimeOfDay(12, 30, 33));
+
+ assertPred!("opCmp", "==")(TimeOfDay(0, 30, 33), TimeOfDay(0, 30, 33));
+ assertPred!("opCmp", "==")(TimeOfDay(0, 0, 33), TimeOfDay(0, 0, 33));
+
+ assertPred!("opCmp", "<")(TimeOfDay(12, 30, 33), TimeOfDay(13, 30, 33));
+ assertPred!("opCmp", ">")(TimeOfDay(13, 30, 33), TimeOfDay(12, 30, 33));
+ assertPred!("opCmp", "<")(TimeOfDay(12, 30, 33), TimeOfDay(12, 31, 33));
+ assertPred!("opCmp", ">")(TimeOfDay(12, 31, 33), TimeOfDay(12, 30, 33));
+ assertPred!("opCmp", "<")(TimeOfDay(12, 30, 33), TimeOfDay(12, 30, 34));
+ assertPred!("opCmp", ">")(TimeOfDay(12, 30, 34), TimeOfDay(12, 30, 33));
+
+ assertPred!("opCmp", ">")(TimeOfDay(13, 30, 33), TimeOfDay(12, 30, 34));
+ assertPred!("opCmp", "<")(TimeOfDay(12, 30, 34), TimeOfDay(13, 30, 33));
+ assertPred!("opCmp", ">")(TimeOfDay(13, 30, 33), TimeOfDay(12, 31, 33));
+ assertPred!("opCmp", "<")(TimeOfDay(12, 31, 33), TimeOfDay(13, 30, 33));
+
+ assertPred!("opCmp", ">")(TimeOfDay(12, 31, 33), TimeOfDay(12, 30, 34));
+ assertPred!("opCmp", "<")(TimeOfDay(12, 30, 34), TimeOfDay(12, 31, 33));
+
+ const ctod = TimeOfDay(12, 30, 33);
+ immutable itod = TimeOfDay(12, 30, 33);
+ static assert(__traits(compiles, ctod.opCmp(itod)));
+ static assert(__traits(compiles, itod.opCmp(ctod)));
+ }
+
+
+ /++
+ Hours passed midnight.
+ +/
+ @property ubyte hour() const pure nothrow
+ {
+ return _hour;
+ }
+
+ unittest
+ {
+ assertPred!"=="(TimeOfDay.init.hour, 0);
+ assertPred!"=="(TimeOfDay(12, 0, 0).hour, 12);
+
+ const ctod = TimeOfDay(12, 0, 0);
+ immutable itod = TimeOfDay(12, 0, 0);
+ static assert(__traits(compiles, ctod.hour == 12));
+ static assert(__traits(compiles, itod.hour == 12));
+ }
+
+
+ /++
+ Hours passed midnight.
+
+ Params:
+ hour = The hour of the day to set this TimeOfDay's hour to.
+
+ Throws:
+ DateTimeException if the given hour would result in an invalid TimeOfDay.
+ +/
+ @property void hour(int hour) pure
+ {
+ enforceValid!"hours"(hour);
+ _hour = cast(ubyte)hour;
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).hour = 24;}());
+
+ auto tod = TimeOfDay(0, 0, 0);
+ tod.hour = 12;
+ assertPred!"=="(tod, TimeOfDay(12, 0, 0));
+
+ const ctod = TimeOfDay(0, 0, 0);
+ immutable itod = TimeOfDay(0, 0, 0);
+ static assert(!__traits(compiles, ctod.hour = 12));
+ static assert(!__traits(compiles, itod.hour = 12));
+ }
+
+
+ /++
+ Minutes passed the hour.
+ +/
+ @property ubyte minute() const pure nothrow
+ {
+ return _minute;
+ }
+
+ unittest
+ {
+ assertPred!"=="(TimeOfDay.init.minute, 0);
+ assertPred!"=="(TimeOfDay(0, 30, 0).minute, 30);
+
+ const ctod = TimeOfDay(0, 30, 0);
+ immutable itod = TimeOfDay(0, 30, 0);
+ static assert(__traits(compiles, ctod.minute == 30));
+ static assert(__traits(compiles, itod.minute == 30));
+ }
+
+
+ /++
+ Minutes passed the hour.
+
+ Params:
+ minute = The minute to set this TimeOfDay's minute to.
+
+ Throws:
+ DateTimeException if the given minute would result in an invalid TimeOfDay.
+ +/
+ @property void minute(int minute) pure
+ {
+ enforceValid!"minutes"(minute);
+ _minute = cast(ubyte)minute;
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).minute = 60;}());
+
+ auto tod = TimeOfDay(0, 0, 0);
+ tod.minute = 30;
+ assertPred!"=="(tod, TimeOfDay(0, 30, 0));
+
+ const ctod = TimeOfDay(0, 0, 0);
+ immutable itod = TimeOfDay(0, 0, 0);
+ static assert(!__traits(compiles, ctod.minute = 30));
+ static assert(!__traits(compiles, itod.minute = 30));
+ }
+
+
+ /++
+ Seconds passed the minute.
+ +/
+ @property ubyte second() const pure nothrow
+ {
+ return _second;
+ }
+
+ unittest
+ {
+ assertPred!"=="(TimeOfDay.init.second, 0);
+ assertPred!"=="(TimeOfDay(0, 0, 33).second, 33);
+
+ const ctod = TimeOfDay(0, 0, 33);
+ immutable itod = TimeOfDay(0, 0, 33);
+ static assert(__traits(compiles, ctod.second == 33));
+ static assert(__traits(compiles, itod.second == 33));
+ }
+
+
+ /++
+ Seconds passed the minute.
+
+ Params:
+ second = The second to set this TimeOfDay's second to.
+
+ Throws:
+ DateTimeException if the given second would result in an invalid TimeOfDay.
+ +/
+ @property void second(int second) pure
+ {
+ enforceValid!"seconds"(second);
+ _second = cast(ubyte)second;
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).second = 60;}());
+
+ auto tod = TimeOfDay(0, 0, 0);
+ tod.second = 33;
+ assertPred!"=="(tod, TimeOfDay(0, 0, 33));
+
+ const ctod = TimeOfDay(0, 0, 0);
+ immutable itod = TimeOfDay(0, 0, 0);
+ static assert(!__traits(compiles, ctod.second = 33));
+ static assert(!__traits(compiles, itod.second = 33));
+ }
+
+
+ /++
+ Adds the given number of hours to this TimeOfDay. A negative number will
+ subtract.
+
+ For hours, because they are the largest unit in TimeOfDay, there is no
+ difference between adding or rolling.
+
+ Note that TimeOfDay has no $(D add!()) function because you can add to a
+ TimeOfDay by adding a duration to it.
+
+ Params:
+ hours = The number of hours to add to this TimeOfDay.
+
+ Examples:
+--------------------
+auto tod1 = TimeOfDay(7, 12, 0);
+tod1.roll!"hours"(1);
+assert(tod1 == TimeOfDay(8, 12, 0));
+
+auto tod2 = TimeOfDay(7, 12, 0);
+tod2.roll!"hours"(-1);
+assert(tod2 == TimeOfDay(6, 12, 0));
+
+auto tod3 = TimeOfDay(23, 0, 0);
+tod3.roll!"hours"(1);
+assert(tod3 == TimeOfDay(0, 0, 0));
+
+auto tod4 = TimeOfDay(0, 0, 0);
+tod4.roll!"hours"(-1);
+assert(tod4 == TimeOfDay(23, 0, 0));
+--------------------
+ +/
+ /+ref TimeOfDay+/ void roll(string units)(long hours) pure nothrow
+ if(units == "hours")
+ {
+ this += dur!"hours"(hours);
+ }
+
+ unittest
+ {
+ const ctod = TimeOfDay(0, 0, 0);
+ immutable itod = TimeOfDay(0, 0, 0);
+ static assert(!__traits(compiles, ctod.roll!"hours"(53)));
+ static assert(!__traits(compiles, itod.roll!"hours"(53)));
+
+ //Verify Examples.
+ auto tod1 = TimeOfDay(7, 12, 0);
+ tod1.roll!"hours"(1);
+ assert(tod1 == TimeOfDay(8, 12, 0));
+
+ auto tod2 = TimeOfDay(7, 12, 0);
+ tod2.roll!"hours"(-1);
+ assert(tod2 == TimeOfDay(6, 12, 0));
+
+ auto tod3 = TimeOfDay(23, 0, 0);
+ tod3.roll!"hours"(1);
+ assert(tod3 == TimeOfDay(0, 0, 0));
+
+ auto tod4 = TimeOfDay(0, 0, 0);
+ tod4.roll!"hours"(-1);
+ assert(tod4 == TimeOfDay(23, 0, 0));
+ }
+
+
+ /++
+ Add minutes to the time of day. Negative values will subtract.
+
+ The difference between rolling and adding is that rolling does not affect
+ larger units. So, if you roll the TimeOfDay 60 minutes, you get the exact
+ same TimeOfDay.
+
+ Note that TimeOfDay has no $(D add!()) function because you can add to a
+ TimeOfDay by adding a duration to it.
+
+ Params:
+ minutes = The number of Minutes to add to this TimeOfDay.
+
+ Examples:
+--------------------
+auto tod1 = TimeOfDay(7, 12, 0);
+tod1.roll!"minutes"(1);
+assert(tod1 == TimeOfDay(7, 13, 0));
+
+auto tod2 = TimeOfDay(7, 12, 0);
+tod2.roll!"minutes"(-1);
+assert(tod2 == TimeOfDay(7, 11, 0));
+
+auto tod3 = TimeOfDay(23, 59, 0);
+tod3.roll!"minutes"(1);
+assert(tod3 == TimeOfDay(23, 0, 0));
+
+auto tod4 = TimeOfDay(0, 0, 0);
+tod4.roll!"minutes"(-1);
+assert(tod4 == TimeOfDay(0, 59, 0));
+
+auto tod5 = TimeOfDay(7, 32, 12);
+tod5.roll!"seconds"(1);
+assert(tod5 == TimeOfDay(7, 32, 13));
+
+auto tod6 = TimeOfDay(7, 32, 12);
+tod6.roll!"seconds"(-1);
+assert(tod6 == TimeOfDay(7, 32, 11));
+
+auto tod7 = TimeOfDay(23, 59, 59);
+tod7.roll!"seconds"(1);
+assert(tod7 == TimeOfDay(23, 59, 0));
+
+auto tod8 = TimeOfDay(0, 0, 0);
+tod8.roll!"seconds"(-1);
+assert(tod8 == TimeOfDay(0, 0, 59));
+--------------------
+ +/
+ /+ref TimeOfDay+/ void roll(string units)(long value) pure nothrow
+ if(units == "minutes" ||
+ units == "seconds")
+ {
+ static if(units == "minutes")
+ enum memberVarStr = "minute";
+ else static if(units == "seconds")
+ enum memberVarStr = "second";
+ else
+ static assert(0);
+
+ value %= 60;
+ mixin("auto newVal = cast(ubyte)(_" ~ memberVarStr ~ ") + value;");
+
+ if(value < 0)
+ {
+ if(newVal < 0)
+ newVal += 60;
+ }
+ else if(newVal >= 60)
+ newVal -= 60;
+
+ mixin("_" ~ memberVarStr ~ " = cast(ubyte)newVal;");
+ }
+
+ //Test roll!"minutes"().
+ unittest
+ {
+ static void testTOD(TimeOfDay orig, int minutes, in TimeOfDay expected, size_t line = __LINE__)
+ {
+ orig.roll!"minutes"(minutes);
+ assertPred!"=="(orig, expected, "", __FILE__, line);
+ }
+
+ testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33));
+ testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 31, 33));
+ testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 32, 33));
+ testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 33, 33));
+ testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 34, 33));
+ testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 35, 33));
+ testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 40, 33));
+ testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 45, 33));
+ testTOD(TimeOfDay(12, 30, 33), 29, TimeOfDay(12, 59, 33));
+ testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 0, 33));
+ testTOD(TimeOfDay(12, 30, 33), 45, TimeOfDay(12, 15, 33));
+ testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 30, 33));
+ testTOD(TimeOfDay(12, 30, 33), 75, TimeOfDay(12, 45, 33));
+ testTOD(TimeOfDay(12, 30, 33), 90, TimeOfDay(12, 0, 33));
+ testTOD(TimeOfDay(12, 30, 33), 100, TimeOfDay(12, 10, 33));
+
+ testTOD(TimeOfDay(12, 30, 33), 689, TimeOfDay(12, 59, 33));
+ testTOD(TimeOfDay(12, 30, 33), 690, TimeOfDay(12, 0, 33));
+ testTOD(TimeOfDay(12, 30, 33), 691, TimeOfDay(12, 1, 33));
+ testTOD(TimeOfDay(12, 30, 33), 960, TimeOfDay(12, 30, 33));
+ testTOD(TimeOfDay(12, 30, 33), 1439, TimeOfDay(12, 29, 33));
+ testTOD(TimeOfDay(12, 30, 33), 1440, TimeOfDay(12, 30, 33));
+ testTOD(TimeOfDay(12, 30, 33), 1441, TimeOfDay(12, 31, 33));
+ testTOD(TimeOfDay(12, 30, 33), 2880, TimeOfDay(12, 30, 33));
+
+ testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 29, 33));
+ testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 28, 33));
+ testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 27, 33));
+ testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 26, 33));
+ testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 25, 33));
+ testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 20, 33));
+ testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 15, 33));
+ testTOD(TimeOfDay(12, 30, 33), -29, TimeOfDay(12, 1, 33));
+ testTOD(TimeOfDay(12, 30, 33), -30, TimeOfDay(12, 0, 33));
+ testTOD(TimeOfDay(12, 30, 33), -45, TimeOfDay(12, 45, 33));
+ testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 30, 33));
+ testTOD(TimeOfDay(12, 30, 33), -75, TimeOfDay(12, 15, 33));
+ testTOD(TimeOfDay(12, 30, 33), -90, TimeOfDay(12, 0, 33));
+ testTOD(TimeOfDay(12, 30, 33), -100, TimeOfDay(12, 50, 33));
+
+ testTOD(TimeOfDay(12, 30, 33), -749, TimeOfDay(12, 1, 33));
+ testTOD(TimeOfDay(12, 30, 33), -750, TimeOfDay(12, 0, 33));
+ testTOD(TimeOfDay(12, 30, 33), -751, TimeOfDay(12, 59, 33));
+ testTOD(TimeOfDay(12, 30, 33), -960, TimeOfDay(12, 30, 33));
+ testTOD(TimeOfDay(12, 30, 33), -1439, TimeOfDay(12, 31, 33));
+ testTOD(TimeOfDay(12, 30, 33), -1440, TimeOfDay(12, 30, 33));
+ testTOD(TimeOfDay(12, 30, 33), -1441, TimeOfDay(12, 29, 33));
+ testTOD(TimeOfDay(12, 30, 33), -2880, TimeOfDay(12, 30, 33));
+
+ testTOD(TimeOfDay(12, 0, 33), 1, TimeOfDay(12, 1, 33));
+ testTOD(TimeOfDay(12, 0, 33), 0, TimeOfDay(12, 0, 33));
+ testTOD(TimeOfDay(12, 0, 33), -1, TimeOfDay(12, 59, 33));
+
+ testTOD(TimeOfDay(11, 59, 33), 1, TimeOfDay(11, 0, 33));
+ testTOD(TimeOfDay(11, 59, 33), 0, TimeOfDay(11, 59, 33));
+ testTOD(TimeOfDay(11, 59, 33), -1, TimeOfDay(11, 58, 33));
+
+ testTOD(TimeOfDay(0, 0, 33), 1, TimeOfDay(0, 1, 33));
+ testTOD(TimeOfDay(0, 0, 33), 0, TimeOfDay(0, 0, 33));
+ testTOD(TimeOfDay(0, 0, 33), -1, TimeOfDay(0, 59, 33));
+
+ testTOD(TimeOfDay(23, 59, 33), 1, TimeOfDay(23, 0, 33));
+ testTOD(TimeOfDay(23, 59, 33), 0, TimeOfDay(23, 59, 33));
+ testTOD(TimeOfDay(23, 59, 33), -1, TimeOfDay(23, 58, 33));
+
+ const ctod = TimeOfDay(0, 0, 0);
+ immutable itod = TimeOfDay(0, 0, 0);
+ static assert(!__traits(compiles, ctod.roll!"minutes"(7)));
+ static assert(!__traits(compiles, itod.roll!"minutes"(7)));
+
+ //Verify Examples.
+ auto tod1 = TimeOfDay(7, 12, 0);
+ tod1.roll!"minutes"(1);
+ assert(tod1 == TimeOfDay(7, 13, 0));
+
+ auto tod2 = TimeOfDay(7, 12, 0);
+ tod2.roll!"minutes"(-1);
+ assert(tod2 == TimeOfDay(7, 11, 0));
+
+ auto tod3 = TimeOfDay(23, 59, 0);
+ tod3.roll!"minutes"(1);
+ assert(tod3 == TimeOfDay(23, 0, 0));
+
+ auto tod4 = TimeOfDay(0, 0, 0);
+ tod4.roll!"minutes"(-1);
+ assert(tod4 == TimeOfDay(0, 59, 0));
+
+ auto tod5 = TimeOfDay(7, 32, 12);
+ tod5.roll!"seconds"(1);
+ assert(tod5 == TimeOfDay(7, 32, 13));
+
+ auto tod6 = TimeOfDay(7, 32, 12);
+ tod6.roll!"seconds"(-1);
+ assert(tod6 == TimeOfDay(7, 32, 11));
+
+ auto tod7 = TimeOfDay(23, 59, 59);
+ tod7.roll!"seconds"(1);
+ assert(tod7 == TimeOfDay(23, 59, 0));
+
+ auto tod8 = TimeOfDay(0, 0, 0);
+ tod8.roll!"seconds"(-1);
+ assert(tod8 == TimeOfDay(0, 0, 59));
+ }
+
+ //Test roll!"seconds"().
+ unittest
+ {
+ static void testTOD(TimeOfDay orig, int seconds, in TimeOfDay expected, size_t line = __LINE__)
+ {
+ orig.roll!"seconds"(seconds);
+ assertPred!"=="(orig, expected, "", __FILE__, line);
+ }
+
+ testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33));
+ testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 30, 34));
+ testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 30, 35));
+ testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 30, 36));
+ testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 30, 37));
+ testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 30, 38));
+ testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 30, 43));
+ testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 30, 48));
+ testTOD(TimeOfDay(12, 30, 33), 26, TimeOfDay(12, 30, 59));
+ testTOD(TimeOfDay(12, 30, 33), 27, TimeOfDay(12, 30, 0));
+ testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 30, 3));
+ testTOD(TimeOfDay(12, 30, 33), 59, TimeOfDay(12, 30, 32));
+ testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 30, 33));
+ testTOD(TimeOfDay(12, 30, 33), 61, TimeOfDay(12, 30, 34));
+
+ testTOD(TimeOfDay(12, 30, 33), 1766, TimeOfDay(12, 30, 59));
+ testTOD(TimeOfDay(12, 30, 33), 1767, TimeOfDay(12, 30, 0));
+ testTOD(TimeOfDay(12, 30, 33), 1768, TimeOfDay(12, 30, 1));
+ testTOD(TimeOfDay(12, 30, 33), 2007, TimeOfDay(12, 30, 0));
+ testTOD(TimeOfDay(12, 30, 33), 3599, TimeOfDay(12, 30, 32));
+ testTOD(TimeOfDay(12, 30, 33), 3600, TimeOfDay(12, 30, 33));
+ testTOD(TimeOfDay(12, 30, 33), 3601, TimeOfDay(12, 30, 34));
+ testTOD(TimeOfDay(12, 30, 33), 7200, TimeOfDay(12, 30, 33));
+
+ testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 30, 32));
+ testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 30, 31));
+ testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 30, 30));
+ testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 30, 29));
+ testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 30, 28));
+ testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 30, 23));
+ testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 30, 18));
+ testTOD(TimeOfDay(12, 30, 33), -33, TimeOfDay(12, 30, 0));
+ testTOD(TimeOfDay(12, 30, 33), -34, TimeOfDay(12, 30, 59));
+ testTOD(TimeOfDay(12, 30, 33), -35, TimeOfDay(12, 30, 58));
+ testTOD(TimeOfDay(12, 30, 33), -59, TimeOfDay(12, 30, 34));
+ testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 30, 33));
+ testTOD(TimeOfDay(12, 30, 33), -61, TimeOfDay(12, 30, 32));
+
+ testTOD(TimeOfDay(12, 30, 0), 1, TimeOfDay(12, 30, 1));
+ testTOD(TimeOfDay(12, 30, 0), 0, TimeOfDay(12, 30, 0));
+ testTOD(TimeOfDay(12, 30, 0), -1, TimeOfDay(12, 30, 59));
+
+ testTOD(TimeOfDay(12, 0, 0), 1, TimeOfDay(12, 0, 1));
+ testTOD(TimeOfDay(12, 0, 0), 0, TimeOfDay(12, 0, 0));
+ testTOD(TimeOfDay(12, 0, 0), -1, TimeOfDay(12, 0, 59));
+
+ testTOD(TimeOfDay(0, 0, 0), 1, TimeOfDay(0, 0, 1));
+ testTOD(TimeOfDay(0, 0, 0), 0, TimeOfDay(0, 0, 0));
+ testTOD(TimeOfDay(0, 0, 0), -1, TimeOfDay(0, 0, 59));
+
+ testTOD(TimeOfDay(23, 59, 59), 1, TimeOfDay(23, 59, 0));
+ testTOD(TimeOfDay(23, 59, 59), 0, TimeOfDay(23, 59, 59));
+ testTOD(TimeOfDay(23, 59, 59), -1, TimeOfDay(23, 59, 58));
+
+ const ctod = TimeOfDay(0, 0, 0);
+ immutable itod = TimeOfDay(0, 0, 0);
+ static assert(!__traits(compiles, ctod.roll!"seconds"(7)));
+ static assert(!__traits(compiles, itod.roll!"seconds"(7)));
+ }
+
+
+ /++
+ Gives the result of adding or subtracting a duration from this TimeOfDay.
+
+ The legal types of arithmetic for TimeOfDay using this operator are
+
+ $(TABLE
+ $(TR $(TD TimeOfDay) $(TD +) $(TD duration) $(TD -->) $(TD TimeOfDay))
+ $(TR $(TD TimeOfDay) $(TD -) $(TD duration) $(TD -->) $(TD TimeOfDay))
+ )
+
+ Params:
+ duration = The duration to add to or subtract from this Date.
+ +/
+ TimeOfDay opBinary(string op, D)(in D duration) const pure nothrow
+ if((op == "+" || op == "-") &&
+ (is(Unqual!D == Duration) ||
+ is(Unqual!D == TickDuration)))
+ {
+ TimeOfDay retval = this;
+
+ static if(is(Unqual!D == Duration))
+ immutable hnsecs = duration.total!"hnsecs";
+ else static if(is(Unqual!D == TickDuration))
+ immutable hnsecs = duration.hnsecs;
+
+ //Ideally, this would just be
+ //return retval.addSeconds(convert!("hnsecs", "seconds")(unaryFun!(op ~ "a")(hnsecs)));
+ //But there isn't currently a pure version of unaryFun!().
+
+ static if(op == "+")
+ immutable signedHNSecs = hnsecs;
+ else static if(op == "-")
+ immutable signedHNSecs = -hnsecs;
+ else
+ static assert(0);
+
+ return retval.addSeconds(convert!("hnsecs", "seconds")(signedHNSecs));
+ }
+
+ unittest
+ {
+ auto tod = TimeOfDay(12, 30, 33);
+
+ assertPred!"=="(tod + dur!"hours"(7), TimeOfDay(19, 30, 33));
+ assertPred!"=="(tod + dur!"hours"(-7), TimeOfDay(5, 30, 33));
+ assertPred!"=="(tod + dur!"minutes"(7), TimeOfDay(12, 37, 33));
+ assertPred!"=="(tod + dur!"minutes"(-7), TimeOfDay(12, 23, 33));
+ assertPred!"=="(tod + dur!"seconds"(7), TimeOfDay(12, 30, 40));
+ assertPred!"=="(tod + dur!"seconds"(-7), TimeOfDay(12, 30, 26));
+
+ assertPred!"=="(tod + dur!"msecs"(7000), TimeOfDay(12, 30, 40));
+ assertPred!"=="(tod + dur!"msecs"(-7000), TimeOfDay(12, 30, 26));
+ assertPred!"=="(tod + dur!"usecs"(7_000_000), TimeOfDay(12, 30, 40));
+ assertPred!"=="(tod + dur!"usecs"(-7_000_000), TimeOfDay(12, 30, 26));
+ assertPred!"=="(tod + dur!"hnsecs"(70_000_000), TimeOfDay(12, 30, 40));
+ assertPred!"=="(tod + dur!"hnsecs"(-70_000_000), TimeOfDay(12, 30, 26));
+
+ //This probably only runs in cases where gettimeofday() is used, but it's
+ //hard to do this test correctly with variable ticksPerSec.
+ if(TickDuration.ticksPerSec == 1_000_000)
+ {
+ assertPred!"=="(tod + TickDuration.from!"usecs"(7_000_000), TimeOfDay(12, 30, 40));
+ assertPred!"=="(tod + TickDuration.from!"usecs"(-7_000_000), TimeOfDay(12, 30, 26));
+ }
+
+ assertPred!"=="(tod - dur!"hours"(-7), TimeOfDay(19, 30, 33));
+ assertPred!"=="(tod - dur!"hours"(7), TimeOfDay(5, 30, 33));
+ assertPred!"=="(tod - dur!"minutes"(-7), TimeOfDay(12, 37, 33));
+ assertPred!"=="(tod - dur!"minutes"(7), TimeOfDay(12, 23, 33));
+ assertPred!"=="(tod - dur!"seconds"(-7), TimeOfDay(12, 30, 40));
+ assertPred!"=="(tod - dur!"seconds"(7), TimeOfDay(12, 30, 26));
+
+ assertPred!"=="(tod - dur!"msecs"(-7000), TimeOfDay(12, 30, 40));
+ assertPred!"=="(tod - dur!"msecs"(7000), TimeOfDay(12, 30, 26));
+ assertPred!"=="(tod - dur!"usecs"(-7_000_000), TimeOfDay(12, 30, 40));
+ assertPred!"=="(tod - dur!"usecs"(7_000_000), TimeOfDay(12, 30, 26));
+ assertPred!"=="(tod - dur!"hnsecs"(-70_000_000), TimeOfDay(12, 30, 40));
+ assertPred!"=="(tod - dur!"hnsecs"(70_000_000), TimeOfDay(12, 30, 26));
+
+ //This probably only runs in cases where gettimeofday() is used, but it's
+ //hard to do this test correctly with variable ticksPerSec.
+ if(TickDuration.ticksPerSec == 1_000_000)
+ {
+ assertPred!"=="(tod - TickDuration.from!"usecs"(-7_000_000), TimeOfDay(12, 30, 40));
+ assertPred!"=="(tod - TickDuration.from!"usecs"(7_000_000), TimeOfDay(12, 30, 26));
+ }
+
+ auto duration = dur!"hours"(11);
+ const ctod = TimeOfDay(12, 33, 30);
+ immutable itod = TimeOfDay(12, 33, 30);
+ static assert(__traits(compiles, tod + duration));
+ static assert(__traits(compiles, ctod + duration));
+ static assert(__traits(compiles, itod + duration));
+
+ static assert(__traits(compiles, tod - duration));
+ static assert(__traits(compiles, ctod - duration));
+ static assert(__traits(compiles, itod - duration));
+ }
+
+
+ /++
+ Gives the result of adding or subtracting a duration from this TimeOfDay,
+ as well as assigning the result to this TimeOfDay.
+
+ The legal types of arithmetic for TimeOfDay using this operator are
+
+ $(TABLE
+ $(TR $(TD TimeOfDay) $(TD +) $(TD duration) $(TD -->) $(TD TimeOfDay))
+ $(TR $(TD TimeOfDay) $(TD -) $(TD duration) $(TD -->) $(TD TimeOfDay))
+ )
+
+ Params:
+ duration = The duration to add to or subtract from this TimeOfDay.
+ +/
+ /+ref+/ TimeOfDay opOpAssign(string op, D)(in D duration) pure nothrow
+ if((op == "+" || op == "-") &&
+ (is(Unqual!D == Duration) ||
+ is(Unqual!D == TickDuration)))
+ {
+ static if(is(Unqual!D == Duration))
+ immutable hnsecs = duration.total!"hnsecs";
+ else static if(is(Unqual!D == TickDuration))
+ immutable hnsecs = duration.hnsecs;
+
+ //Ideally, this would just be
+ //return addSeconds(convert!("hnsecs", "seconds")(unaryFun!(op ~ "a")(hnsecs)));
+ //But there isn't currently a pure version of unaryFun!().
+
+ static if(op == "+")
+ immutable signedHNSecs = hnsecs;
+ else static if(op == "-")
+ immutable signedHNSecs = -hnsecs;
+ else
+ static assert(0);
+
+ return addSeconds(convert!("hnsecs", "seconds")(signedHNSecs));
+ }
+
+ unittest
+ {
+ auto duration = dur!"hours"(12);
+
+ assertPred!"+="(TimeOfDay(12, 30, 33), dur!"hours"(7), TimeOfDay(19, 30, 33));
+ assertPred!"+="(TimeOfDay(12, 30, 33), dur!"hours"(-7), TimeOfDay(5, 30, 33));
+ assertPred!"+="(TimeOfDay(12, 30, 33), dur!"minutes"(7), TimeOfDay(12, 37, 33));
+ assertPred!"+="(TimeOfDay(12, 30, 33), dur!"minutes"(-7), TimeOfDay(12, 23, 33));
+ assertPred!"+="(TimeOfDay(12, 30, 33), dur!"seconds"(7), TimeOfDay(12, 30, 40));
+ assertPred!"+="(TimeOfDay(12, 30, 33), dur!"seconds"(-7), TimeOfDay(12, 30, 26));
+
+ assertPred!"+="(TimeOfDay(12, 30, 33), dur!"msecs"(7000), TimeOfDay(12, 30, 40));
+ assertPred!"+="(TimeOfDay(12, 30, 33), dur!"msecs"(-7000), TimeOfDay(12, 30, 26));
+ assertPred!"+="(TimeOfDay(12, 30, 33), dur!"usecs"(7_000_000), TimeOfDay(12, 30, 40));
+ assertPred!"+="(TimeOfDay(12, 30, 33), dur!"usecs"(-7_000_000), TimeOfDay(12, 30, 26));
+ assertPred!"+="(TimeOfDay(12, 30, 33), dur!"hnsecs"(70_000_000), TimeOfDay(12, 30, 40));
+ assertPred!"+="(TimeOfDay(12, 30, 33), dur!"hnsecs"(-70_000_000), TimeOfDay(12, 30, 26));
+
+ assertPred!"-="(TimeOfDay(12, 30, 33), dur!"hours"(-7), TimeOfDay(19, 30, 33));
+ assertPred!"-="(TimeOfDay(12, 30, 33), dur!"hours"(7), TimeOfDay(5, 30, 33));
+ assertPred!"-="(TimeOfDay(12, 30, 33), dur!"minutes"(-7), TimeOfDay(12, 37, 33));
+ assertPred!"-="(TimeOfDay(12, 30, 33), dur!"minutes"(7), TimeOfDay(12, 23, 33));
+ assertPred!"-="(TimeOfDay(12, 30, 33), dur!"seconds"(-7), TimeOfDay(12, 30, 40));
+ assertPred!"-="(TimeOfDay(12, 30, 33), dur!"seconds"(7), TimeOfDay(12, 30, 26));
+
+ assertPred!"-="(TimeOfDay(12, 30, 33), dur!"msecs"(-7000), TimeOfDay(12, 30, 40));
+ assertPred!"-="(TimeOfDay(12, 30, 33), dur!"msecs"(7000), TimeOfDay(12, 30, 26));
+ assertPred!"-="(TimeOfDay(12, 30, 33), dur!"usecs"(-7_000_000), TimeOfDay(12, 30, 40));
+ assertPred!"-="(TimeOfDay(12, 30, 33), dur!"usecs"(7_000_000), TimeOfDay(12, 30, 26));
+ assertPred!"-="(TimeOfDay(12, 30, 33), dur!"hnsecs"(-70_000_000), TimeOfDay(12, 30, 40));
+ assertPred!"-="(TimeOfDay(12, 30, 33), dur!"hnsecs"(70_000_000), TimeOfDay(12, 30, 26));
+
+ const ctod = TimeOfDay(12, 33, 30);
+ immutable itod = TimeOfDay(12, 33, 30);
+ static assert(!__traits(compiles, ctod += duration));
+ static assert(!__traits(compiles, itod += duration));
+ static assert(!__traits(compiles, ctod -= duration));
+ static assert(!__traits(compiles, itod -= duration));
+ }
+
+
+ /++
+ Gives the difference between two TimeOfDays.
+
+ The legal types of arithmetic for TimeOfDay using this operator are
+
+ $(TABLE
+ $(TR $(TD TimeOfDay) $(TD -) $(TD TimeOfDay) $(TD -->) $(TD duration))
+ )
+
+ Params:
+ rhs = The TimeOfDay to subtract from this one.
+ +/
+ Duration opBinary(string op)(in TimeOfDay rhs) const pure nothrow
+ if(op == "-")
+ {
+ immutable lhsSec = _hour * 3600 + _minute * 60 + _second;
+ immutable rhsSec = rhs._hour * 3600 + rhs._minute * 60 + rhs._second;
+
+ return dur!"seconds"(lhsSec - rhsSec);
+ }
+
+ unittest
+ {
+ auto tod = TimeOfDay(12, 30, 33);
+
+ assertPred!"=="(TimeOfDay(7, 12, 52) - TimeOfDay(12, 30, 33), dur!"seconds"(-19_061));
+ assertPred!"=="(TimeOfDay(12, 30, 33) - TimeOfDay(7, 12, 52), dur!"seconds"(19_061));
+ assertPred!"=="(TimeOfDay(12, 30, 33) - TimeOfDay(14, 30, 33), dur!"seconds"(-7200));
+ assertPred!"=="(TimeOfDay(14, 30, 33) - TimeOfDay(12, 30, 33), dur!"seconds"(7200));
+ assertPred!"=="(TimeOfDay(12, 30, 33) - TimeOfDay(12, 34, 33), dur!"seconds"(-240));
+ assertPred!"=="(TimeOfDay(12, 34, 33) - TimeOfDay(12, 30, 33), dur!"seconds"(240));
+ assertPred!"=="(TimeOfDay(12, 30, 33) - TimeOfDay(12, 30, 34), dur!"seconds"(-1));
+ assertPred!"=="(TimeOfDay(12, 30, 34) - TimeOfDay(12, 30, 33), dur!"seconds"(1));
+
+ const ctod = TimeOfDay(12, 30, 33);
+ immutable itod = TimeOfDay(12, 30, 33);
+ static assert(__traits(compiles, tod - tod));
+ static assert(__traits(compiles, ctod - tod));
+ static assert(__traits(compiles, itod - tod));
+
+ static assert(__traits(compiles, tod - ctod));
+ static assert(__traits(compiles, ctod - ctod));
+ static assert(__traits(compiles, itod - ctod));
+
+ static assert(__traits(compiles, tod - itod));
+ static assert(__traits(compiles, ctod - itod));
+ static assert(__traits(compiles, itod - itod));
+ }
+
+
+ /++
+ Converts this TimeOfDay to a string with the format HHMMSS.
+
+ Examples:
+--------------------
+assert(TimeOfDay(0, 0, 0).toISOString() == "000000");
+assert(TimeOfDay(12, 30, 33).toISOString() == "123033");
+--------------------
+ +/
+ string toISOString() const nothrow
+ {
+ try
+ return format("%02d%02d%02d", _hour, _minute, _second);
+ catch(Exception e)
+ assert(0, "format() threw.");
+ }
+
+ unittest
+ {
+ auto tod = TimeOfDay(12, 30, 33);
+ const ctod = TimeOfDay(12, 30, 33);
+ immutable itod = TimeOfDay(12, 30, 33);
+ static assert(__traits(compiles, tod.toISOString()));
+ static assert(__traits(compiles, ctod.toISOString()));
+ static assert(__traits(compiles, itod.toISOString()));
+
+ //Verify Examples.
+ assert(TimeOfDay(0, 0, 0).toISOString() == "000000");
+ assert(TimeOfDay(12, 30, 33).toISOString() == "123033");
+ }
+
+
+ /++
+ Converts this TimeOfDay to a string with the format HH:MM:SS.
+
+ Examples:
+--------------------
+assert(TimeOfDay(0, 0, 0).toISOExtendedString() == "000000");
+assert(TimeOfDay(12, 30, 33).toISOExtendedString() == "123033");
+--------------------
+ +/
+ string toISOExtendedString() const nothrow
+ {
+ try
+ return format("%02d:%02d:%02d", _hour, _minute, _second);
+ catch(Exception e)
+ assert(0, "format() threw.");
+ }
+
+
+ unittest
+ {
+ auto tod = TimeOfDay(12, 30, 33);
+ const ctod = TimeOfDay(12, 30, 33);
+ immutable itod = TimeOfDay(12, 30, 33);
+ static assert(__traits(compiles, tod.toISOExtendedString()));
+ static assert(__traits(compiles, ctod.toISOExtendedString()));
+ static assert(__traits(compiles, itod.toISOExtendedString()));
+
+ //Verify Examples.
+ assert(TimeOfDay(0, 0, 0).toISOExtendedString() == "00:00:00");
+ assert(TimeOfDay(12, 30, 33).toISOExtendedString() == "12:30:33");
+ }
+
+
+ /+
+ Converts this TimeOfDay to a string.
+ +/
+ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't
+ //have versions of toString() with extra modifiers, so we define one version
+ //with modifiers and one without.
+ string toString()
+ {
+ return toISOExtendedString();
+ }
+
+
+ /++
+ Converts this TimeOfDay to a string.
+ +/
+ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't
+ //have versions of toString() with extra modifiers, so we define one version
+ //with modifiers and one without.
+ string toString() const nothrow
+ {
+ return toISOExtendedString();
+ }
+
+ unittest
+ {
+ auto tod = TimeOfDay(12, 30, 33);
+ const ctod = TimeOfDay(12, 30, 33);
+ immutable itod = TimeOfDay(12, 30, 33);
+ static assert(__traits(compiles, tod.toString()));
+ static assert(__traits(compiles, ctod.toString()));
+ static assert(__traits(compiles, itod.toString()));
+ }
+
+ //TODO Add a function which returns a string in a user-specified format.
+
+
+
+ /++
+ Creates a TimeOfDay from a string with the format HHMMSS. Whitespace is
+ stripped from the given string.
+
+ Params:
+ isoString = A string formatted in the ISO format for times.
+
+ Throws:
+ DateTimeException if the given string is not in the ISO format or if
+ the resulting TimeOfDay would not be valid.
+
+ Examples:
+--------------------
+assert(TimeOfDay.fromISOString("000000") == TimeOfDay(0, 0, 0));
+assert(TimeOfDay.fromISOString("123033") == TimeOfDay(12, 30, 33));
+assert(TimeOfDay.fromISOString(" 123033 ") == TimeOfDay(12, 30, 33));
+--------------------
+ +/
+ static TimeOfDay fromISOString(S)(in S isoString)
+ if(isSomeString!S)
+ {
+ auto dstr = to!dstring(strip(isoString));
+
+ enforce(dstr.length == 6, new DateTimeException(format("Invalid ISO String: %s", isoString)));
+
+ auto hours = dstr[0 .. 2];
+ auto minutes = dstr[2 .. 4];
+ auto seconds = dstr[4 .. $];
+
+ enforce(!canFind!((dchar c){return !isdigit(c);})(hours), new DateTimeException(format("Invalid ISO String: %s", isoString)));
+ enforce(!canFind!((dchar c){return !isdigit(c);})(minutes), new DateTimeException(format("Invalid ISO String: %s", isoString)));
+ enforce(!canFind!((dchar c){return !isdigit(c);})(seconds), new DateTimeException(format("Invalid ISO String: %s", isoString)));
+
+ return TimeOfDay(to!int(hours), to!int(minutes), to!int(seconds));
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException(TimeOfDay.fromISOString(""));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("0"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("00"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("000"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("0000"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("00000"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("13033"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("1277"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("12707"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("12070"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("12303a"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("1230a3"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("123a33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("12a033"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("1a0033"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("a20033"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("1200330"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("0120033"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("-120033"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("+120033"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("120033am"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("120033pm"));
+
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("0::"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString(":0:"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("::0"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("0:0:0"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("0:0:00"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("0:00:0"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("00:0:0"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("00:00:0"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("00:0:00"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("13:0:33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("12:7:7"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("12:7:07"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("12:07:0"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("12:30:3a"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("12:30:a3"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("12:3a:33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("12:a0:33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("1a:00:33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("a2:00:33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("12:003:30"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("120:03:30"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("012:00:33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("01:200:33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("-12:00:33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("+12:00:33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33am"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33pm"));
+
+ assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33"));
+
+ assertPred!"=="(TimeOfDay.fromISOString("011217"), TimeOfDay(1, 12, 17));
+ assertPred!"=="(TimeOfDay.fromISOString("001412"), TimeOfDay(0, 14, 12));
+ assertPred!"=="(TimeOfDay.fromISOString("000007"), TimeOfDay(0, 0, 7));
+ assertPred!"=="(TimeOfDay.fromISOString("011217 "), TimeOfDay(1, 12, 17));
+ assertPred!"=="(TimeOfDay.fromISOString(" 011217"), TimeOfDay(1, 12, 17));
+ assertPred!"=="(TimeOfDay.fromISOString(" 011217 "), TimeOfDay(1, 12, 17));
+
+ //Verify Examples.
+ assert(TimeOfDay.fromISOString("000000") == TimeOfDay(0, 0, 0));
+ assert(TimeOfDay.fromISOString("123033") == TimeOfDay(12, 30, 33));
+ assert(TimeOfDay.fromISOString(" 123033 ") == TimeOfDay(12, 30, 33));
+ }
+
+
+ /++
+ Creates a TimeOfDay from a string with the format HH:MM:SS. Whitespace is
+ stripped from the given string.
+
+ Params:
+ isoString = A string formatted in the ISO Extended format for times.
+
+ Throws:
+ DateTimeException if the given string is not in the ISO Extended
+ format or if the resulting TimeOfDay would not be valid.
+
+ Examples:
+--------------------
+assert(TimeOfDay.fromISOExtendedString("00:00:00") == TimeOfDay(0, 0, 0));
+assert(TimeOfDay.fromISOExtendedString("12:30:33") == TimeOfDay(12, 30, 33));
+assert(TimeOfDay.fromISOExtendedString(" 12:30:33 ") == TimeOfDay(12, 30, 33));
+--------------------
+ +/
+ static TimeOfDay fromISOExtendedString(S)(in S isoExtString)
+ if(isSomeString!S)
+ {
+ auto dstr = to!dstring(strip(isoExtString));
+
+ enforce(dstr.length == 8, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
+
+ auto hours = dstr[0 .. 2];
+ auto minutes = dstr[3 .. 5];
+ auto seconds = dstr[6 .. $];
+
+ enforce(dstr[2] == ':', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
+ enforce(dstr[5] == ':', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
+ enforce(!canFind!((dchar c){return !isdigit(c);})(hours), new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
+ enforce(!canFind!((dchar c){return !isdigit(c);})(minutes), new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
+ enforce(!canFind!((dchar c){return !isdigit(c);})(seconds), new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
+
+ return TimeOfDay(to!int(hours), to!int(minutes), to!int(seconds));
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString(""));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("0"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("00"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("000"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("0000"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("00000"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("13033"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("1277"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("12707"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("12070"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("12303a"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("1230a3"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("123a33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("12a033"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("1a0033"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("a20033"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("1200330"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("0120033"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("-120033"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("+120033"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("120033am"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("120033pm"));
+
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("0::"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString(":0:"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("::0"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("0:0:0"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("0:0:00"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("0:00:0"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("00:0:0"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("00:00:0"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("00:0:00"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("13:0:33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("12:7:7"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("12:7:07"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("12:07:0"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("12:30:3a"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("12:30:a3"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("12:3a:33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("12:a0:33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("1a:00:33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("a2:00:33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("12:003:30"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("120:03:30"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("012:00:33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("01:200:33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("-12:00:33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("+12:00:33"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("12:00:33am"));
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("12:00:33pm"));
+
+ assertThrown!DateTimeException(TimeOfDay.fromISOExtendedString("120033"));
+
+ assertPred!"=="(TimeOfDay.fromISOExtendedString("01:12:17"), TimeOfDay(1, 12, 17));
+ assertPred!"=="(TimeOfDay.fromISOExtendedString("00:14:12"), TimeOfDay(0, 14, 12));
+ assertPred!"=="(TimeOfDay.fromISOExtendedString("00:00:07"), TimeOfDay(0, 0, 7));
+ assertPred!"=="(TimeOfDay.fromISOExtendedString("01:12:17 "), TimeOfDay(1, 12, 17));
+ assertPred!"=="(TimeOfDay.fromISOExtendedString(" 01:12:17"), TimeOfDay(1, 12, 17));
+ assertPred!"=="(TimeOfDay.fromISOExtendedString(" 01:12:17 "), TimeOfDay(1, 12, 17));
+
+ //Verify Examples.
+ assert(TimeOfDay.fromISOExtendedString("00:00:00") == TimeOfDay(0, 0, 0));
+ assert(TimeOfDay.fromISOExtendedString("12:30:33") == TimeOfDay(12, 30, 33));
+ assert(TimeOfDay.fromISOExtendedString(" 12:30:33 ") == TimeOfDay(12, 30, 33));
+ }
+
+
+ //TODO Add function which takes a user-specified time format and produces a TimeOfDay
+
+ //TODO Add function which takes pretty much any time-string and produces a TimeOfDay
+ // Obviously, it will be less efficient, and it probably won't manage _every_
+ // possible date format, but a smart conversion function would be nice.
+
+
+ /++
+ Returns midnight.
+ +/
+ @property static TimeOfDay min() pure nothrow
+ {
+ return TimeOfDay.init;
+ }
+
+ unittest
+ {
+ assert(TimeOfDay.min.hour == 0);
+ assert(TimeOfDay.min.minute == 0);
+ assert(TimeOfDay.min.second == 0);
+ assert(TimeOfDay.min < TimeOfDay.max);
+ }
+
+
+ /++
+ Returns one second short of midnight.
+ +/
+ @property static TimeOfDay max() pure nothrow
+ {
+ auto tod = TimeOfDay.init;
+ tod._hour = maxHour;
+ tod._minute = maxMinute;
+ tod._second = maxSecond;
+
+ return tod;
+ }
+
+ unittest
+ {
+ assert(TimeOfDay.max.hour == 23);
+ assert(TimeOfDay.max.minute == 59);
+ assert(TimeOfDay.max.second == 59);
+ assert(TimeOfDay.max > TimeOfDay.min);
+ }
+
+
+private:
+
+ /++
+ Add seconds to the time of day. Negative values will subtract. If the
+ number of seconds overflows (or underflows), then the seconds will wrap,
+ increasing (or decreasing) the number of minutes accordingly. If the
+ number of minutes overflows (or underflows), then the minutes will wrap.
+ If the number of minutes overflows(or underflows), then the hour will
+ wrap. (e.g. adding 90 seconds to 23:59:00 would result in 00:00:30).
+
+ Params:
+ seconds = The number of seconds to add to this TimeOfDay.
+ +/
+ ref TimeOfDay addSeconds(long seconds) pure nothrow
+ {
+ long hnsecs = convert!("seconds", "hnsecs")(seconds);
+ hnsecs += convert!("hours", "hnsecs")(_hour);
+ hnsecs += convert!("minutes", "hnsecs")(_minute);
+ hnsecs += convert!("seconds", "hnsecs")(_second);
+
+ hnsecs %= convert!("days", "hnsecs")(1);
+
+ if(hnsecs < 0)
+ hnsecs += convert!("days", "hnsecs")(1);
+
+ immutable newHours = splitUnitsFromHNSecs!"hours"(hnsecs);
+ immutable newMinutes = splitUnitsFromHNSecs!"minutes"(hnsecs);
+ immutable newSeconds = splitUnitsFromHNSecs!"seconds"(hnsecs);
+
+ _hour = cast(ubyte)newHours;
+ _minute = cast(ubyte)newMinutes;
+ _second = cast(ubyte)newSeconds;
+
+ return this;
+ }
+
+ unittest
+ {
+ static void testTOD(TimeOfDay orig, int seconds, in TimeOfDay expected, size_t line = __LINE__)
+ {
+ orig.addSeconds(seconds);
+ assertPred!"=="(orig, expected, "", __FILE__, line);
+ }
+
+ testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33));
+ testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 30, 34));
+ testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 30, 35));
+ testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 30, 36));
+ testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 30, 37));
+ testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 30, 38));
+ testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 30, 43));
+ testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 30, 48));
+ testTOD(TimeOfDay(12, 30, 33), 26, TimeOfDay(12, 30, 59));
+ testTOD(TimeOfDay(12, 30, 33), 27, TimeOfDay(12, 31, 0));
+ testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 31, 3));
+ testTOD(TimeOfDay(12, 30, 33), 59, TimeOfDay(12, 31, 32));
+ testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 31, 33));
+ testTOD(TimeOfDay(12, 30, 33), 61, TimeOfDay(12, 31, 34));
+
+ testTOD(TimeOfDay(12, 30, 33), 1766, TimeOfDay(12, 59, 59));
+ testTOD(TimeOfDay(12, 30, 33), 1767, TimeOfDay(13, 0, 0));
+ testTOD(TimeOfDay(12, 30, 33), 1768, TimeOfDay(13, 0, 1));
+ testTOD(TimeOfDay(12, 30, 33), 2007, TimeOfDay(13, 4, 0));
+ testTOD(TimeOfDay(12, 30, 33), 3599, TimeOfDay(13, 30, 32));
+ testTOD(TimeOfDay(12, 30, 33), 3600, TimeOfDay(13, 30, 33));
+ testTOD(TimeOfDay(12, 30, 33), 3601, TimeOfDay(13, 30, 34));
+ testTOD(TimeOfDay(12, 30, 33), 7200, TimeOfDay(14, 30, 33));
+
+ testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 30, 32));
+ testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 30, 31));
+ testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 30, 30));
+ testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 30, 29));
+ testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 30, 28));
+ testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 30, 23));
+ testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 30, 18));
+ testTOD(TimeOfDay(12, 30, 33), -33, TimeOfDay(12, 30, 0));
+ testTOD(TimeOfDay(12, 30, 33), -34, TimeOfDay(12, 29, 59));
+ testTOD(TimeOfDay(12, 30, 33), -35, TimeOfDay(12, 29, 58));
+ testTOD(TimeOfDay(12, 30, 33), -59, TimeOfDay(12, 29, 34));
+ testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 29, 33));
+ testTOD(TimeOfDay(12, 30, 33), -61, TimeOfDay(12, 29, 32));
+
+ testTOD(TimeOfDay(12, 30, 33), -1833, TimeOfDay(12, 0, 0));
+ testTOD(TimeOfDay(12, 30, 33), -1834, TimeOfDay(11, 59, 59));
+ testTOD(TimeOfDay(12, 30, 33), -3600, TimeOfDay(11, 30, 33));
+ testTOD(TimeOfDay(12, 30, 33), -3601, TimeOfDay(11, 30, 32));
+ testTOD(TimeOfDay(12, 30, 33), -5134, TimeOfDay(11, 4, 59));
+ testTOD(TimeOfDay(12, 30, 33), -7200, TimeOfDay(10, 30, 33));
+
+ testTOD(TimeOfDay(12, 30, 0), 1, TimeOfDay(12, 30, 1));
+ testTOD(TimeOfDay(12, 30, 0), 0, TimeOfDay(12, 30, 0));
+ testTOD(TimeOfDay(12, 30, 0), -1, TimeOfDay(12, 29, 59));
+
+ testTOD(TimeOfDay(12, 0, 0), 1, TimeOfDay(12, 0, 1));
+ testTOD(TimeOfDay(12, 0, 0), 0, TimeOfDay(12, 0, 0));
+ testTOD(TimeOfDay(12, 0, 0), -1, TimeOfDay(11, 59, 59));
+
+ testTOD(TimeOfDay(0, 0, 0), 1, TimeOfDay(0, 0, 1));
+ testTOD(TimeOfDay(0, 0, 0), 0, TimeOfDay(0, 0, 0));
+ testTOD(TimeOfDay(0, 0, 0), -1, TimeOfDay(23, 59, 59));
+
+ testTOD(TimeOfDay(23, 59, 59), 1, TimeOfDay(0, 0, 0));
+ testTOD(TimeOfDay(23, 59, 59), 0, TimeOfDay(23, 59, 59));
+ testTOD(TimeOfDay(23, 59, 59), -1, TimeOfDay(23, 59, 58));
+
+ const ctod = TimeOfDay(0, 0, 0);
+ immutable itod = TimeOfDay(0, 0, 0);
+ static assert(!__traits(compiles, ctod.addSeconds(7)));
+ static assert(!__traits(compiles, itod.addSeconds(7)));
+ }
+
+
+ /++
+ Whether the given values form a valid TimeOfDay
+ +/
+ static bool _valid(int hour, int minute, int second) pure nothrow
+ {
+ return valid!"hours"(hour) && valid!"minutes"(minute) && valid!"seconds"(second);
+ }
+
+
+ pure invariant()
+ {
+ assert(_valid(_hour, _minute, _second),
+ "Invariant Failure: hour [" ~
+ numToString(_hour) ~
+ "] minute [" ~
+ numToString(_minute) ~
+ "] second [" ~
+ numToString(_second) ~
+ "]");
+ }
+
+ ubyte _hour;
+ ubyte _minute;
+ ubyte _second;
+
+ enum ubyte maxHour = 24 - 1;
+ enum ubyte maxMinute = 60 - 1;
+ enum ubyte maxSecond = 60 - 1;
+}
+
+
+/++
+ Combines Date and TimeOfDay structs to give you an object which holds both
+ the date and the time. It is optimized for calendar operations and has no
+ concept of time zone. If you want an object which is optimized for time
+ operations based on the system time, then use SysTime. SysTime has a concept
+ of time zone and has much higher precision (hnsecs). DateTime is intended
+ primarily for calendar-based uses rather than precise time operations.
+ +/
+struct DateTime
+{
+public:
+
+ /++
+ Params:
+ date = The date portion of DateTime.
+ tod = The time portion of DateTime.
+ +/
+ this(in Date date, in TimeOfDay tod = TimeOfDay.init) pure nothrow
+ {
+ _date = date;
+ _tod = tod;
+ }
+
+ unittest
+ {
+ {
+ auto dt = DateTime.init;
+ assertPred!"=="(dt._date, Date.init);
+ assertPred!"=="(dt._tod, TimeOfDay.init);
+ }
+
+ {
+ auto dt = DateTime(Date(1999, 7 ,6));
+ assertPred!"=="(dt._date, Date(1999, 7, 6));
+ assertPred!"=="(dt._tod, TimeOfDay.init);
+ }
+
+ {
+ auto dt = DateTime(Date(1999, 7 ,6), TimeOfDay(12, 30, 33));
+ assertPred!"=="(dt._date, Date(1999, 7, 6));
+ assertPred!"=="(dt._tod, TimeOfDay(12, 30, 33));
+ }
+ }
+
+
+ /++
+ Params:
+ year = The year portion of the date.
+ month = The month portion of the date.
+ day = The day portion of the date.
+ hour = The hour portion of the time;
+ minute = The minute portion of the time;
+ second = The second portion of the time;
+ +/
+ this(int year, int month, int day,
+ int hour = 0, int minute = 0, int second = 0) pure
+ {
+ _date = Date(year, month, day);
+ _tod = TimeOfDay(hour, minute, second);
+ }
+
+ unittest
+ {
+ {
+ auto dt = DateTime(1999, 7 ,6);
+ assertPred!"=="(dt._date, Date(1999, 7, 6));
+ assertPred!"=="(dt._tod, TimeOfDay.init);
+ }
+
+ {
+ auto dt = DateTime(1999, 7 ,6, 12, 30, 33);
+ assertPred!"=="(dt._date, Date(1999, 7, 6));
+ assertPred!"=="(dt._tod, TimeOfDay(12, 30, 33));
+ }
+ }
+
+
+ /++
+ Compares this DateTime with the given DateTime.
+
+ Returns:
+ $(TABLE
+ $(TR $(TD this < rhs) $(TD < 0))
+ $(TR $(TD this == rhs) $(TD 0))
+ $(TR $(TD this > rhs) $(TD > 0))
+ )
+ +/
+ int opCmp(in DateTime rhs) const pure nothrow
+ {
+ immutable dateResult = _date.opCmp(rhs._date);
+
+ if(dateResult != 0)
+ return dateResult;
+
+ return _tod.opCmp(rhs._tod);
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!("opCmp", "==")(DateTime(Date.init, TimeOfDay.init), DateTime.init);
+
+ assertPred!("opCmp", "==")(DateTime(Date(1999, 1, 1)), DateTime(Date(1999, 1, 1)));
+ assertPred!("opCmp", "==")(DateTime(Date(1, 7, 1)), DateTime(Date(1, 7, 1)));
+ assertPred!("opCmp", "==")(DateTime(Date(1, 1, 6)), DateTime(Date(1, 1, 6)));
+
+ assertPred!("opCmp", "==")(DateTime(Date(1999, 7, 1)), DateTime(Date(1999, 7, 1)));
+ assertPred!("opCmp", "==")(DateTime(Date(1999, 7, 6)), DateTime(Date(1999, 7, 6)));
+
+ assertPred!("opCmp", "==")(DateTime(Date(1, 7, 6)), DateTime(Date(1, 7, 6)));
+
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 6)), DateTime(Date(2000, 7, 6)));
+ assertPred!("opCmp", ">")(DateTime(Date(2000, 7, 6)), DateTime(Date(1999, 7, 6)));
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 6)), DateTime(Date(1999, 8, 6)));
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 8, 6)), DateTime(Date(1999, 7, 6)));
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 6)), DateTime(Date(1999, 7, 7)));
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 7, 7)), DateTime(Date(1999, 7, 6)));
+
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 8, 7)), DateTime(Date(2000, 7, 6)));
+ assertPred!("opCmp", ">")(DateTime(Date(2000, 8, 6)), DateTime(Date(1999, 7, 7)));
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 7)), DateTime(Date(2000, 7, 6)));
+ assertPred!("opCmp", ">")(DateTime(Date(2000, 7, 6)), DateTime(Date(1999, 7, 7)));
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 7)), DateTime(Date(1999, 8, 6)));
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 8, 6)), DateTime(Date(1999, 7, 7)));
+
+
+ assertPred!("opCmp", "==")(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)));
+ assertPred!("opCmp", "==")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)));
+ assertPred!("opCmp", "==")(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 0)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 0)));
+ assertPred!("opCmp", "==")(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)));
+
+ assertPred!("opCmp", "==")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)));
+ assertPred!("opCmp", "==")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+
+ assertPred!("opCmp", "==")(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)));
+ assertPred!("opCmp", "==")(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)));
+
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)));
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)));
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)));
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)));
+
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)));
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)));
+
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)),
+ DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)));
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)),
+ DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)));
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)),
+ DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)));
+
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)),
+ DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)));
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)),
+ DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)));
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)),
+ DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)));
+
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)),
+ DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)));
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)),
+ DateTime(Date(1999, 7, 7), TimeOfDay(12, 31, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", "<")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)),
+ DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)));
+
+ //Test B.C.
+ assertPred!("opCmp", "==")(DateTime(Date(-1, 1, 1), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1, 1, 1), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", "==")(DateTime(Date(-1, 7, 1), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1, 7, 1), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", "==")(DateTime(Date(-1, 1, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1, 1, 6), TimeOfDay(12, 30, 33)));
+
+ assertPred!("opCmp", "==")(DateTime(Date(-1999, 7, 1), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1999, 7, 1), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", "==")(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+
+ assertPred!("opCmp", "==")(DateTime(Date(-1, 7, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1, 7, 6), TimeOfDay(12, 30, 33)));
+
+ assertPred!("opCmp", "<")(DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", "<")(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", "<")(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+
+ assertPred!("opCmp", "<")(DateTime(Date(-2000, 8, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", "<")(DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", "<")(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)));
+
+ //Test Both
+ assertPred!("opCmp", "<")(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+
+ assertPred!("opCmp", "<")(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)));
+
+ assertPred!("opCmp", "<")(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)));
+
+ assertPred!("opCmp", "<")(DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33)),
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33)));
+
+ assertPred!("opCmp", "<")(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)),
+ DateTime(Date(1999, 6, 6), TimeOfDay(12, 30, 33)));
+ assertPred!("opCmp", ">")(DateTime(Date(1999, 6, 8), TimeOfDay(12, 30, 33)),
+ DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+
+ auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 30));
+ const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 30));
+ immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 30));
+ static assert(__traits(compiles, dt.opCmp(dt)));
+ static assert(__traits(compiles, dt.opCmp(cdt)));
+ static assert(__traits(compiles, dt.opCmp(idt)));
+ static assert(__traits(compiles, cdt.opCmp(dt)));
+ static assert(__traits(compiles, cdt.opCmp(cdt)));
+ static assert(__traits(compiles, cdt.opCmp(idt)));
+ static assert(__traits(compiles, idt.opCmp(dt)));
+ static assert(__traits(compiles, idt.opCmp(cdt)));
+ static assert(__traits(compiles, idt.opCmp(idt)));
+ }
+
+
+ /++
+ The date portion of DateTime.
+ +/
+ @property Date date() const pure nothrow
+ {
+ return _date;
+ }
+
+ unittest
+ {
+ {
+ auto dt = DateTime.init;
+ assertPred!"=="(dt.date, Date.init);
+ }
+
+ {
+ auto dt = DateTime(Date(1999, 7, 6));
+ assertPred!"=="(dt.date, Date(1999, 7, 6));
+ }
+
+ const cdt = DateTime(1999, 7, 6);
+ immutable idt = DateTime(1999, 7, 6);
+ static assert(__traits(compiles, cdt.date == Date(2010, 1, 1)));
+ static assert(__traits(compiles, idt.date == Date(2010, 1, 1)));
+ }
+
+
+ /++
+ The date portion of DateTime.
+
+ Params:
+ date = The Date to set this DateTime's date portion to.
+ +/
+ @property void date(in Date date) pure nothrow
+ {
+ _date = date;
+ }
+
+ unittest
+ {
+ auto dt = DateTime.init;
+ dt.date = Date(1999, 7, 6);
+ assertPred!"=="(dt._date, Date(1999, 7, 6));
+ assertPred!"=="(dt._tod, TimeOfDay.init);
+
+ const cdt = DateTime(1999, 7, 6);
+ immutable idt = DateTime(1999, 7, 6);
+ static assert(!__traits(compiles, cdt.date = Date(2010, 1, 1)));
+ static assert(!__traits(compiles, idt.date = Date(2010, 1, 1)));
+ }
+
+
+ /++
+ The time portion of DateTime.
+ +/
+ @property TimeOfDay timeOfDay() const pure nothrow
+ {
+ return _tod;
+ }
+
+ unittest
+ {
+ {
+ auto dt = DateTime.init;
+ assertPred!"=="(dt.timeOfDay, TimeOfDay.init);
+ }
+
+ {
+ auto dt = DateTime(Date.init, TimeOfDay(12, 30, 33));
+ assertPred!"=="(dt.timeOfDay, TimeOfDay(12, 30, 33));
+ }
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(__traits(compiles, cdt.timeOfDay == TimeOfDay(12, 30, 33)));
+ static assert(__traits(compiles, idt.timeOfDay == TimeOfDay(12, 30, 33)));
+ }
+
+
+ /++
+ The time portion of DateTime.
+
+ Params:
+ tod = The TimeOfDay to set this DateTime's time portion to.
+ +/
+ @property void timeOfDay(in TimeOfDay tod) pure nothrow
+ {
+ _tod = tod;
+ }
+
+ unittest
+ {
+ auto dt = DateTime.init;
+ dt.timeOfDay = TimeOfDay(12, 30, 33);
+ assertPred!"=="(dt._date, date.init);
+ assertPred!"=="(dt._tod, TimeOfDay(12, 30, 33));
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(!__traits(compiles, cdt.timeOfDay = TimeOfDay(12, 30, 33)));
+ static assert(!__traits(compiles, idt.timeOfDay = TimeOfDay(12, 30, 33)));
+ }
+
+
+ /++
+ Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
+ are B.C.
+ +/
+ @property short year() const pure nothrow
+ {
+ return _date.year;
+ }
+
+ unittest
+ {
+ assertPred!"=="(Date.init.year, 1);
+ assertPred!"=="(Date(1999, 7, 6).year, 1999);
+ assertPred!"=="(Date(-1999, 7, 6).year, -1999);
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(__traits(compiles, idt.year));
+ static assert(__traits(compiles, idt.year));
+ }
+
+
+ /++
+ Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
+ are B.C.
+
+ Params:
+ year = The year to set this DateTime's year to.
+
+ Throws:
+ DateTimeException if the new year is not a leap year and if the
+ resulting date would be on February 29th.
+
+ Examples:
+--------------------
+assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).year == 1999);
+assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).year == 2010);
+assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).year == -7);
+--------------------
+ +/
+ @property void year(int year) pure
+ {
+ _date.year = year;
+ }
+
+ unittest
+ {
+ static void testDT(DateTime dt, int year, in DateTime expected, size_t line = __LINE__)
+ {
+ dt.year = year;
+ assertPred!"=="(dt, expected, "", __FILE__, line);
+ }
+
+ testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), 1999, DateTime(Date(1999, 1, 1), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), 0, DateTime(Date(0, 1, 1), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), -1999, DateTime(Date(-1999, 1, 1), TimeOfDay(12, 30, 33)));
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(!__traits(compiles, cdt.year = 7));
+ static assert(!__traits(compiles, idt.year = 7));
+
+ //Verify Examples.
+ assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).year == 1999);
+ assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).year == 2010);
+ assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).year == -7);
+ }
+
+
+ /++
+ Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
+
+ Throws:
+ DateTimeException if $(D isAD) is true.
+
+ Examples:
+--------------------
+assert(DateTime(Date(0, 1, 1), TimeOfDay(12, 30, 33)).yearBC == 1);
+assert(DateTime(Date(-1, 1, 1), TimeOfDay(10, 7, 2)).yearBC == 2);
+assert(DateTime(Date(-100, 1, 1), TimeOfDay(4, 59, 0)).yearBC == 101);
+--------------------
+ +/
+ @property short yearBC() const pure
+ {
+ return _date.yearBC;
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException((in DateTime dt){dt.yearBC;}(DateTime(Date(1, 1, 1))));
+
+ auto dt = DateTime(1999, 7, 6, 12, 30, 33);
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(__traits(compiles, dt.yearBC = 12));
+ static assert(!__traits(compiles, cdt.yearBC = 12));
+ static assert(!__traits(compiles, idt.yearBC = 12));
+
+ //Verify Examples.
+ assert(DateTime(Date(0, 1, 1), TimeOfDay(12, 30, 33)).yearBC == 1);
+ assert(DateTime(Date(-1, 1, 1), TimeOfDay(10, 7, 2)).yearBC == 2);
+ assert(DateTime(Date(-100, 1, 1), TimeOfDay(4, 59, 0)).yearBC == 101);
+ }
+
+
+ /++
+ Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
+
+ Params:
+ year = The year B.C. to set this DateTime's year to.
+
+ Throws:
+ DateTimeException if a non-positive value is given.
+
+ Examples:
+--------------------
+auto dt = DateTime(Date(2010, 1, 1), TimeOfDay(7, 30, 0));
+dt.yearBC = 1;
+assert(dt == DateTime(Date(0, 1, 1), TimeOfDay(7, 30, 0)));
+
+dt.yearBC = 10;
+assert(dt == DateTime(Date(-9, 1, 1), TimeOfDay(7, 30, 0)));
+--------------------
+ +/
+ @property void yearBC(int year) pure
+ {
+ _date.yearBC = year;
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException((DateTime dt){dt.yearBC = -1;}(DateTime(Date(1, 1, 1))));
+
+ {
+ auto dt = DateTime(1999, 7, 6, 12, 30, 33);
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(__traits(compiles, dt.yearBC = 12));
+ static assert(!__traits(compiles, cdt.yearBC = 12));
+ static assert(!__traits(compiles, idt.yearBC = 12));
+ }
+
+ //Verify Examples.
+ {
+ auto dt = DateTime(Date(2010, 1, 1), TimeOfDay(7, 30, 0));
+ dt.yearBC = 1;
+ assert(dt == DateTime(Date(0, 1, 1), TimeOfDay(7, 30, 0)));
+
+ dt.yearBC = 10;
+ assert(dt == DateTime(Date(-9, 1, 1), TimeOfDay(7, 30, 0)));
+ }
+ }
+
+
+ /++
+ Month of a Gregorian Year.
+
+ Examples:
+--------------------
+assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).month == 7);
+assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).month == 10);
+assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).month == 4);
+--------------------
+ +/
+ @property Month month() const pure nothrow
+ {
+ return _date.month;
+ }
+
+ unittest
+ {
+ assertPred!"=="(DateTime.init.month, 1);
+ assertPred!"=="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).month, 7);
+ assertPred!"=="(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).month, 7);
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(__traits(compiles, cdt.month));
+ static assert(__traits(compiles, idt.month));
+
+ //Verify Examples.
+ assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).month == 7);
+ assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).month == 10);
+ assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).month == 4);
+ }
+
+
+ /++
+ Month of a Gregorian Year.
+
+ Params:
+ month = The month to set this DateTime's month to.
+
+ Throws:
+ DateTimeException if the given month is not a valid month.
+ +/
+ @property void month(Month month) pure
+ {
+ _date.month = month;
+ }
+
+ unittest
+ {
+ static void testDT(DateTime dt, Month month, in DateTime expected = DateTime.init, size_t line = __LINE__)
+ {
+ dt.month = month;
+ assert(expected != DateTime.init);
+ assertPred!"=="(dt, expected, "", __FILE__, line);
+ }
+
+ assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), cast(Month)0));
+ assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), cast(Month)13));
+
+ testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), cast(Month)7, DateTime(Date(1, 7, 1), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(-1, 1, 1), TimeOfDay(12, 30, 33)), cast(Month)7, DateTime(Date(-1, 7, 1), TimeOfDay(12, 30, 33)));
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(!__traits(compiles, cdt.month = 12));
+ static assert(!__traits(compiles, idt.month = 12));
+ }
+
+
+ /++
+ Day of a Gregorian Month.
+
+ Examples:
+--------------------
+assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).day == 6);
+assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).day == 4);
+assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).day == 5);
+--------------------
+ +/
+ @property ubyte day() const pure nothrow
+ {
+ return _date.day;
+ }
+
+ unittest
+ {
+ assertPred!"=="(DateTime.init.day, 1);
+ assertPred!"=="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).day, 6);
+ assertPred!"=="(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).day, 6);
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(__traits(compiles, cdt.day));
+ static assert(__traits(compiles, idt.day));
+
+ //Verify Examples.
+ assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).day == 6);
+ assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).day == 4);
+ assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).day == 5);
+ }
+
+
+ /++
+ Day of a Gregorian Month.
+
+ Params:
+ day = The day of the month to set this DateTime's day to.
+
+ Throws:
+ DateTimeException if the given day is not a valid day of the current month.
+ +/
+ @property void day(int day) pure
+ {
+ _date.day = day;
+ }
+
+ unittest
+ {
+ static void testDT(DateTime dt, int day)
+ {
+ dt.day = day;
+ }
+
+ //Test A.D.
+ assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1)), 0));
+ assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1)), 32));
+ assertThrown!DateTimeException(testDT(DateTime(Date(1, 2, 1)), 29));
+ assertThrown!DateTimeException(testDT(DateTime(Date(4, 2, 1)), 30));
+ assertThrown!DateTimeException(testDT(DateTime(Date(1, 3, 1)), 32));
+ assertThrown!DateTimeException(testDT(DateTime(Date(1, 4, 1)), 31));
+ assertThrown!DateTimeException(testDT(DateTime(Date(1, 5, 1)), 32));
+ assertThrown!DateTimeException(testDT(DateTime(Date(1, 6, 1)), 31));
+ assertThrown!DateTimeException(testDT(DateTime(Date(1, 7, 1)), 32));
+ assertThrown!DateTimeException(testDT(DateTime(Date(1, 8, 1)), 32));
+ assertThrown!DateTimeException(testDT(DateTime(Date(1, 9, 1)), 31));
+ assertThrown!DateTimeException(testDT(DateTime(Date(1, 10, 1)), 32));
+ assertThrown!DateTimeException(testDT(DateTime(Date(1, 11, 1)), 31));
+ assertThrown!DateTimeException(testDT(DateTime(Date(1, 12, 1)), 32));
+
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1)), 31));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 2, 1)), 28));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(4, 2, 1)), 29));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 3, 1)), 31));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 4, 1)), 30));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 5, 1)), 31));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 6, 1)), 30));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 7, 1)), 31));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 8, 1)), 31));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 9, 1)), 30));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 10, 1)), 31));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 11, 1)), 30));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 12, 1)), 31));
+
+ {
+ auto dt = DateTime(Date(1, 1, 1), TimeOfDay(7, 12, 22));
+ dt.day = 6;
+ assertPred!"=="(dt, DateTime(Date(1, 1, 6), TimeOfDay(7, 12, 22)));
+ }
+
+ //Test B.C.
+ assertThrown!DateTimeException(testDT(DateTime(Date(-1, 1, 1)), 0));
+ assertThrown!DateTimeException(testDT(DateTime(Date(-1, 1, 1)), 32));
+ assertThrown!DateTimeException(testDT(DateTime(Date(-1, 2, 1)), 29));
+ assertThrown!DateTimeException(testDT(DateTime(Date(0, 2, 1)), 30));
+ assertThrown!DateTimeException(testDT(DateTime(Date(-1, 3, 1)), 32));
+ assertThrown!DateTimeException(testDT(DateTime(Date(-1, 4, 1)), 31));
+ assertThrown!DateTimeException(testDT(DateTime(Date(-1, 5, 1)), 32));
+ assertThrown!DateTimeException(testDT(DateTime(Date(-1, 6, 1)), 31));
+ assertThrown!DateTimeException(testDT(DateTime(Date(-1, 7, 1)), 32));
+ assertThrown!DateTimeException(testDT(DateTime(Date(-1, 8, 1)), 32));
+ assertThrown!DateTimeException(testDT(DateTime(Date(-1, 9, 1)), 31));
+ assertThrown!DateTimeException(testDT(DateTime(Date(-1, 10, 1)), 32));
+ assertThrown!DateTimeException(testDT(DateTime(Date(-1, 11, 1)), 31));
+ assertThrown!DateTimeException(testDT(DateTime(Date(-1, 12, 1)), 32));
+
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 1, 1)), 31));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 2, 1)), 28));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(0, 2, 1)), 29));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 3, 1)), 31));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 4, 1)), 30));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 5, 1)), 31));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 6, 1)), 30));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 7, 1)), 31));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 8, 1)), 31));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 9, 1)), 30));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 10, 1)), 31));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 11, 1)), 30));
+ assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 12, 1)), 31));
+
+ auto dt = DateTime(Date(-1, 1, 1), TimeOfDay(7, 12, 22));
+ dt.day = 6;
+ assertPred!"=="(dt, DateTime(Date(-1, 1, 6), TimeOfDay(7, 12, 22)));
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(!__traits(compiles, cdt.day = 27));
+ static assert(!__traits(compiles, idt.day = 27));
+ }
+
+
+ /++
+ Hours passed midnight.
+ +/
+ @property ubyte hour() const pure nothrow
+ {
+ return _tod.hour;
+ }
+
+ unittest
+ {
+ assertPred!"=="(DateTime.init.hour, 0);
+ assertPred!"=="(DateTime(Date.init, TimeOfDay(12, 0, 0)).hour, 12);
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(__traits(compiles, cdt.hour));
+ static assert(__traits(compiles, idt.hour));
+ }
+
+
+ /++
+ Hours passed midnight.
+
+ Params:
+ hour = The hour of the day to set this DateTime's hour to.
+
+ Throws:
+ DateTimeException if the given hour would result in an invalid
+ DateTime.
+ +/
+ @property void hour(int hour) pure
+ {
+ _tod.hour = hour;
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException((){DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)).hour = 24;}());
+
+ auto dt = DateTime.init;
+ dt.hour = 12;
+ assertPred!"=="(dt, DateTime(1, 1, 1, 12, 0, 0));
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(!__traits(compiles, cdt.hour = 27));
+ static assert(!__traits(compiles, idt.hour = 27));
+ }
+
+
+ /++
+ Minutes passed the hour.
+ +/
+ @property ubyte minute() const pure nothrow
+ {
+ return _tod.minute;
+ }
+
+ unittest
+ {
+ assertPred!"=="(DateTime.init.minute, 0);
+ assertPred!"=="(DateTime(1, 1, 1, 0, 30, 0).minute, 30);
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(__traits(compiles, cdt.minute));
+ static assert(__traits(compiles, idt.minute));
+ }
+
+
+ /++
+ Minutes passed the hour.
+
+ Params:
+ minute = The minute to set this DateTime's minute to.
+
+ Throws:
+ DateTimeException if the given minute would result in an invalid
+ DateTime.
+ +/
+ @property void minute(int minute) pure
+ {
+ _tod.minute = minute;
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException((){DateTime.init.minute = 60;}());
+
+ auto dt = DateTime.init;
+ dt.minute = 30;
+ assertPred!"=="(dt, DateTime(1, 1, 1, 0, 30, 0));
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(!__traits(compiles, cdt.minute = 27));
+ static assert(!__traits(compiles, idt.minute = 27));
+ }
+
+
+ /++
+ Seconds passed the minute.
+ +/
+ @property ubyte second() const pure nothrow
+ {
+ return _tod.second;
+ }
+
+ unittest
+ {
+ assertPred!"=="(DateTime.init.second, 0);
+ assertPred!"=="(DateTime(1, 1, 1, 0, 0, 33).second, 33);
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(__traits(compiles, cdt.second));
+ static assert(__traits(compiles, idt.second));
+ }
+
+
+ /++
+ Seconds passed the minute.
+
+ Params
+ second = The second to set this DateTime's second to.
+
+ Throws:
+ DateTimeException if the given seconds would result in an invalid
+ DateTime.
+ +/
+ @property void second(int second) pure
+ {
+ _tod.second = second;
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException((){DateTime.init.second = 60;}());
+
+ auto dt = DateTime.init;
+ dt.second = 33;
+ assertPred!"=="(dt, DateTime(1, 1, 1, 0, 0, 33));
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(!__traits(compiles, cdt.second = 27));
+ static assert(!__traits(compiles, idt.second = 27));
+ }
+
+
+ /++
+ Adds the given number of years or months to this DateTime. A negative
+ number will subtract.
+
+ Note that if day overflow is allowed, and the date with the adjusted
+ year/month overflows the number of days in the new month, then the month
+ will be incremented by one, and the days set to the number of days overflowed.
+ (e.g. if the day were 31 and the new month were June, then the month would
+ be incremented to July, and the new day would be 1). If day overflow is
+ not allowed, then the day will be set to the last valid day in the month
+ (e.g. June 31st would become June 30th).
+
+ Params:
+ units = The type of units to add ("years" or "months").
+ value = The number of months or years to add to this DateTime.
+ allowOverflow = Whether the days should be allowed to overflow, causing
+ the month to increment.
+
+ Examples:
+--------------------
+auto dt1 = DateTime(Date(2010, 1, 1), TimeOfDay(12, 30, 33));
+dt1.add!"months"(11);
+assert(dt1 == DateTime(Date(2010, 12, 1), TimeOfDay(12, 30, 33)));
+
+auto dt2 = DateTime(Date(2010, 1, 1), TimeOfDay(12, 30, 33));
+dt2.add!"months"(-11);
+assert(dt2 == DateTime(Date(2009, 2, 1), TimeOfDay(12, 30, 33)));
+
+auto dt3 = DateTime(Date(2000, 2, 29), TimeOfDay(12, 30, 33));
+dt3.add!"years"(1);
+assert(dt3 == DateTime(Date(2001, 3, 1), TimeOfDay(12, 30, 33)));
+
+auto dt4 = DateTime(Date(2000, 2, 29), TimeOfDay(12, 30, 33));
+dt4.add!"years"(1, AllowDayOverflow.no);
+assert(dt4 == DateTime(Date(2001, 2, 28), TimeOfDay(12, 30, 33)));
+--------------------
+ +/
+ /+ref DateTime+/ void add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) pure nothrow
+ if(units == "years" ||
+ units == "months")
+ {
+ _date.add!units(value, allowOverflow);
+ }
+
+ unittest
+ {
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(!__traits(compiles, cdt.add!"years"(4)));
+ static assert(!__traits(compiles, idt.add!"years"(4)));
+ static assert(!__traits(compiles, cdt.add!"months"(4)));
+ static assert(!__traits(compiles, idt.add!"months"(4)));
+
+ //Verify Examples.
+ auto dt1 = DateTime(Date(2010, 1, 1), TimeOfDay(12, 30, 33));
+ dt1.add!"months"(11);
+ assert(dt1 == DateTime(Date(2010, 12, 1), TimeOfDay(12, 30, 33)));
+
+ auto dt2 = DateTime(Date(2010, 1, 1), TimeOfDay(12, 30, 33));
+ dt2.add!"months"(-11);
+ assert(dt2 == DateTime(Date(2009, 2, 1), TimeOfDay(12, 30, 33)));
+
+ auto dt3 = DateTime(Date(2000, 2, 29), TimeOfDay(12, 30, 33));
+ dt3.add!"years"(1);
+ assert(dt3 == DateTime(Date(2001, 3, 1), TimeOfDay(12, 30, 33)));
+
+ auto dt4 = DateTime(Date(2000, 2, 29), TimeOfDay(12, 30, 33));
+ dt4.add!"years"(1, AllowDayOverflow.no);
+ assert(dt4 == DateTime(Date(2001, 2, 28), TimeOfDay(12, 30, 33)));
+ }
+
+
+ /++
+ Adds the given number of years or months this DateTime. A negative
+ number will subtract.
+
+ The difference between rolling and adding is that rolling does not
+ affect larger units. So, if you roll the DateTime 12 months, you get
+ the exact same Date. However, the days can still be affected due to
+ the differing number of days in each month.
+
+ Params:
+ units = The units to roll.
+ value = The number of units to add to this DateTime.
+ allowOverflow = Whether the days should be allowed to overflow, causing the month to increment.
+
+ Examples:
+--------------------
+auto dt1 = DateTime(Date(2010, 1, 1), TimeOfDay(12, 33, 33));
+dt1.roll!"years"(1);
+assert(dt1 == DateTime(Date(2011, 1, 1), TimeOfDay(12, 33, 33)));
+
+auto dt2 = DateTime(Date(2010, 1, 1), TimeOfDay(12, 33, 33));
+dt2.roll!"months"(-12);
+assert(dt2 == DateTime(Date(2010, 1, 1), TimeOfDay(12, 33, 33)));
+
+auto dt3 = DateTime(Date(1999, 1, 29), TimeOfDay(12, 33, 33));
+dt3.roll!"months"(1);
+assert(dt3 == DateTime(Date(1999, 3, 1), TimeOfDay(12, 33, 33)));
+
+auto dt4 = DateTime(Date(1999, 1, 29), TimeOfDay(12, 33, 33));
+dt4.roll!"months"(1, AllowDayOverflow.no);
+assert(dt4 == DateTime(Date(1999, 2, 28), TimeOfDay(12, 33, 33)));
+--------------------
+ +/
+ /+ref DateTime+/ void roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) pure nothrow
+ if(units == "years" ||
+ units == "months")
+ {
+ _date.roll!units(value, allowOverflow);
+ }
+
+ unittest
+ {
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(!__traits(compiles, cdt.roll!"years"(4)));
+ static assert(!__traits(compiles, idt.roll!"years"(4)));
+ static assert(!__traits(compiles, cdt.roll!"months"(4)));
+ static assert(!__traits(compiles, idt.roll!"months"(4)));
+ static assert(!__traits(compiles, cdt.roll!"days"(4)));
+ static assert(!__traits(compiles, idt.roll!"days"(4)));
+
+ //Verify Examples
+ auto dt1 = DateTime(Date(2010, 1, 1), TimeOfDay(12, 33, 33));
+ dt1.roll!"years"(1);
+ assert(dt1 == DateTime(Date(2011, 1, 1), TimeOfDay(12, 33, 33)));
+
+ auto dt2 = DateTime(Date(2010, 1, 1), TimeOfDay(12, 33, 33));
+ dt2.roll!"months"(-12);
+ assert(dt2 == DateTime(Date(2010, 1, 1), TimeOfDay(12, 33, 33)));
+
+ auto dt3 = DateTime(Date(1999, 1, 29), TimeOfDay(12, 33, 33));
+ dt3.roll!"months"(1);
+ assert(dt3 == DateTime(Date(1999, 3, 1), TimeOfDay(12, 33, 33)));
+
+ auto dt4 = DateTime(Date(1999, 1, 29), TimeOfDay(12, 33, 33));
+ dt4.roll!"months"(1, AllowDayOverflow.no);
+ assert(dt4 == DateTime(Date(1999, 2, 28), TimeOfDay(12, 33, 33)));
+ }
+
+
+ /++
+ Adds the given number of days this DateTime. A negative number will subtract.
+
+ The difference between rolling and adding is that rolling does not affect
+ larger units. So, if you roll the Date one year's worth of days, then you
+ get the exact same Date.
+
+ Note that there is no $(D add!"days"()) because you can add days to a DateTime
+ by adding a duration to it.
+
+ Params:
+ days = The number of days to add to this DateTime.
+
+ Examples:
+--------------------
+auto dt = DateTime(Date(2010, 1, 1), TimeOfDay(11, 23, 12));
+dt.roll!"days"(1);
+assert(dt == DateTime(Date(2010, 1, 2), TimeOfDay(11, 23, 12)));
+dt.roll!"days"(365);
+assert(dt == DateTime(Date(2010, 1, 26), TimeOfDay(11, 23, 12)));
+dt.roll!"days"(-32);
+assert(dt == DateTime(Date(2010, 1, 25), TimeOfDay(11, 23, 12)));
+--------------------
+ +/
+ /+ref DateTime+/ void roll(string units)(long days) pure nothrow
+ if(units == "days")
+ {
+ _date.roll!"days"(days);
+ }
+
+ unittest
+ {
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(!__traits(compiles, cdt.roll!"days"(4)));
+ static assert(!__traits(compiles, idt.roll!"days"(4)));
+
+ //Verify Examples.
+ auto dt = DateTime(Date(2010, 1, 1), TimeOfDay(11, 23, 12));
+ dt.roll!"days"(1);
+ assert(dt == DateTime(Date(2010, 1, 2), TimeOfDay(11, 23, 12)));
+ dt.roll!"days"(365);
+ assert(dt == DateTime(Date(2010, 1, 26), TimeOfDay(11, 23, 12)));
+ dt.roll!"days"(-32);
+ assert(dt == DateTime(Date(2010, 1, 25), TimeOfDay(11, 23, 12)));
+ }
+
+
+ /++
+ Add the given number of the given units to the time of day. Negative
+ values will subtract.
+
+ The difference between rolling and adding is that rolling does not
+ affect larger units. So, if you roll the DateTime 24 hours, you get
+ the exact same DateTime.
+
+ Note that there is no $(D add!"hours"()), $(D add!"minutes"()), or
+ $(D add!"seconds"()) function because you can add them to a DateTime by
+ adding a duration to it.
+
+ Params:
+ units = The units to roll.
+ value = The number of units to add to this DateTime.
+
+ Examples:
+--------------------
+auto dt1 = DateTime(Date(2010, 7, 4), TimeOfDay(12, 0, 0));
+dt1.roll!"hours"(1);
+assert(dt1 == DateTime(Date(2010, 7, 4), TimeOfDay(13, 0, 0)));
+
+auto dt2 = DateTime(Date(2010, 2, 12), TimeOfDay(12, 0, 0));
+dt2.roll!"hours"(-1);
+assert(dt2 == DateTime(Date(2010, 2, 12), TimeOfDay(11, 0, 0)));
+
+auto dt3 = DateTime(Date(2009, 12, 31), TimeOfDay(23, 0, 0));
+dt3.roll!"hours"(1);
+assert(dt3 == DateTime(Date(2009, 12, 31), TimeOfDay(0, 0, 0)));
+
+auto dt4 = DateTime(Date(2010, 1, 1), TimeOfDay(0, 0, 0));
+dt4.roll!"hours"(-1);
+assert(dt4 == DateTime(Date(2010, 1, 1), TimeOfDay(23, 0, 0)));
+--------------------
+ +/
+ /+ref DateTime+/ void roll(string units)(long value) pure nothrow
+ if(units == "hours" ||
+ units == "minutes" ||
+ units == "seconds")
+ {
+ _tod.roll!units(value);
+ }
+
+ //Test roll!"hours"().
+ unittest
+ {
+ static void testDT(DateTime orig, int hours, in DateTime expected, size_t line = __LINE__)
+ {
+ orig.roll!"hours"(hours);
+ assertPred!"=="(orig, expected, "", __FILE__, line);
+ }
+
+ //Test A.D.
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2, DateTime(Date(1999, 7, 6), TimeOfDay(14, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3, DateTime(Date(1999, 7, 6), TimeOfDay(15, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 4, DateTime(Date(1999, 7, 6), TimeOfDay(16, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 5, DateTime(Date(1999, 7, 6), TimeOfDay(17, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 6, DateTime(Date(1999, 7, 6), TimeOfDay(18, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 7, DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 8, DateTime(Date(1999, 7, 6), TimeOfDay(20, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 9, DateTime(Date(1999, 7, 6), TimeOfDay(21, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 10, DateTime(Date(1999, 7, 6), TimeOfDay(22, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 11, DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 12, DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 13, DateTime(Date(1999, 7, 6), TimeOfDay(1, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 14, DateTime(Date(1999, 7, 6), TimeOfDay(2, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 15, DateTime(Date(1999, 7, 6), TimeOfDay(3, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 16, DateTime(Date(1999, 7, 6), TimeOfDay(4, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 17, DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 18, DateTime(Date(1999, 7, 6), TimeOfDay(6, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 19, DateTime(Date(1999, 7, 6), TimeOfDay(7, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 20, DateTime(Date(1999, 7, 6), TimeOfDay(8, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 21, DateTime(Date(1999, 7, 6), TimeOfDay(9, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 22, DateTime(Date(1999, 7, 6), TimeOfDay(10, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 23, DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 24, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 25, DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)));
+
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2, DateTime(Date(1999, 7, 6), TimeOfDay(10, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -3, DateTime(Date(1999, 7, 6), TimeOfDay(9, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -4, DateTime(Date(1999, 7, 6), TimeOfDay(8, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -5, DateTime(Date(1999, 7, 6), TimeOfDay(7, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -6, DateTime(Date(1999, 7, 6), TimeOfDay(6, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -7, DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -8, DateTime(Date(1999, 7, 6), TimeOfDay(4, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -9, DateTime(Date(1999, 7, 6), TimeOfDay(3, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -10, DateTime(Date(1999, 7, 6), TimeOfDay(2, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -11, DateTime(Date(1999, 7, 6), TimeOfDay(1, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -12, DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -13, DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -14, DateTime(Date(1999, 7, 6), TimeOfDay(22, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -15, DateTime(Date(1999, 7, 6), TimeOfDay(21, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -16, DateTime(Date(1999, 7, 6), TimeOfDay(20, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -17, DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -18, DateTime(Date(1999, 7, 6), TimeOfDay(18, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -19, DateTime(Date(1999, 7, 6), TimeOfDay(17, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -20, DateTime(Date(1999, 7, 6), TimeOfDay(16, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -21, DateTime(Date(1999, 7, 6), TimeOfDay(15, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -22, DateTime(Date(1999, 7, 6), TimeOfDay(14, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -23, DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -24, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -25, DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)));
+
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(1, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)));
+
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(22, 30, 33)));
+
+ testDT(DateTime(Date(1999, 7, 31), TimeOfDay(23, 30, 33)), 1, DateTime(Date(1999, 7, 31), TimeOfDay(0, 30, 33)));
+ testDT(DateTime(Date(1999, 8, 1), TimeOfDay(0, 30, 33)), -1, DateTime(Date(1999, 8, 1), TimeOfDay(23, 30, 33)));
+
+ testDT(DateTime(Date(1999, 12, 31), TimeOfDay(23, 30, 33)), 1, DateTime(Date(1999, 12, 31), TimeOfDay(0, 30, 33)));
+ testDT(DateTime(Date(2000, 1, 1), TimeOfDay(0, 30, 33)), -1, DateTime(Date(2000, 1, 1), TimeOfDay(23, 30, 33)));
+
+ testDT(DateTime(Date(1999, 2, 28), TimeOfDay(23, 30, 33)), 25, DateTime(Date(1999, 2, 28), TimeOfDay(0, 30, 33)));
+ testDT(DateTime(Date(1999, 3, 2), TimeOfDay(0, 30, 33)), -25, DateTime(Date(1999, 3, 2), TimeOfDay(23, 30, 33)));
+
+ testDT(DateTime(Date(2000, 2, 28), TimeOfDay(23, 30, 33)), 25, DateTime(Date(2000, 2, 28), TimeOfDay(0, 30, 33)));
+ testDT(DateTime(Date(2000, 3, 1), TimeOfDay(0, 30, 33)), -25, DateTime(Date(2000, 3, 1), TimeOfDay(23, 30, 33)));
+
+ //Test B.C.
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(13, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2, DateTime(Date(-1999, 7, 6), TimeOfDay(14, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3, DateTime(Date(-1999, 7, 6), TimeOfDay(15, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 4, DateTime(Date(-1999, 7, 6), TimeOfDay(16, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 5, DateTime(Date(-1999, 7, 6), TimeOfDay(17, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 6, DateTime(Date(-1999, 7, 6), TimeOfDay(18, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 7, DateTime(Date(-1999, 7, 6), TimeOfDay(19, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 8, DateTime(Date(-1999, 7, 6), TimeOfDay(20, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 9, DateTime(Date(-1999, 7, 6), TimeOfDay(21, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 10, DateTime(Date(-1999, 7, 6), TimeOfDay(22, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 11, DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 12, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 13, DateTime(Date(-1999, 7, 6), TimeOfDay(1, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 14, DateTime(Date(-1999, 7, 6), TimeOfDay(2, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 15, DateTime(Date(-1999, 7, 6), TimeOfDay(3, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 16, DateTime(Date(-1999, 7, 6), TimeOfDay(4, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 17, DateTime(Date(-1999, 7, 6), TimeOfDay(5, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 18, DateTime(Date(-1999, 7, 6), TimeOfDay(6, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 19, DateTime(Date(-1999, 7, 6), TimeOfDay(7, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 20, DateTime(Date(-1999, 7, 6), TimeOfDay(8, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 21, DateTime(Date(-1999, 7, 6), TimeOfDay(9, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 22, DateTime(Date(-1999, 7, 6), TimeOfDay(10, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 23, DateTime(Date(-1999, 7, 6), TimeOfDay(11, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 24, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 25, DateTime(Date(-1999, 7, 6), TimeOfDay(13, 30, 33)));
+
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(11, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2, DateTime(Date(-1999, 7, 6), TimeOfDay(10, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -3, DateTime(Date(-1999, 7, 6), TimeOfDay(9, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -4, DateTime(Date(-1999, 7, 6), TimeOfDay(8, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -5, DateTime(Date(-1999, 7, 6), TimeOfDay(7, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -6, DateTime(Date(-1999, 7, 6), TimeOfDay(6, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -7, DateTime(Date(-1999, 7, 6), TimeOfDay(5, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -8, DateTime(Date(-1999, 7, 6), TimeOfDay(4, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -9, DateTime(Date(-1999, 7, 6), TimeOfDay(3, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -10, DateTime(Date(-1999, 7, 6), TimeOfDay(2, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -11, DateTime(Date(-1999, 7, 6), TimeOfDay(1, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -12, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -13, DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -14, DateTime(Date(-1999, 7, 6), TimeOfDay(22, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -15, DateTime(Date(-1999, 7, 6), TimeOfDay(21, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -16, DateTime(Date(-1999, 7, 6), TimeOfDay(20, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -17, DateTime(Date(-1999, 7, 6), TimeOfDay(19, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -18, DateTime(Date(-1999, 7, 6), TimeOfDay(18, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -19, DateTime(Date(-1999, 7, 6), TimeOfDay(17, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -20, DateTime(Date(-1999, 7, 6), TimeOfDay(16, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -21, DateTime(Date(-1999, 7, 6), TimeOfDay(15, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -22, DateTime(Date(-1999, 7, 6), TimeOfDay(14, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -23, DateTime(Date(-1999, 7, 6), TimeOfDay(13, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -24, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -25, DateTime(Date(-1999, 7, 6), TimeOfDay(11, 30, 33)));
+
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(1, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)));
+
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(22, 30, 33)));
+
+ testDT(DateTime(Date(-1999, 7, 31), TimeOfDay(23, 30, 33)), 1, DateTime(Date(-1999, 7, 31), TimeOfDay(0, 30, 33)));
+ testDT(DateTime(Date(-1999, 8, 1), TimeOfDay(0, 30, 33)), -1, DateTime(Date(-1999, 8, 1), TimeOfDay(23, 30, 33)));
+
+ testDT(DateTime(Date(-2001, 12, 31), TimeOfDay(23, 30, 33)), 1, DateTime(Date(-2001, 12, 31), TimeOfDay(0, 30, 33)));
+ testDT(DateTime(Date(-2000, 1, 1), TimeOfDay(0, 30, 33)), -1, DateTime(Date(-2000, 1, 1), TimeOfDay(23, 30, 33)));
+
+ testDT(DateTime(Date(-2001, 2, 28), TimeOfDay(23, 30, 33)), 25, DateTime(Date(-2001, 2, 28), TimeOfDay(0, 30, 33)));
+ testDT(DateTime(Date(-2001, 3, 2), TimeOfDay(0, 30, 33)), -25, DateTime(Date(-2001, 3, 2), TimeOfDay(23, 30, 33)));
+
+ testDT(DateTime(Date(-2000, 2, 28), TimeOfDay(23, 30, 33)), 25, DateTime(Date(-2000, 2, 28), TimeOfDay(0, 30, 33)));
+ testDT(DateTime(Date(-2000, 3, 1), TimeOfDay(0, 30, 33)), -25, DateTime(Date(-2000, 3, 1), TimeOfDay(23, 30, 33)));
+
+ //Test Both
+ testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 17_546, DateTime(Date(-1, 1, 1), TimeOfDay(13, 30, 33)));
+ testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)), -17_546, DateTime(Date(1, 1, 1), TimeOfDay(11, 30, 33)));
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(!__traits(compiles, cdt.roll!"hours"(4)));
+ static assert(!__traits(compiles, idt.roll!"hours"(4)));
+
+ //Verify Examples.
+ auto dt1 = DateTime(Date(2010, 7, 4), TimeOfDay(12, 0, 0));
+ dt1.roll!"hours"(1);
+ assert(dt1 == DateTime(Date(2010, 7, 4), TimeOfDay(13, 0, 0)));
+
+ auto dt2 = DateTime(Date(2010, 2, 12), TimeOfDay(12, 0, 0));
+ dt2.roll!"hours"(-1);
+ assert(dt2 == DateTime(Date(2010, 2, 12), TimeOfDay(11, 0, 0)));
+
+ auto dt3 = DateTime(Date(2009, 12, 31), TimeOfDay(23, 0, 0));
+ dt3.roll!"hours"(1);
+ assert(dt3 == DateTime(Date(2009, 12, 31), TimeOfDay(0, 0, 0)));
+
+ auto dt4 = DateTime(Date(2010, 1, 1), TimeOfDay(0, 0, 0));
+ dt4.roll!"hours"(-1);
+ assert(dt4 == DateTime(Date(2010, 1, 1), TimeOfDay(23, 0, 0)));
+ }
+
+ //Test roll!"minutes"().
+ unittest
+ {
+ static void testDT(DateTime orig, int minutes, in DateTime expected, size_t line = __LINE__)
+ {
+ orig.roll!"minutes"(minutes);
+ assertPred!"=="(orig, expected, "", __FILE__, line);
+ }
+
+ //Test A.D.
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2, DateTime(Date(1999, 7, 6), TimeOfDay(12, 32, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3, DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 4, DateTime(Date(1999, 7, 6), TimeOfDay(12, 34, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 5, DateTime(Date(1999, 7, 6), TimeOfDay(12, 35, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 10, DateTime(Date(1999, 7, 6), TimeOfDay(12, 40, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 15, DateTime(Date(1999, 7, 6), TimeOfDay(12, 45, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 29, DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 30, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 45, DateTime(Date(1999, 7, 6), TimeOfDay(12, 15, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 60, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 75, DateTime(Date(1999, 7, 6), TimeOfDay(12, 45, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 90, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 100, DateTime(Date(1999, 7, 6), TimeOfDay(12, 10, 33)));
+
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 689, DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 690, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 691, DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 960, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1439, DateTime(Date(1999, 7, 6), TimeOfDay(12, 29, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1440, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1441, DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2880, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 29, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2, DateTime(Date(1999, 7, 6), TimeOfDay(12, 28, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -3, DateTime(Date(1999, 7, 6), TimeOfDay(12, 27, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -4, DateTime(Date(1999, 7, 6), TimeOfDay(12, 26, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -5, DateTime(Date(1999, 7, 6), TimeOfDay(12, 25, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -10, DateTime(Date(1999, 7, 6), TimeOfDay(12, 20, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -15, DateTime(Date(1999, 7, 6), TimeOfDay(12, 15, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -29, DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -30, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -45, DateTime(Date(1999, 7, 6), TimeOfDay(12, 45, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -60, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -75, DateTime(Date(1999, 7, 6), TimeOfDay(12, 15, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -90, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -100, DateTime(Date(1999, 7, 6), TimeOfDay(12, 50, 33)));
+
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -749, DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -750, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -751, DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -960, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1439, DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1440, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1441, DateTime(Date(1999, 7, 6), TimeOfDay(12, 29, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2880, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33)));
+
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(11, 0, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(11, 58, 33)));
+
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(0, 1, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(0, 59, 33)));
+
+ testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33)), 1, DateTime(Date(1999, 7, 5), TimeOfDay(23, 0, 33)));
+ testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33)), 0, DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33)));
+ testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33)), -1, DateTime(Date(1999, 7, 5), TimeOfDay(23, 58, 33)));
+
+ testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33)), 1, DateTime(Date(1998, 12, 31), TimeOfDay(23, 0, 33)));
+ testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33)), 0, DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33)));
+ testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33)), -1, DateTime(Date(1998, 12, 31), TimeOfDay(23, 58, 33)));
+
+ //Test B.C.
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 31, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 32, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 33, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 4, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 34, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 5, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 35, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 10, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 40, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 15, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 45, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 29, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 30, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 45, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 15, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 60, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 75, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 45, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 90, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 100, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 10, 33)));
+
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 689, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 690, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 691, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 960, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1439, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 29, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1440, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1441, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 31, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2880, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 29, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 28, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -3, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 27, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -4, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 26, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -5, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 25, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -10, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 20, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -15, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 15, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -29, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -30, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -45, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 45, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -60, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -75, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 15, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -90, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -100, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 50, 33)));
+
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -749, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -750, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -751, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -960, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1439, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 31, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1440, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1441, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 29, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2880, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33)));
+
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(11, 0, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(11, 58, 33)));
+
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 1, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 59, 33)));
+
+ testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33)), 1, DateTime(Date(-1999, 7, 5), TimeOfDay(23, 0, 33)));
+ testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33)), 0, DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33)));
+ testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33)), -1, DateTime(Date(-1999, 7, 5), TimeOfDay(23, 58, 33)));
+
+ testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33)), 1, DateTime(Date(-2000, 12, 31), TimeOfDay(23, 0, 33)));
+ testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33)), 0, DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33)));
+ testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33)), -1, DateTime(Date(-2000, 12, 31), TimeOfDay(23, 58, 33)));
+
+ //Test Both
+ testDT(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)), -1, DateTime(Date(1, 1, 1), TimeOfDay(0, 59, 0)));
+ testDT(DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 0)), 1, DateTime(Date(0, 12, 31), TimeOfDay(23, 0, 0)));
+
+ testDT(DateTime(Date(0, 1, 1), TimeOfDay(0, 0, 0)), -1, DateTime(Date(0, 1, 1), TimeOfDay(0, 59, 0)));
+ testDT(DateTime(Date(-1, 12, 31), TimeOfDay(23, 59, 0)), 1, DateTime(Date(-1, 12, 31), TimeOfDay(23, 0, 0)));
+
+ testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 1_052_760, DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)));
+ testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)), -1_052_760, DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)));
+
+ testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 1_052_782, DateTime(Date(-1, 1, 1), TimeOfDay(11, 52, 33)));
+ testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 52, 33)), -1_052_782, DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)));
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(!__traits(compiles, cdt.roll!"minutes"(4)));
+ static assert(!__traits(compiles, idt.roll!"minutes"(4)));
+ }
+
+ //Test roll!"seconds"().
+ unittest
+ {
+ static void testDT(DateTime orig, int seconds, in DateTime expected, size_t line = __LINE__)
+ {
+ orig.roll!"seconds"(seconds);
+ assertPred!"=="(orig, expected, "", __FILE__, line);
+ }
+
+ //Test A.D.
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 35)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 36)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 4, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 37)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 5, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 38)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 10, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 43)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 15, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 48)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 26, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 27, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 30, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 3)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 59, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 60, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 61, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)));
+
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1766, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1767, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1768, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 1)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2007, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3599, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3600, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3601, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 7200, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 31)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -3, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 30)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -4, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 29)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -5, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 28)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -10, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 23)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -15, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 18)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -33, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -34, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -35, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 58)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -59, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -60, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -61, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32)));
+
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 1)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59)));
+
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 1)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 59)));
+
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), 1, DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 1)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), 0, DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)));
+ testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), -1, DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 59)));
+
+ testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59)), 1, DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 0)));
+ testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59)), 0, DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59)));
+ testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59)), -1, DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 58)));
+
+ testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59)), 1, DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 0)));
+ testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59)), 0, DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59)));
+ testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59)), -1, DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 58)));
+
+ //Test B.C.
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 35)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 36)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 4, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 37)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 5, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 38)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 10, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 43)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 15, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 48)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 26, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 27, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 30, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 3)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 59, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 60, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 61, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34)));
+
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1766, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1767, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1768, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 1)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2007, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3599, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3600, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3601, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 7200, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 31)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -3, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 30)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -4, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 29)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -5, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 28)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -10, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 23)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -15, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 18)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -33, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -34, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -35, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 58)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -59, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -60, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -61, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32)));
+
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 1)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59)));
+
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 1)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 59)));
+
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0)), 1, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 1)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0)), 0, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0)));
+ testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0)), -1, DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 59)));
+
+ testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59)), 1, DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 0)));
+ testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59)), 0, DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59)));
+ testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59)), -1, DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 58)));
+
+ testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59)), 1, DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 0)));
+ testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59)), 0, DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59)));
+ testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59)), -1, DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 58)));
+
+ //Test Both
+ testDT(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)), -1, DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 59)));
+ testDT(DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 59)), 1, DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 0)));
+
+ testDT(DateTime(Date(0, 1, 1), TimeOfDay(0, 0, 0)), -1, DateTime(Date(0, 1, 1), TimeOfDay(0, 0, 59)));
+ testDT(DateTime(Date(-1, 12, 31), TimeOfDay(23, 59, 59)), 1, DateTime(Date(-1, 12, 31), TimeOfDay(23, 59, 0)));
+
+ testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 63_165_600L, DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)));
+ testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)), -63_165_600L, DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)));
+
+ testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 63_165_617L, DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 50)));
+ testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 50)), -63_165_617L, DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)));
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(!__traits(compiles, cdt.roll!"seconds"(4)));
+ static assert(!__traits(compiles, idt.roll!"seconds"(4)));
+ }
+
+
+ /++
+ Gives the result of adding or subtracting a duration from this DateTime.
+
+ The legal types of arithmetic for DateTime using this operator are
+
+ $(TABLE
+ $(TR $(TD DateTime) $(TD +) $(TD duration) $(TD -->) $(TD DateTime))
+ $(TR $(TD DateTime) $(TD -) $(TD duration) $(TD -->) $(TD DateTime))
+ )
+
+ Params:
+ duration = The duration to add to or subtract from this DateTime.
+ +/
+ DateTime opBinary(string op, D)(in D duration) const pure nothrow
+ if((op == "+" || op == "-") &&
+ (is(Unqual!D == Duration) ||
+ is(Unqual!D == TickDuration)))
+ {
+ DateTime retval = this;
+
+ static if(is(Unqual!D == Duration))
+ immutable hnsecs = duration.total!"hnsecs";
+ else static if(is(Unqual!D == TickDuration))
+ immutable hnsecs = duration.hnsecs;
+
+ //Ideally, this would just be
+ //return retval.addSeconds(convert!("hnsecs", "seconds")(unaryFun!(op ~ "a")(hnsecs)));
+ //But there isn't currently a pure version of unaryFun!().
+
+ static if(op == "+")
+ immutable signedHNSecs = hnsecs;
+ else static if(op == "-")
+ immutable signedHNSecs = -hnsecs;
+ else
+ static assert(0);
+
+ return retval.addSeconds(convert!("hnsecs", "seconds")(signedHNSecs));
+ }
+
+ unittest
+ {
+ auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+
+ assertPred!"=="(dt + dur!"weeks"(7), DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(dt + dur!"weeks"(-7), DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(dt + dur!"days"(7), DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(dt + dur!"days"(-7), DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33)));
+
+ assertPred!"=="(dt + dur!"hours"(7), DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33)));
+ assertPred!"=="(dt + dur!"hours"(-7), DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33)));
+ assertPred!"=="(dt + dur!"minutes"(7), DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33)));
+ assertPred!"=="(dt + dur!"minutes"(-7), DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33)));
+ assertPred!"=="(dt + dur!"seconds"(7), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
+ assertPred!"=="(dt + dur!"seconds"(-7), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
+ assertPred!"=="(dt + dur!"msecs"(7_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
+ assertPred!"=="(dt + dur!"msecs"(-7_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
+ assertPred!"=="(dt + dur!"usecs"(7_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
+ assertPred!"=="(dt + dur!"usecs"(-7_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
+ assertPred!"=="(dt + dur!"hnsecs"(70_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
+ assertPred!"=="(dt + dur!"hnsecs"(-70_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
+
+ //This probably only runs in cases where gettimeofday() is used, but it's
+ //hard to do this test correctly with variable ticksPerSec.
+ if(TickDuration.ticksPerSec == 1_000_000)
+ {
+ assertPred!"=="(dt + TickDuration.from!"usecs"(7_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
+ assertPred!"=="(dt + TickDuration.from!"usecs"(-7_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
+ }
+
+ assertPred!"=="(dt - dur!"weeks"(-7), DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(dt - dur!"weeks"(7), DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(dt - dur!"days"(-7), DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(dt - dur!"days"(7), DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33)));
+
+ assertPred!"=="(dt - dur!"hours"(-7), DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33)));
+ assertPred!"=="(dt - dur!"hours"(7), DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33)));
+ assertPred!"=="(dt - dur!"minutes"(-7), DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33)));
+ assertPred!"=="(dt - dur!"minutes"(7), DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33)));
+ assertPred!"=="(dt - dur!"seconds"(-7), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
+ assertPred!"=="(dt - dur!"seconds"(7), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
+ assertPred!"=="(dt - dur!"msecs"(-7_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
+ assertPred!"=="(dt - dur!"msecs"(7_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
+ assertPred!"=="(dt - dur!"usecs"(-7_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
+ assertPred!"=="(dt - dur!"usecs"(7_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
+ assertPred!"=="(dt - dur!"hnsecs"(-70_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
+ assertPred!"=="(dt - dur!"hnsecs"(70_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
+
+ //This probably only runs in cases where gettimeofday() is used, but it's
+ //hard to do this test correctly with variable ticksPerSec.
+ if(TickDuration.ticksPerSec == 1_000_000)
+ {
+ assertPred!"=="(dt - TickDuration.from!"usecs"(-7_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
+ assertPred!"=="(dt - TickDuration.from!"usecs"(7_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
+ }
+
+ auto duration = dur!"seconds"(12);
+ const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ static assert(__traits(compiles, cdt + duration));
+ static assert(__traits(compiles, idt + duration));
+ static assert(__traits(compiles, cdt - duration));
+ static assert(__traits(compiles, idt - duration));
+ }
+
+
+ /++
+ Gives the result of adding or subtracting a duration from this DateTime,
+ as well as assigning the result to this DateTime.
+
+ The legal types of arithmetic for DateTime using this operator are
+
+ $(TABLE
+ $(TR $(TD DateTime) $(TD +) $(TD duration) $(TD -->) $(TD DateTime))
+ $(TR $(TD DateTime) $(TD -) $(TD duration) $(TD -->) $(TD DateTime))
+ )
+
+ Params:
+ duration = The duration to add to or subtract from this DateTime.
+ +/
+ /+ref+/ DateTime opOpAssign(string op, D)(in D duration) pure nothrow
+ if((op == "+" || op == "-") &&
+ (is(Unqual!D == Duration) ||
+ is(Unqual!D == TickDuration)))
+ {
+ DateTime retval = this;
+
+ static if(is(Unqual!D == Duration))
+ immutable hnsecs = duration.total!"hnsecs";
+ else static if(is(Unqual!D == TickDuration))
+ immutable hnsecs = duration.hnsecs;
+
+ //Ideally, this would just be
+ //return addSeconds(convert!("hnsecs", "seconds")(unaryFun!(op ~ "a")(hnsecs)));
+ //But there isn't currently a pure version of unaryFun!().
+
+ static if(op == "+")
+ immutable signedHNSecs = hnsecs;
+ else static if(op == "-")
+ immutable signedHNSecs = -hnsecs;
+ else
+ static assert(0);
+
+ return addSeconds(convert!("hnsecs", "seconds")(signedHNSecs));
+ }
+
+ unittest
+ {
+ assertPred!"+="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"weeks"(7), DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33)));
+ assertPred!"+="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"weeks"(-7), DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33)));
+ assertPred!"+="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"days"(7), DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33)));
+ assertPred!"+="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"days"(-7), DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33)));
+
+ assertPred!"+="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"hours"(7), DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33)));
+ assertPred!"+="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"hours"(-7), DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33)));
+ assertPred!"+="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"minutes"(7), DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33)));
+ assertPred!"+="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"minutes"(-7), DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33)));
+ assertPred!"+="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"seconds"(7), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
+ assertPred!"+="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"seconds"(-7), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
+ assertPred!"+="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"msecs"(7_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
+ assertPred!"+="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"msecs"(-7_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
+ assertPred!"+="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"usecs"(7_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
+ assertPred!"+="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"usecs"(-7_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
+ assertPred!"+="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"hnsecs"(70_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
+ assertPred!"+="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"hnsecs"(-70_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
+
+ assertPred!"-="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"weeks"(-7), DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33)));
+ assertPred!"-="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"weeks"(7), DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33)));
+ assertPred!"-="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"days"(-7), DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33)));
+ assertPred!"-="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"days"(7), DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33)));
+
+ assertPred!"-="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"hours"(-7), DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33)));
+ assertPred!"-="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"hours"(7), DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33)));
+ assertPred!"-="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"minutes"(-7), DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33)));
+ assertPred!"-="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"minutes"(7), DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33)));
+ assertPred!"-="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"seconds"(-7), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
+ assertPred!"-="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"seconds"(7), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
+ assertPred!"-="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"msecs"(-7_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
+ assertPred!"-="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"msecs"(7_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
+ assertPred!"-="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"usecs"(-7_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
+ assertPred!"-="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"usecs"(7_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
+ assertPred!"-="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"hnsecs"(-70_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
+ assertPred!"-="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), dur!"hnsecs"(70_000_000), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
+
+ auto duration = dur!"seconds"(12);
+ const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ static assert(!__traits(compiles, cdt += duration));
+ static assert(!__traits(compiles, idt += duration));
+ static assert(!__traits(compiles, cdt -= duration));
+ static assert(!__traits(compiles, idt -= duration));
+ }
+
+
+ /++
+ Gives the difference between two DateTimes.
+
+ The legal types of arithmetic for DateTime using this operator are
+
+ $(TABLE
+ $(TR $(TD DateTime) $(TD -) $(TD DateTime) $(TD -->) $(TD duration))
+ )
+ +/
+ Duration opBinary(string op)(in DateTime rhs) const pure nothrow
+ if(op == "-")
+ {
+ immutable dateResult = _date - rhs.date;
+ immutable todResult = _tod - rhs._tod;
+
+ return dur!"hnsecs"(dateResult.total!"hnsecs" + todResult.total!"hnsecs");
+ }
+
+ unittest
+ {
+ auto dt = DateTime(1999, 7, 6, 12, 30, 33);
+
+ assertPred!"=="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) -
+ DateTime(Date(1998, 7, 6), TimeOfDay(12, 30, 33)),
+ dur!"seconds"(31_536_000));
+ assertPred!"=="(DateTime(Date(1998, 7, 6), TimeOfDay(12, 30, 33)) -
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)),
+ dur!"seconds"(-31_536_000));
+
+ assertPred!"=="(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)) -
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)),
+ dur!"seconds"(26_78_400));
+ assertPred!"=="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) -
+ DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)),
+ dur!"seconds"(-26_78_400));
+
+ assertPred!"=="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) -
+ DateTime(Date(1999, 7, 5), TimeOfDay(12, 30, 33)),
+ dur!"seconds"(86_400));
+ assertPred!"=="(DateTime(Date(1999, 7, 5), TimeOfDay(12, 30, 33)) -
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)),
+ dur!"seconds"(-86_400));
+
+ assertPred!"=="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) -
+ DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)),
+ dur!"seconds"(3600));
+ assertPred!"=="(DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)) -
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)),
+ dur!"seconds"(-3600));
+
+ assertPred!"=="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)) -
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)),
+ dur!"seconds"(60));
+ assertPred!"=="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) -
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)),
+ dur!"seconds"(-60));
+
+ assertPred!"=="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)) -
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)),
+ dur!"seconds"(1));
+ assertPred!"=="(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) -
+ DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)),
+ dur!"seconds"(-1));
+
+ assertPred!"=="(DateTime(1, 1, 1, 12, 30, 33) - DateTime(1, 1, 1, 0, 0, 0), dur!"seconds"(45033));
+ assertPred!"=="(DateTime(1, 1, 1, 0, 0, 0) - DateTime(1, 1, 1, 12, 30, 33), dur!"seconds"(-45033));
+ assertPred!"=="(DateTime(0, 12, 31, 12, 30, 33) - DateTime(1, 1, 1, 0, 0, 0), dur!"seconds"(-41367));
+ assertPred!"=="(DateTime(1, 1, 1, 0, 0, 0) - DateTime(0, 12, 31, 12, 30, 33), dur!"seconds"(41367));
+
+ const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ static assert(__traits(compiles, dt - dt));
+ static assert(__traits(compiles, cdt - dt));
+ static assert(__traits(compiles, idt - dt));
+
+ static assert(__traits(compiles, dt - cdt));
+ static assert(__traits(compiles, cdt - cdt));
+ static assert(__traits(compiles, idt - cdt));
+
+ static assert(__traits(compiles, dt - idt));
+ static assert(__traits(compiles, cdt - idt));
+ static assert(__traits(compiles, idt - idt));
+ }
+
+
+ /++
+ Returns the difference between the two DateTimes in months.
+
+ You can get the difference in years by subtracting the year property
+ of two DateTimes, and you can get the difference in days or weeks by
+ subtracting the DateTimes themselves and using the Duration that results,
+ but because you cannot convert between months and smaller units without
+ a specific date (which Durations don't have), you cannot get the difference
+ in months without doing some math using both the year and month properties,
+ so this is a convenience function for getting the difference in months.
+
+ Note that the number of days in the months or how far into the month either
+ date is is irrelevant. It is the difference in the month property combined
+ with the difference in years * 12. So, for instance, December 31st and
+ January 1st are one month apart just as December 1st and January 31st are
+ one month apart.
+
+ Params:
+ rhs = The DateTime to subtract from this one.
+
+ Examples:
+--------------------
+assert(DateTime(1999, 2, 1, 12, 2, 3).diffMonths(DateTime(1999, 1, 31, 23, 59, 59)) == 1);
+assert(DateTime(1999, 1, 31, 0, 0, 0).diffMonths(DateTime(1999, 2, 1, 12, 3, 42)) == -1);
+assert(DateTime(1999, 3, 1, 5, 30, 0).diffMonths(DateTime(1999, 1, 1, 2, 4, 7)) == 2);
+assert(DateTime(1999, 1, 1, 7, 2, 4).diffMonths(DateTime(1999, 3, 31, 0, 30, 58)) == -2);
+--------------------
+ +/
+ int diffMonths(in DateTime rhs) const pure nothrow
+ {
+ return _date.diffMonths(rhs._date);
+ }
+
+ unittest
+ {
+ auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ static assert(__traits(compiles, dt.diffMonths(dt)));
+ static assert(__traits(compiles, cdt.diffMonths(dt)));
+ static assert(__traits(compiles, idt.diffMonths(dt)));
+
+ static assert(__traits(compiles, dt.diffMonths(cdt)));
+ static assert(__traits(compiles, cdt.diffMonths(cdt)));
+ static assert(__traits(compiles, idt.diffMonths(cdt)));
+
+ static assert(__traits(compiles, dt.diffMonths(idt)));
+ static assert(__traits(compiles, cdt.diffMonths(idt)));
+ static assert(__traits(compiles, idt.diffMonths(idt)));
+
+ //Verify Examples.
+ assert(DateTime(1999, 2, 1, 12, 2, 3).diffMonths(DateTime(1999, 1, 31, 23, 59, 59)) == 1);
+ assert(DateTime(1999, 1, 31, 0, 0, 0).diffMonths(DateTime(1999, 2, 1, 12, 3, 42)) == -1);
+ assert(DateTime(1999, 3, 1, 5, 30, 0).diffMonths(DateTime(1999, 1, 1, 2, 4, 7)) == 2);
+ assert(DateTime(1999, 1, 1, 7, 2, 4).diffMonths(DateTime(1999, 3, 31, 0, 30, 58)) == -2);
+ }
+
+
+ /++
+ Whether this DateTime is in a leap year.
+ +/
+ @property bool isLeapYear() const pure nothrow
+ {
+ return _date.isLeapYear;
+ }
+
+ unittest
+ {
+ auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ static assert(__traits(compiles, dt.isLeapYear));
+ static assert(__traits(compiles, cdt.isLeapYear));
+ static assert(__traits(compiles, idt.isLeapYear));
+ }
+
+
+ /++
+ Day of the week this DateTime is on.
+ +/
+ @property DayOfWeek dayOfWeek() const pure nothrow
+ {
+ return _date.dayOfWeek;
+ }
+
+ unittest
+ {
+ auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ static assert(__traits(compiles, dt.dayOfWeek));
+ static assert(__traits(compiles, cdt.dayOfWeek));
+ static assert(__traits(compiles, idt.dayOfWeek));
+ }
+
+
+ /++
+ Day of the year this DateTime is on.
+
+ Examples:
+--------------------
+assert(DateTime(Date(1999, 1, 1), TimeOfDay(12, 22, 7)).dayOfYear == 1);
+assert(DateTime(Date(1999, 12, 31), TimeOfDay(7, 2, 59)).dayOfYear == 365);
+assert(DateTime(Date(2000, 12, 31), TimeOfDay(21, 20, 0)).dayOfYear == 366);
+--------------------
+ +/
+ @property ushort dayOfYear() const pure nothrow
+ {
+ return _date.dayOfYear;
+ }
+
+ unittest
+ {
+ auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ static assert(__traits(compiles, dt.dayOfYear));
+ static assert(__traits(compiles, cdt.dayOfYear));
+ static assert(__traits(compiles, idt.dayOfYear));
+
+ //Verify Examples.
+ assert(DateTime(Date(1999, 1, 1), TimeOfDay(12, 22, 7)).dayOfYear == 1);
+ assert(DateTime(Date(1999, 12, 31), TimeOfDay(7, 2, 59)).dayOfYear == 365);
+ assert(DateTime(Date(2000, 12, 31), TimeOfDay(21, 20, 0)).dayOfYear == 366);
+ }
+
+
+ /++
+ Day of the year.
+
+ Params:
+ day = The day of the year to set which day of the year this DateTime is on.
+ +/
+ @property void dayOfYear(int day) pure
+ {
+ _date.dayOfYear = day;
+ }
+
+ unittest
+ {
+ auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ static assert(__traits(compiles, dt.dayOfYear = 12));
+ static assert(!__traits(compiles, cdt.dayOfYear = 12));
+ static assert(!__traits(compiles, idt.dayOfYear = 12));
+ }
+
+
+ /++
+ The Xth day of the Gregorian Calendar that this DateTime is on.
+
+ Examples:
+--------------------
+assert(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).dayOfGregorianCal == 1);
+assert(DateTime(Date(1, 12, 31), TimeOfDay(23, 59, 59)).dayOfGregorianCal == 365);
+assert(DateTime(Date(2, 1, 1), TimeOfDay(2, 2, 2)).dayOfGregorianCal == 366);
+
+assert(DateTime(Date(0, 12, 31), TimeOfDay(7, 7, 7)).dayOfGregorianCal == 0);
+assert(DateTime(Date(0, 1, 1), TimeOfDay(19, 30, 0)).dayOfGregorianCal == -365);
+assert(DateTime(Date(-1, 12, 31), TimeOfDay(4, 7, 0)).dayOfGregorianCal == -366);
+
+assert(DateTime(Date(2000, 1, 1), TimeOfDay(9, 30, 20)).dayOfGregorianCal == 730_120);
+assert(DateTime(Date(2010, 12, 31), TimeOfDay(15, 45, 50)).dayOfGregorianCal == 734_137);
+--------------------
+ +/
+ @property int dayOfGregorianCal() const pure nothrow
+ {
+ return _date.dayOfGregorianCal;
+ }
+
+ unittest
+ {
+ const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ static assert(__traits(compiles, cdt.dayOfGregorianCal));
+ static assert(__traits(compiles, idt.dayOfGregorianCal));
+
+ //Verify Examples.
+ assert(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).dayOfGregorianCal == 1);
+ assert(DateTime(Date(1, 12, 31), TimeOfDay(23, 59, 59)).dayOfGregorianCal == 365);
+ assert(DateTime(Date(2, 1, 1), TimeOfDay(2, 2, 2)).dayOfGregorianCal == 366);
+
+ assert(DateTime(Date(0, 12, 31), TimeOfDay(7, 7, 7)).dayOfGregorianCal == 0);
+ assert(DateTime(Date(0, 1, 1), TimeOfDay(19, 30, 0)).dayOfGregorianCal == -365);
+ assert(DateTime(Date(-1, 12, 31), TimeOfDay(4, 7, 0)).dayOfGregorianCal == -366);
+
+ assert(DateTime(Date(2000, 1, 1), TimeOfDay(9, 30, 20)).dayOfGregorianCal == 730_120);
+ assert(DateTime(Date(2010, 12, 31), TimeOfDay(15, 45, 50)).dayOfGregorianCal == 734_137);
+ }
+
+
+ /++
+ The Xth day of the Gregorian Calendar that this DateTime is on. Setting
+ this property does not affect the time portion of DateTime.
+
+ Params:
+ days = The day of the Gregorian Calendar to set this DateTime to.
+
+ Examples:
+--------------------
+auto dt = DateTime(Date.init, TimeOfDay(12, 0, 0));
+dt.dayOfGregorianCal = 1;
+assert(dt == DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0)));
+
+dt.dayOfGregorianCal = 365;
+assert(dt == DateTime(Date(1, 12, 31), TimeOfDay(12, 0, 0)));
+
+dt.dayOfGregorianCal = 366;
+assert(dt == DateTime(Date(2, 1, 1), TimeOfDay(12, 0, 0)));
+
+dt.dayOfGregorianCal = 0;
+assert(dt == DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0)));
+
+dt.dayOfGregorianCal = -365;
+assert(dt == DateTime(Date(-0, 1, 1), TimeOfDay(12, 0, 0)));
+
+dt.dayOfGregorianCal = -366;
+assert(dt == DateTime(Date(-1, 12, 31), TimeOfDay(12, 0, 0)));
+
+dt.dayOfGregorianCal = 730_120;
+assert(dt == DateTime(Date(2000, 1, 1), TimeOfDay(12, 0, 0)));
+
+dt.dayOfGregorianCal = 734_137;
+assert(dt == DateTime(Date(2010, 12, 31), TimeOfDay(12, 0, 0)));
+--------------------
+ +/
+ @property void dayOfGregorianCal(int days) pure nothrow
+ {
+ _date.dayOfGregorianCal = days;
+ }
+
+ unittest
+ {
+ const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ static assert(!__traits(compiles, cdt.dayOfGregorianCal = 7));
+ static assert(!__traits(compiles, idt.dayOfGregorianCal = 7));
+
+ //Verify Examples.
+ auto dt = DateTime(Date.init, TimeOfDay(12, 0, 0));
+ dt.dayOfGregorianCal = 1;
+ assert(dt == DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0)));
+
+ dt.dayOfGregorianCal = 365;
+ assert(dt == DateTime(Date(1, 12, 31), TimeOfDay(12, 0, 0)));
+
+ dt.dayOfGregorianCal = 366;
+ assert(dt == DateTime(Date(2, 1, 1), TimeOfDay(12, 0, 0)));
+
+ dt.dayOfGregorianCal = 0;
+ assert(dt == DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0)));
+
+ dt.dayOfGregorianCal = -365;
+ assert(dt == DateTime(Date(-0, 1, 1), TimeOfDay(12, 0, 0)));
+
+ dt.dayOfGregorianCal = -366;
+ assert(dt == DateTime(Date(-1, 12, 31), TimeOfDay(12, 0, 0)));
+
+ dt.dayOfGregorianCal = 730_120;
+ assert(dt == DateTime(Date(2000, 1, 1), TimeOfDay(12, 0, 0)));
+
+ dt.dayOfGregorianCal = 734_137;
+ assert(dt == DateTime(Date(2010, 12, 31), TimeOfDay(12, 0, 0)));
+ }
+
+
+ /++
+ The ISO 8601 week of the year that this DateTime is in.
+
+ See_Also:
+ ISO Week Date
+ +/
+ @property ubyte isoWeek() const pure nothrow
+ {
+ return _date.isoWeek;
+ }
+
+ unittest
+ {
+ auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ static assert(__traits(compiles, dt.isoWeek));
+ static assert(__traits(compiles, cdt.isoWeek));
+ static assert(__traits(compiles, idt.isoWeek));
+ }
+
+
+ /++
+ DateTime for the last day in the month that this DateTime is in.
+ The time portion of endOfMonth is always 23:59:59.
+
+ Examples:
+--------------------
+assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).endOfMonth == DateTime(Date(1999, 1, 31), TimeOfDay(23, 59, 59)));
+assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).endOfMonth == DateTime(Date(1999, 2, 28), TimeOfDay(23, 59, 59)));
+assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).endOfMonth == DateTime(Date(2000, 2, 29), TimeOfDay(23, 59, 59)));
+assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).endOfMonth == DateTime(Date(2000, 6, 30), TimeOfDay(23, 59, 59)));
+--------------------
+ +/
+ @property DateTime endOfMonth() const pure nothrow
+ {
+ try
+ return DateTime(_date.endOfMonth, TimeOfDay(23, 59, 59));
+ catch(Exception e)
+ assert(0, "DateTime constructor threw.");
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(DateTime(1999, 1, 1, 0, 13, 26).endOfMonth, DateTime(1999, 1, 31, 23, 59, 59));
+ assertPred!"=="(DateTime(1999, 2, 1, 1, 14, 27).endOfMonth, DateTime(1999, 2, 28, 23, 59, 59));
+ assertPred!"=="(DateTime(2000, 2, 1, 2, 15, 28).endOfMonth, DateTime(2000, 2, 29, 23, 59, 59));
+ assertPred!"=="(DateTime(1999, 3, 1, 3, 16, 29).endOfMonth, DateTime(1999, 3, 31, 23, 59, 59));
+ assertPred!"=="(DateTime(1999, 4, 1, 4, 17, 30).endOfMonth, DateTime(1999, 4, 30, 23, 59, 59));
+ assertPred!"=="(DateTime(1999, 5, 1, 5, 18, 31).endOfMonth, DateTime(1999, 5, 31, 23, 59, 59));
+ assertPred!"=="(DateTime(1999, 6, 1, 6, 19, 32).endOfMonth, DateTime(1999, 6, 30, 23, 59, 59));
+ assertPred!"=="(DateTime(1999, 7, 1, 7, 20, 33).endOfMonth, DateTime(1999, 7, 31, 23, 59, 59));
+ assertPred!"=="(DateTime(1999, 8, 1, 8, 21, 34).endOfMonth, DateTime(1999, 8, 31, 23, 59, 59));
+ assertPred!"=="(DateTime(1999, 9, 1, 9, 22, 35).endOfMonth, DateTime(1999, 9, 30, 23, 59, 59));
+ assertPred!"=="(DateTime(1999, 10, 1, 10, 23, 36).endOfMonth, DateTime(1999, 10, 31, 23, 59, 59));
+ assertPred!"=="(DateTime(1999, 11, 1, 11, 24, 37).endOfMonth, DateTime(1999, 11, 30, 23, 59, 59));
+ assertPred!"=="(DateTime(1999, 12, 1, 12, 25, 38).endOfMonth, DateTime(1999, 12, 31, 23, 59, 59));
+
+ //Test B.C.
+ assertPred!"=="(DateTime(-1999, 1, 1, 0, 13, 26).endOfMonth, DateTime(-1999, 1, 31, 23, 59, 59));
+ assertPred!"=="(DateTime(-1999, 2, 1, 1, 14, 27).endOfMonth, DateTime(-1999, 2, 28, 23, 59, 59));
+ assertPred!"=="(DateTime(-2000, 2, 1, 2, 15, 28).endOfMonth, DateTime(-2000, 2, 29, 23, 59, 59));
+ assertPred!"=="(DateTime(-1999, 3, 1, 3, 16, 29).endOfMonth, DateTime(-1999, 3, 31, 23, 59, 59));
+ assertPred!"=="(DateTime(-1999, 4, 1, 4, 17, 30).endOfMonth, DateTime(-1999, 4, 30, 23, 59, 59));
+ assertPred!"=="(DateTime(-1999, 5, 1, 5, 18, 31).endOfMonth, DateTime(-1999, 5, 31, 23, 59, 59));
+ assertPred!"=="(DateTime(-1999, 6, 1, 6, 19, 32).endOfMonth, DateTime(-1999, 6, 30, 23, 59, 59));
+ assertPred!"=="(DateTime(-1999, 7, 1, 7, 20, 33).endOfMonth, DateTime(-1999, 7, 31, 23, 59, 59));
+ assertPred!"=="(DateTime(-1999, 8, 1, 8, 21, 34).endOfMonth, DateTime(-1999, 8, 31, 23, 59, 59));
+ assertPred!"=="(DateTime(-1999, 9, 1, 9, 22, 35).endOfMonth, DateTime(-1999, 9, 30, 23, 59, 59));
+ assertPred!"=="(DateTime(-1999, 10, 1, 10, 23, 36).endOfMonth, DateTime(-1999, 10, 31, 23, 59, 59));
+ assertPred!"=="(DateTime(-1999, 11, 1, 11, 24, 37).endOfMonth, DateTime(-1999, 11, 30, 23, 59, 59));
+ assertPred!"=="(DateTime(-1999, 12, 1, 12, 25, 38).endOfMonth, DateTime(-1999, 12, 31, 23, 59, 59));
+
+ const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ static assert(__traits(compiles, cdt.endOfMonth));
+ static assert(__traits(compiles, idt.endOfMonth));
+
+ //Verify Examples.
+ assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).endOfMonth == DateTime(Date(1999, 1, 31), TimeOfDay(23, 59, 59)));
+ assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).endOfMonth == DateTime(Date(1999, 2, 28), TimeOfDay(23, 59, 59)));
+ assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).endOfMonth == DateTime(Date(2000, 2, 29), TimeOfDay(23, 59, 59)));
+ assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).endOfMonth == DateTime(Date(2000, 6, 30), TimeOfDay(23, 59, 59)));
+ }
+
+
+ /++
+ The last day in the month that this DateTime is in.
+
+ Examples:
+--------------------
+assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).endOfMonthDay == 31);
+assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).endOfMonthDay == 28);
+assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).endOfMonthDay == 29);
+assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).endOfMonthDay == 30);
+--------------------
+ +/
+ @property ubyte endOfMonthDay() const pure nothrow
+ {
+ return _date.endOfMonthDay;
+ }
+
+ unittest
+ {
+ const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ static assert(__traits(compiles, cdt.endOfMonthDay));
+ static assert(__traits(compiles, idt.endOfMonthDay));
+
+ //Verify Examples.
+ assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).endOfMonthDay == 31);
+ assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).endOfMonthDay == 28);
+ assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).endOfMonthDay == 29);
+ assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).endOfMonthDay == 30);
+ }
+
+
+ /++
+ Whether the current year is a date in A.D.
+
+ Examples:
+--------------------
+assert(DateTime(Date(1, 1, 1), TimeOfDay(12, 7, 0)).isAD);
+assert(DateTime(Date(2010, 12, 31), TimeOfDay(0, 0, 0)).isAD);
+assert(!DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 59)).isAD);
+assert(!DateTime(Date(-2010, 1, 1), TimeOfDay(2, 2, 2)).isAD);
+--------------------
+ +/
+ @property bool isAD() const pure nothrow
+ {
+ return _date.isAD;
+ }
+
+ unittest
+ {
+ const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ static assert(__traits(compiles, cdt.isAD));
+ static assert(__traits(compiles, idt.isAD));
+
+ //Verify Examples.
+ assert(DateTime(Date(1, 1, 1), TimeOfDay(12, 7, 0)).isAD);
+ assert(DateTime(Date(2010, 12, 31), TimeOfDay(0, 0, 0)).isAD);
+ assert(!DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 59)).isAD);
+ assert(!DateTime(Date(-2010, 1, 1), TimeOfDay(2, 2, 2)).isAD);
+ }
+
+
+ /++
+ The julian day for this DateTime at the given time. For example,
+ prior to noon, 1996-03-31 would be the julian day number 2_450_173,
+ so this function returns 2_450_173, while from noon onward, it the
+ julian day number would be 2_450_174, so this function returns 2_450_174.
+ +/
+ @property long julianDay() const pure nothrow
+ {
+ if(_tod._hour < 12)
+ return _date.julianDay - 1;
+ else
+ return _date.julianDay;
+ }
+
+ unittest
+ {
+ assertPred!"=="(DateTime(Date(-4713, 11, 24), TimeOfDay(0, 0, 0)).julianDay, -1);
+ assertPred!"=="(DateTime(Date(-4713, 11, 24), TimeOfDay(12, 0, 0)).julianDay, 0);
+
+ assertPred!"=="(DateTime(Date(0, 12, 31), TimeOfDay(0, 0, 0)).julianDay, 1_721_424);
+ assertPred!"=="(DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0)).julianDay, 1_721_425);
+
+ assertPred!"=="(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).julianDay, 1_721_425);
+ assertPred!"=="(DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0)).julianDay, 1_721_426);
+
+ assertPred!"=="(DateTime(Date(1582, 10, 15), TimeOfDay(0, 0, 0)).julianDay, 2_299_160);
+ assertPred!"=="(DateTime(Date(1582, 10, 15), TimeOfDay(12, 0, 0)).julianDay, 2_299_161);
+
+ assertPred!"=="(DateTime(Date(1858, 11, 17), TimeOfDay(0, 0, 0)).julianDay, 2_400_000);
+ assertPred!"=="(DateTime(Date(1858, 11, 17), TimeOfDay(12, 0, 0)).julianDay, 2_400_001);
+
+ assertPred!"=="(DateTime(Date(1982, 1, 4), TimeOfDay(0, 0, 0)).julianDay, 2_444_973);
+ assertPred!"=="(DateTime(Date(1982, 1, 4), TimeOfDay(12, 0, 0)).julianDay, 2_444_974);
+
+ assertPred!"=="(DateTime(Date(1996, 3, 31), TimeOfDay(0, 0, 0)).julianDay, 2_450_173);
+ assertPred!"=="(DateTime(Date(1996, 3, 31), TimeOfDay(12, 0, 0)).julianDay, 2_450_174);
+
+ assertPred!"=="(DateTime(Date(2010, 8, 24), TimeOfDay(0, 0, 0)).julianDay, 2_455_432);
+ assertPred!"=="(DateTime(Date(2010, 8, 24), TimeOfDay(12, 0, 0)).julianDay, 2_455_433);
+
+ const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ static assert(__traits(compiles, cdt.julianDay));
+ static assert(__traits(compiles, idt.julianDay));
+ }
+
+
+ /++
+ The modified julian day for any time on this Date (since, the modified
+ julian day changes at midnight).
+ +/
+ @property long modJulianDay() const pure nothrow
+ {
+ return _date.modJulianDay;
+ }
+
+ unittest
+ {
+ assertPred!"=="(DateTime(Date(1858, 11, 17), TimeOfDay(0, 0, 0)).modJulianDay, 0);
+ assertPred!"=="(DateTime(Date(1858, 11, 17), TimeOfDay(12, 0, 0)).modJulianDay, 0);
+
+ assertPred!"=="(DateTime(Date(2010, 8, 24), TimeOfDay(0, 0, 0)).modJulianDay, 55_432);
+ assertPred!"=="(DateTime(Date(2010, 8, 24), TimeOfDay(12, 0, 0)).modJulianDay, 55_432);
+
+ const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ static assert(__traits(compiles, cdt.modJulianDay));
+ static assert(__traits(compiles, idt.modJulianDay));
+ }
+
+
+ /++
+ Converts this DateTime to a string with the format YYYYMMDDTHHMMSS.
+
+ Examples:
+--------------------
+assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOString() == "20100704T070612");
+assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOString() == "19981225T021500");
+assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOString() == "00000105T230959");
+assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOString() == "-00040105T000002");
+--------------------
+ +/
+ string toISOString() const nothrow
+ {
+ try
+ return format("%sT%s", _date.toISOString(), _tod.toISOString());
+ catch(Exception e)
+ assert(0, "format() threw.");
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toISOString(), "00091204T000000");
+ assertPred!"=="(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toISOString(), "00991204T050612");
+ assertPred!"=="(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toISOString(), "09991204T134459");
+ assertPred!"=="(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toISOString(), "99990704T235959");
+ assertPred!"=="(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toISOString(), "+100001020T010101");
+
+ //Test B.C.
+ assertPred!"=="(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toISOString(), "00001204T001204");
+ assertPred!"=="(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toISOString(), "-00091204T000000");
+ assertPred!"=="(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toISOString(), "-00991204T050612");
+ assertPred!"=="(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toISOString(), "-09991204T134459");
+ assertPred!"=="(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toISOString(), "-99990704T235959");
+ assertPred!"=="(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toISOString(), "-100001020T010101");
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(__traits(compiles, cdt.toISOString()));
+ static assert(__traits(compiles, idt.toISOString()));
+
+ //Verify Examples.
+ assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOString() == "20100704T070612");
+ assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOString() == "19981225T021500");
+ assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOString() == "00000105T230959");
+ assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOString() == "-00040105T000002");
+ }
+
+
+ /++
+ Converts this DateTime to a string with the format YYYY-MM-DDTHH:MM:SS.
+
+ Examples:
+--------------------
+assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOExtendedString() == "2010-07-04T07:06:12");
+assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOExtendedString() == "1998-12-25T02:15:00");
+assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOExtendedString() == "0000-01-05T23:09:59");
+assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOExtendedString() == "-0004-01-05T00:00:02");
+--------------------
+ +/
+ string toISOExtendedString() const nothrow
+ {
+ try
+ return format("%sT%s", _date.toISOExtendedString(), _tod.toISOExtendedString());
+ catch(Exception e)
+ assert(0, "format() threw.");
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toISOExtendedString(), "0009-12-04T00:00:00");
+ assertPred!"=="(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toISOExtendedString(), "0099-12-04T05:06:12");
+ assertPred!"=="(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toISOExtendedString(), "0999-12-04T13:44:59");
+ assertPred!"=="(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toISOExtendedString(), "9999-07-04T23:59:59");
+ assertPred!"=="(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toISOExtendedString(), "+10000-10-20T01:01:01");
+
+ //Test B.C.
+ assertPred!"=="(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toISOExtendedString(), "0000-12-04T00:12:04");
+ assertPred!"=="(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toISOExtendedString(), "-0009-12-04T00:00:00");
+ assertPred!"=="(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toISOExtendedString(), "-0099-12-04T05:06:12");
+ assertPred!"=="(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toISOExtendedString(), "-0999-12-04T13:44:59");
+ assertPred!"=="(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toISOExtendedString(), "-9999-07-04T23:59:59");
+ assertPred!"=="(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toISOExtendedString(), "-10000-10-20T01:01:01");
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(__traits(compiles, cdt.toISOExtendedString()));
+ static assert(__traits(compiles, idt.toISOExtendedString()));
+
+ //Verify Examples.
+ assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOExtendedString() == "2010-07-04T07:06:12");
+ assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOExtendedString() == "1998-12-25T02:15:00");
+ assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOExtendedString() == "0000-01-05T23:09:59");
+ assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOExtendedString() == "-0004-01-05T00:00:02");
+ }
+
+ /++
+ Converts this DateTime to a string with the format YYYY-Mon-DD HH:MM:SS.
+
+ Examples:
+--------------------
+assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toSimpleString() == "2010-Jul-04 07:06:12");
+assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toSimpleString() == "1998-Dec-25 02:15:00");
+assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toSimpleString() == "0000-Jan-05 23:09:59");
+assert(DateTime(Dte(-4, 1, 5), TimeOfDay(0, 0, 2)).toSimpleString() == "-0004-Jan-05 00:00:02");
+--------------------
+ +/
+ string toSimpleString() const nothrow
+ {
+ try
+ return format("%s %s", _date.toSimpleString(), _tod.toString());
+ catch(Exception e)
+ assert(0, "format() threw.");
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toSimpleString(), "0009-Dec-04 00:00:00");
+ assertPred!"=="(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toSimpleString(), "0099-Dec-04 05:06:12");
+ assertPred!"=="(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toSimpleString(), "0999-Dec-04 13:44:59");
+ assertPred!"=="(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toSimpleString(), "9999-Jul-04 23:59:59");
+ assertPred!"=="(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toSimpleString(), "+10000-Oct-20 01:01:01");
+
+ //Test B.C.
+ assertPred!"=="(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toSimpleString(), "0000-Dec-04 00:12:04");
+ assertPred!"=="(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toSimpleString(), "-0009-Dec-04 00:00:00");
+ assertPred!"=="(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toSimpleString(), "-0099-Dec-04 05:06:12");
+ assertPred!"=="(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toSimpleString(), "-0999-Dec-04 13:44:59");
+ assertPred!"=="(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toSimpleString(), "-9999-Jul-04 23:59:59");
+ assertPred!"=="(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toSimpleString(), "-10000-Oct-20 01:01:01");
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(__traits(compiles, cdt.toSimpleString()));
+ static assert(__traits(compiles, idt.toSimpleString()));
+
+ //Verify Examples.
+ assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toSimpleString() == "2010-Jul-04 07:06:12");
+ assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toSimpleString() == "1998-Dec-25 02:15:00");
+ assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toSimpleString() == "0000-Jan-05 23:09:59");
+ assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toSimpleString() == "-0004-Jan-05 00:00:02");
+ }
+
+
+ /+
+ Converts this DateTime to a string.
+ +/
+ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't
+ //have versions of toString() with extra modifiers, so we define one version
+ //with modifiers and one without.
+ string toString()
+ {
+ return toSimpleString();
+ }
+
+ /++
+ Converts this DateTime to a string.
+ +/
+ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't
+ //have versions of toString() with extra modifiers, so we define one version
+ //with modifiers and one without.
+ string toString() const nothrow
+ {
+ return toSimpleString();
+ }
+
+ unittest
+ {
+ auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
+ static assert(__traits(compiles, dt.toString()));
+ static assert(__traits(compiles, cdt.toString()));
+ static assert(__traits(compiles, idt.toString()));
+ }
+
+
+
+ /++
+ Creates a DateTime from a string with the format YYYYMMDDTHHMMSS.
+ Whitespace is stripped from the given string.
+
+ Params:
+ isoString = A string formatted in the ISO format for dates and times.
+
+ Throws:
+ DateTimeException if the given string is not in the ISO format or if
+ the resulting DateTime would not be valid.
+
+ Examples:
+--------------------
+assert(DateTime.fromISOString("20100704T070612") == DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
+assert(DateTime.fromISOString("19981225T021500") == DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)));
+assert(DateTime.fromISOString("00000105T230959") == DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)));
+assert(DateTime.fromISOString("-00040105T000002") == DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)));
+assert(DateTime.fromISOString(" 20100704T070612 ") == DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
+--------------------
+ +/
+ static DateTime fromISOString(S)(in S isoString)
+ if(isSomeString!S)
+ {
+ immutable dstr = to!dstring(strip(isoString));
+
+ enforce(dstr.length >= 15, new DateTimeException(format("Invalid ISO String: %s", isoString)));
+ auto t = dstr.indexOf('T');
+
+ enforce(t != -1, new DateTimeException(format("Invalid ISO String: %s", isoString)));
+
+ immutable date = Date.fromISOString(dstr[0..t]);
+ immutable tod = TimeOfDay.fromISOString(dstr[t+1 .. $]);
+
+ return DateTime(date, tod);
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException(DateTime.fromISOString(""));
+ assertThrown!DateTimeException(DateTime.fromISOString("20100704000000"));
+ assertThrown!DateTimeException(DateTime.fromISOString("20100704 000000"));
+ assertThrown!DateTimeException(DateTime.fromISOString("20100704t000000"));
+ assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000."));
+ assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.0"));
+
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-07-0400:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04 00:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04t00:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00."));
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.0"));
+
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-0400:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04t00:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04T00:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00."));
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.0"));
+
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-12-22T172201"));
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-Dec-22 17:22:01"));
+
+ assertPred!"=="(DateTime.fromISOString("20101222T172201"), DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01)));
+ assertPred!"=="(DateTime.fromISOString("19990706T123033"), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(DateTime.fromISOString("-19990706T123033"), DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(DateTime.fromISOString("+019990706T123033"), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(DateTime.fromISOString("19990706T123033 "), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(DateTime.fromISOString(" 19990706T123033"), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(DateTime.fromISOString(" 19990706T123033 "), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+
+ //Verify Examples.
+ assert(DateTime.fromISOString("20100704T070612") == DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
+ assert(DateTime.fromISOString("19981225T021500") == DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)));
+ assert(DateTime.fromISOString("00000105T230959") == DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)));
+ assert(DateTime.fromISOString("-00040105T000002") == DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)));
+ assert(DateTime.fromISOString(" 20100704T070612 ") == DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
+ }
+
+
+ /++
+ Creates a DateTime from a string with the format YYYY-MM-DDTHH:MM:SS.
+ Whitespace is stripped from the given string.
+
+ Params:
+ isoString = A string formatted in the ISO Extended format for dates
+ and times.
+
+ Throws:
+ DateTimeException if the given string is not in the ISO Extended
+ format or if the resulting DateTime would not be valid.
+
+ Examples:
+--------------------
+assert(DateTime.fromISOExtendedString("2010-07-04T07:06:12") ==
+ DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
+assert(DateTime.fromISOExtendedString("1998-12-25T02:15:00") ==
+ DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)));
+assert(DateTime.fromISOExtendedString("0000-01-05T23:09:59") ==
+ DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)));
+assert(DateTime.fromISOExtendedString("-0004-01-05T00:00:02") ==
+ DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)));
+assert(DateTime.fromISOExtendedString(" 2010-07-04T07:06:12 ") ==
+ DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
+--------------------
+ +/
+ static DateTime fromISOExtendedString(S)(in S isoExtString)
+ if(isSomeString!(S))
+ {
+ immutable dstr = to!dstring(strip(isoExtString));
+
+ enforce(dstr.length >= 15, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
+ auto t = dstr.indexOf('T');
+
+ enforce(t != -1, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
+
+ immutable date = Date.fromISOExtendedString(dstr[0..t]);
+ immutable tod = TimeOfDay.fromISOExtendedString(dstr[t+1 .. $]);
+
+ return DateTime(date, tod);
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException(DateTime.fromISOExtendedString(""));
+ assertThrown!DateTimeException(DateTime.fromISOExtendedString("20100704000000"));
+ assertThrown!DateTimeException(DateTime.fromISOExtendedString("20100704 000000"));
+ assertThrown!DateTimeException(DateTime.fromISOExtendedString("20100704t000000"));
+ assertThrown!DateTimeException(DateTime.fromISOExtendedString("20100704T000000."));
+ assertThrown!DateTimeException(DateTime.fromISOExtendedString("20100704T000000.0"));
+
+ assertThrown!DateTimeException(DateTime.fromISOExtendedString("2010-07:0400:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOExtendedString("2010-07-04 00:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOExtendedString("2010-07-04 00:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOExtendedString("2010-07-04t00:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOExtendedString("2010-07-04T00:00:00."));
+ assertThrown!DateTimeException(DateTime.fromISOExtendedString("2010-07-04T00:00:00.0"));
+
+ assertThrown!DateTimeException(DateTime.fromISOExtendedString("2010-Jul-0400:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOExtendedString("2010-Jul-04t00:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOExtendedString("2010-Jul-04 00:00:00."));
+ assertThrown!DateTimeException(DateTime.fromISOExtendedString("2010-Jul-04 00:00:00.0"));
+
+ assertThrown!DateTimeException(DateTime.fromISOExtendedString("20101222T172201"));
+ assertThrown!DateTimeException(DateTime.fromISOExtendedString("2010-Dec-22 17:22:01"));
+
+ assertPred!"=="(DateTime.fromISOExtendedString("2010-12-22T17:22:01"), DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01)));
+ assertPred!"=="(DateTime.fromISOExtendedString("1999-07-06T12:30:33"), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(DateTime.fromISOExtendedString("-1999-07-06T12:30:33"), DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(DateTime.fromISOExtendedString("+01999-07-06T12:30:33"), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(DateTime.fromISOExtendedString("1999-07-06T12:30:33 "), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(DateTime.fromISOExtendedString(" 1999-07-06T12:30:33"), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(DateTime.fromISOExtendedString(" 1999-07-06T12:30:33 "), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+
+ //Verify Examples.
+ assert(DateTime.fromISOExtendedString("2010-07-04T07:06:12") == DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
+ assert(DateTime.fromISOExtendedString("1998-12-25T02:15:00") == DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)));
+ assert(DateTime.fromISOExtendedString("0000-01-05T23:09:59") == DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)));
+ assert(DateTime.fromISOExtendedString("-0004-01-05T00:00:02") == DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)));
+ assert(DateTime.fromISOExtendedString(" 2010-07-04T07:06:12 ") == DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
+ }
+
+
+ /++
+ Creates a DateTime from a string with the format YYYY-Mon-DD HH:MM:SS.
+ Whitespace is stripped from the given string.
+
+ Params:
+ simpleString = A string formatted in the way that toSimpleString()
+ formats dates and times.
+
+ Throws:
+ DateTimeException if the given string is not in the correct format or if
+ the resulting DateTime would not be valid.
+
+ Examples:
+--------------------
+assert(DateTime.fromSimpleString("2010-Jul-04 07:06:12") ==
+ DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
+assert(DateTime.fromSimpleString("1998-Dec-25 02:15:00") ==
+ DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)));
+assert(DateTime.fromSimpleString("0000-Jan-05 23:09:59") ==
+ DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)));
+assert(DateTime.fromSimpleString("-0004-Jan-05 00:00:02") ==
+ DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)));
+assert(DateTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") ==
+ DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
+--------------------
+ +/
+ static DateTime fromSimpleString(S)(in S simpleString)
+ if(isSomeString!(S))
+ {
+ immutable dstr = to!dstring(strip(simpleString));
+
+ enforce(dstr.length >= 15, new DateTimeException(format("Invalid string format: %s", simpleString)));
+ auto t = dstr.indexOf(' ');
+
+ enforce(t != -1, new DateTimeException(format("Invalid string format: %s", simpleString)));
+
+ immutable date = Date.fromSimpleString(dstr[0..t]);
+ immutable tod = TimeOfDay.fromISOExtendedString(dstr[t+1 .. $]);
+
+ return DateTime(date, tod);
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException(DateTime.fromISOString(""));
+ assertThrown!DateTimeException(DateTime.fromISOString("20100704000000"));
+ assertThrown!DateTimeException(DateTime.fromISOString("20100704 000000"));
+ assertThrown!DateTimeException(DateTime.fromISOString("20100704t000000"));
+ assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000."));
+ assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.0"));
+
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-07-0400:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04 00:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04t00:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00."));
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.0"));
+
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-0400:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04t00:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04T00:00:00"));
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00."));
+ assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.0"));
+
+ assertThrown!DateTimeException(DateTime.fromSimpleString("20101222T172201"));
+ assertThrown!DateTimeException(DateTime.fromSimpleString("2010-12-22T172201"));
+
+ assertPred!"=="(DateTime.fromSimpleString("2010-Dec-22 17:22:01"), DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01)));
+ assertPred!"=="(DateTime.fromSimpleString("1999-Jul-06 12:30:33"), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(DateTime.fromSimpleString("-1999-Jul-06 12:30:33"), DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(DateTime.fromSimpleString("+01999-Jul-06 12:30:33"), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(DateTime.fromSimpleString("1999-Jul-06 12:30:33 "), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(DateTime.fromSimpleString(" 1999-Jul-06 12:30:33"), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+ assertPred!"=="(DateTime.fromSimpleString(" 1999-Jul-06 12:30:33 "), DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
+
+ //Verify Examples.
+ assert(DateTime.fromSimpleString("2010-Jul-04 07:06:12") == DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
+ assert(DateTime.fromSimpleString("1998-Dec-25 02:15:00") == DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)));
+ assert(DateTime.fromSimpleString("0000-Jan-05 23:09:59") == DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)));
+ assert(DateTime.fromSimpleString("-0004-Jan-05 00:00:02") == DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)));
+ assert(DateTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") == DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
+ }
+
+
+ //TODO Add function which takes a user-specified time format and produces a DateTime
+
+ //TODO Add function which takes pretty much any time-string and produces a DateTime
+ // Obviously, it will be less efficient, and it probably won't manage _every_
+ // possible date format, but a smart conversion function would be nice.
+
+
+ /++
+ Returns the DateTime farthest in the past which is representable by DateTime.
+ +/
+ @property static DateTime min() pure nothrow
+ out(result)
+ {
+ assert(result._date == Date.min);
+ assert(result._tod == TimeOfDay.min);
+ }
+ body
+ {
+ auto dt = DateTime.init;
+ dt._date._year = short.min;
+ dt._date._month = Month.jan;
+ dt._date._day = 1;
+
+ return dt;
+ }
+
+ unittest
+ {
+ assert(DateTime.min.year < 0);
+ assert(DateTime.min < DateTime.max);
+ }
+
+
+ /++
+ Returns the DateTime farthest in the future which is representable by DateTime.
+ +/
+ @property static DateTime max() pure nothrow
+ out(result)
+ {
+ assert(result._date == Date.max);
+ assert(result._tod == TimeOfDay.max);
+ }
+ body
+ {
+ auto dt = DateTime.init;
+ dt._date._year = short.max;
+ dt._date._month = Month.dec;
+ dt._date._day = 31;
+ dt._tod._hour = TimeOfDay.maxHour;
+ dt._tod._minute = TimeOfDay.maxMinute;
+ dt._tod._second = TimeOfDay.maxSecond;
+
+ return dt;
+ }
+
+ unittest
+ {
+ assert(DateTime.max.year > 0);
+ assert(DateTime.max > DateTime.min);
+ }
+
+
+private:
+
+ /++
+ Add seconds to the time of day. Negative values will subtract. If the
+ number of seconds overflows (or underflows), then the seconds will wrap,
+ increasing (or decreasing) the number of minutes accordingly. The
+ same goes for any larger units.
+
+ Params:
+ seconds = The number of seconds to add to this DateTime.
+ +/
+ ref DateTime addSeconds(long seconds) pure nothrow
+ {
+ long hnsecs = convert!("seconds", "hnsecs")(seconds);
+ hnsecs += convert!("hours", "hnsecs")(_tod._hour);
+ hnsecs += convert!("minutes", "hnsecs")(_tod._minute);
+ hnsecs += convert!("seconds", "hnsecs")(_tod._second);
+
+ auto days = splitUnitsFromHNSecs!"days"(hnsecs);
+
+ if(hnsecs < 0)
+ {
+ hnsecs += convert!("days", "hnsecs")(1);
+ --days;
+ }
+
+ _date.addDays(days);
+
+ immutable newHours = splitUnitsFromHNSecs!"hours"(hnsecs);
+ immutable newMinutes = splitUnitsFromHNSecs!"minutes"(hnsecs);
+ immutable newSeconds = splitUnitsFromHNSecs!"seconds"(hnsecs);
+
+ _tod._hour = cast(ubyte)newHours;
+ _tod._minute = cast(ubyte)newMinutes;
+ _tod._second = cast(ubyte)newSeconds;
+
+ return this;
+ }
+
+ unittest
+ {
+ static void testDT(DateTime orig, int seconds, in DateTime expected, size_t line = __LINE__)
+ {
+ orig.addSeconds(seconds);
+ assertPred!"=="(orig, expected, "", __FILE__, line);
+ }
+
+ //Test A.D.
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 0, DateTime(1999, 7, 6, 12, 30, 33));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 1, DateTime(1999, 7, 6, 12, 30, 34));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 2, DateTime(1999, 7, 6, 12, 30, 35));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 3, DateTime(1999, 7, 6, 12, 30, 36));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 4, DateTime(1999, 7, 6, 12, 30, 37));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 5, DateTime(1999, 7, 6, 12, 30, 38));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 10, DateTime(1999, 7, 6, 12, 30, 43));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 15, DateTime(1999, 7, 6, 12, 30, 48));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 26, DateTime(1999, 7, 6, 12, 30, 59));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 27, DateTime(1999, 7, 6, 12, 31, 0));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 30, DateTime(1999, 7, 6, 12, 31, 3));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 59, DateTime(1999, 7, 6, 12, 31, 32));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 60, DateTime(1999, 7, 6, 12, 31, 33));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 61, DateTime(1999, 7, 6, 12, 31, 34));
+
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 1766, DateTime(1999, 7, 6, 12, 59, 59));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 1767, DateTime(1999, 7, 6, 13, 0, 0));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 1768, DateTime(1999, 7, 6, 13, 0, 1));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 2007, DateTime(1999, 7, 6, 13, 4, 0));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 3599, DateTime(1999, 7, 6, 13, 30, 32));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 3600, DateTime(1999, 7, 6, 13, 30, 33));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 3601, DateTime(1999, 7, 6, 13, 30, 34));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), 7200, DateTime(1999, 7, 6, 14, 30, 33));
+ testDT(DateTime(1999, 7, 6, 23, 0, 0), 432_123, DateTime(1999, 7, 11, 23, 2, 3));
+
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), -1, DateTime(1999, 7, 6, 12, 30, 32));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), -2, DateTime(1999, 7, 6, 12, 30, 31));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), -3, DateTime(1999, 7, 6, 12, 30, 30));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), -4, DateTime(1999, 7, 6, 12, 30, 29));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), -5, DateTime(1999, 7, 6, 12, 30, 28));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), -10, DateTime(1999, 7, 6, 12, 30, 23));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), -15, DateTime(1999, 7, 6, 12, 30, 18));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), -33, DateTime(1999, 7, 6, 12, 30, 0));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), -34, DateTime(1999, 7, 6, 12, 29, 59));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), -35, DateTime(1999, 7, 6, 12, 29, 58));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), -59, DateTime(1999, 7, 6, 12, 29, 34));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), -60, DateTime(1999, 7, 6, 12, 29, 33));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), -61, DateTime(1999, 7, 6, 12, 29, 32));
+
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), -1833, DateTime(1999, 7, 6, 12, 0, 0));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), -1834, DateTime(1999, 7, 6, 11, 59, 59));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), -3600, DateTime(1999, 7, 6, 11, 30, 33));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), -3601, DateTime(1999, 7, 6, 11, 30, 32));
+ testDT(DateTime(1999, 7, 6, 12, 30, 33), -5134, DateTime(1999, 7, 6, 11, 4, 59));
+ testDT(DateTime(1999, 7, 6, 23, 0, 0), -432_123, DateTime(1999, 7, 1, 22, 57, 57));
+
+ testDT(DateTime(1999, 7, 6, 12, 30, 0), 1, DateTime(1999, 7, 6, 12, 30, 1));
+ testDT(DateTime(1999, 7, 6, 12, 30, 0), 0, DateTime(1999, 7, 6, 12, 30, 0));
+ testDT(DateTime(1999, 7, 6, 12, 30, 0), -1, DateTime(1999, 7, 6, 12, 29, 59));
+
+ testDT(DateTime(1999, 7, 6, 12, 0, 0), 1, DateTime(1999, 7, 6, 12, 0, 1));
+ testDT(DateTime(1999, 7, 6, 12, 0, 0), 0, DateTime(1999, 7, 6, 12, 0, 0));
+ testDT(DateTime(1999, 7, 6, 12, 0, 0), -1, DateTime(1999, 7, 6, 11, 59, 59));
+
+ testDT(DateTime(1999, 7, 6, 0, 0, 0), 1, DateTime(1999, 7, 6, 0, 0, 1));
+ testDT(DateTime(1999, 7, 6, 0, 0, 0), 0, DateTime(1999, 7, 6, 0, 0, 0));
+ testDT(DateTime(1999, 7, 6, 0, 0, 0), -1, DateTime(1999, 7, 5, 23, 59, 59));
+
+ testDT(DateTime(1999, 7, 5, 23, 59, 59), 1, DateTime(1999, 7, 6, 0, 0, 0));
+ testDT(DateTime(1999, 7, 5, 23, 59, 59), 0, DateTime(1999, 7, 5, 23, 59, 59));
+ testDT(DateTime(1999, 7, 5, 23, 59, 59), -1, DateTime(1999, 7, 5, 23, 59, 58));
+
+ testDT(DateTime(1998, 12, 31, 23, 59, 59), 1, DateTime(1999, 1, 1, 0, 0, 0));
+ testDT(DateTime(1998, 12, 31, 23, 59, 59), 0, DateTime(1998, 12, 31, 23, 59, 59));
+ testDT(DateTime(1998, 12, 31, 23, 59, 59), -1, DateTime(1998, 12, 31, 23, 59, 58));
+
+ testDT(DateTime(1998, 1, 1, 0, 0, 0), 1, DateTime(1998, 1, 1, 0, 0, 1));
+ testDT(DateTime(1998, 1, 1, 0, 0, 0), 0, DateTime(1998, 1, 1, 0, 0, 0));
+ testDT(DateTime(1998, 1, 1, 0, 0, 0), -1, DateTime(1997, 12, 31, 23, 59, 59));
+
+ //Test B.C.
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 0, DateTime(-1999, 7, 6, 12, 30, 33));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1, DateTime(-1999, 7, 6, 12, 30, 34));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 2, DateTime(-1999, 7, 6, 12, 30, 35));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3, DateTime(-1999, 7, 6, 12, 30, 36));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 4, DateTime(-1999, 7, 6, 12, 30, 37));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 5, DateTime(-1999, 7, 6, 12, 30, 38));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 10, DateTime(-1999, 7, 6, 12, 30, 43));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 15, DateTime(-1999, 7, 6, 12, 30, 48));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 26, DateTime(-1999, 7, 6, 12, 30, 59));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 27, DateTime(-1999, 7, 6, 12, 31, 0));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 30, DateTime(-1999, 7, 6, 12, 31, 3));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 59, DateTime(-1999, 7, 6, 12, 31, 32));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 60, DateTime(-1999, 7, 6, 12, 31, 33));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 61, DateTime(-1999, 7, 6, 12, 31, 34));
+
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1766, DateTime(-1999, 7, 6, 12, 59, 59));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1767, DateTime(-1999, 7, 6, 13, 0, 0));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1768, DateTime(-1999, 7, 6, 13, 0, 1));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 2007, DateTime(-1999, 7, 6, 13, 4, 0));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3599, DateTime(-1999, 7, 6, 13, 30, 32));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3600, DateTime(-1999, 7, 6, 13, 30, 33));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3601, DateTime(-1999, 7, 6, 13, 30, 34));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), 7200, DateTime(-1999, 7, 6, 14, 30, 33));
+ testDT(DateTime(-1999, 7, 6, 23, 0, 0), 432_123, DateTime(-1999, 7, 11, 23, 2, 3));
+
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1, DateTime(-1999, 7, 6, 12, 30, 32));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), -2, DateTime(-1999, 7, 6, 12, 30, 31));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3, DateTime(-1999, 7, 6, 12, 30, 30));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), -4, DateTime(-1999, 7, 6, 12, 30, 29));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), -5, DateTime(-1999, 7, 6, 12, 30, 28));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), -10, DateTime(-1999, 7, 6, 12, 30, 23));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), -15, DateTime(-1999, 7, 6, 12, 30, 18));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), -33, DateTime(-1999, 7, 6, 12, 30, 0));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), -34, DateTime(-1999, 7, 6, 12, 29, 59));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), -35, DateTime(-1999, 7, 6, 12, 29, 58));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), -59, DateTime(-1999, 7, 6, 12, 29, 34));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), -60, DateTime(-1999, 7, 6, 12, 29, 33));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), -61, DateTime(-1999, 7, 6, 12, 29, 32));
+
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1833, DateTime(-1999, 7, 6, 12, 0, 0));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1834, DateTime(-1999, 7, 6, 11, 59, 59));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3600, DateTime(-1999, 7, 6, 11, 30, 33));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3601, DateTime(-1999, 7, 6, 11, 30, 32));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), -5134, DateTime(-1999, 7, 6, 11, 4, 59));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 33), -7200, DateTime(-1999, 7, 6, 10, 30, 33));
+ testDT(DateTime(-1999, 7, 6, 23, 0, 0), -432_123, DateTime(-1999, 7, 1, 22, 57, 57));
+
+ testDT(DateTime(-1999, 7, 6, 12, 30, 0), 1, DateTime(-1999, 7, 6, 12, 30, 1));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 0), 0, DateTime(-1999, 7, 6, 12, 30, 0));
+ testDT(DateTime(-1999, 7, 6, 12, 30, 0), -1, DateTime(-1999, 7, 6, 12, 29, 59));
+
+ testDT(DateTime(-1999, 7, 6, 12, 0, 0), 1, DateTime(-1999, 7, 6, 12, 0, 1));
+ testDT(DateTime(-1999, 7, 6, 12, 0, 0), 0, DateTime(-1999, 7, 6, 12, 0, 0));
+ testDT(DateTime(-1999, 7, 6, 12, 0, 0), -1, DateTime(-1999, 7, 6, 11, 59, 59));
+
+ testDT(DateTime(-1999, 7, 6, 0, 0, 0), 1, DateTime(-1999, 7, 6, 0, 0, 1));
+ testDT(DateTime(-1999, 7, 6, 0, 0, 0), 0, DateTime(-1999, 7, 6, 0, 0, 0));
+ testDT(DateTime(-1999, 7, 6, 0, 0, 0), -1, DateTime(-1999, 7, 5, 23, 59, 59));
+
+ testDT(DateTime(-1999, 7, 5, 23, 59, 59), 1, DateTime(-1999, 7, 6, 0, 0, 0));
+ testDT(DateTime(-1999, 7, 5, 23, 59, 59), 0, DateTime(-1999, 7, 5, 23, 59, 59));
+ testDT(DateTime(-1999, 7, 5, 23, 59, 59), -1, DateTime(-1999, 7, 5, 23, 59, 58));
+
+ testDT(DateTime(-2000, 12, 31, 23, 59, 59), 1, DateTime(-1999, 1, 1, 0, 0, 0));
+ testDT(DateTime(-2000, 12, 31, 23, 59, 59), 0, DateTime(-2000, 12, 31, 23, 59, 59));
+ testDT(DateTime(-2000, 12, 31, 23, 59, 59), -1, DateTime(-2000, 12, 31, 23, 59, 58));
+
+ testDT(DateTime(-2000, 1, 1, 0, 0, 0), 1, DateTime(-2000, 1, 1, 0, 0, 1));
+ testDT(DateTime(-2000, 1, 1, 0, 0, 0), 0, DateTime(-2000, 1, 1, 0, 0, 0));
+ testDT(DateTime(-2000, 1, 1, 0, 0, 0), -1, DateTime(-2001, 12, 31, 23, 59, 59));
+
+ //Test Both
+ testDT(DateTime(1, 1, 1, 0, 0, 0), -1, DateTime(0, 12, 31, 23, 59, 59));
+ testDT(DateTime(0, 12, 31, 23, 59, 59), 1, DateTime(1, 1, 1, 0, 0, 0));
+
+ testDT(DateTime(0, 1, 1, 0, 0, 0), -1, DateTime(-1, 12, 31, 23, 59, 59));
+ testDT(DateTime(-1, 12, 31, 23, 59, 59), 1, DateTime(0, 1, 1, 0, 0, 0));
+
+ testDT(DateTime(-1, 1, 1, 11, 30, 33), 63_165_600L, DateTime(1, 1, 1, 13, 30, 33));
+ testDT(DateTime(1, 1, 1, 13, 30, 33), -63_165_600L, DateTime(-1, 1, 1, 11, 30, 33));
+
+ testDT(DateTime(-1, 1, 1, 11, 30, 33), 63_165_617L, DateTime(1, 1, 1, 13, 30, 50));
+ testDT(DateTime(1, 1, 1, 13, 30, 50), -63_165_617L, DateTime(-1, 1, 1, 11, 30, 33));
+
+ const cdt = DateTime(1999, 7, 6, 12, 30, 33);
+ immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
+ static assert(!__traits(compiles, cdt.addSeconds(4)));
+ static assert(!__traits(compiles, idt.addSeconds(4)));
+ }
+
+
+ Date _date;
+ TimeOfDay _tod;
+}
+
+
+
+/++
+ SysTime is the type used when you want to get the current time from the system
+ or if you're doing anything that involves time zones. Unlike DateTime, time
+ zone is an integral part of SysTime (though if all you care about is local
+ time, you can pretty much ignore time zones, and it will work, since it
+ defaults to using the local time zone). It holds its internal time in std time
+ (hnsecs since midnight, January 1st, 1 A.D. UTC), so it interfaces well with the
+ system time. However, that means that, unlike DateTime, it is not optimized
+ for calendar operations, and getting individual units from it such as years
+ or days is going to involve conversions and be less efficient.
+
+ Basically, if you care about calendar operations and don't necessarily care
+ about time zones, then DateTime would be the type to use. However, if what
+ you care about is the system time, then SysTime is the type to use.
+
+ $(D Clock.currTime()) will return the current time as a SysTime. If you want
+ to convert a SysTime to a Date or DateTime, simply cast it. And if you ever
+ want to convert a Date or DateTime to a SysTime, use SysTime's constructor,
+ and you can pass in the intended time zone with it (or don't pass in a
+ TimeZone, and the local time zone will be used).
+
+ If you care about using time zones other than local time or UTC, you can use
+ PosixTimeZone on Posix systems (or on Windows, if you provide the TZ database
+ files), and you can use WindowsTimeZone on Windows systems. The time in SysTime
+ is kept internally in hnsecs from midnight, January 1st, 1 A.D. UTC. So, you
+ never get conversion errors when changing the time zone of a SysTime (since,
+ if the hnecs were kept in local time, DST would cause problems with conversions).
+ LocalTime is the TimeZone class which represents the local time, and UTC is the
+ TimeZone class which represents UTC. SysTime uses LocalTime if no TimeZone is
+ provided. For more details on time zones, look at the documentation for
+ TimeZone, PosixTimeZone, and WindowsTimeZone.
+
+ SysTime's range is from approximately 29,000 B.C. to 29,000 A.D.
+ +/
+struct SysTime
+{
+public:
+
+ /++
+ Params:
+ dateTime = The DateTime to use to set this SysTime's internal std
+ time. As DateTime has no concept of time zone, tz is used
+ as its time zone.
+ tz = The TimeZone to use for this SysTime. If null, LocalTime
+ will be used. The given DateTime is assumed to be in the
+ given time zone.
+ +/
+ this(in DateTime dateTime, immutable TimeZone tz = null) nothrow
+ {
+ try
+ this(dateTime, FracSec.from!"hnsecs"(0), tz);
+ catch(Exception e)
+ assert(0, "FracSec's constructor threw when it shouldn't have.");
+ }
+
+ unittest
+ {
+ assertPred!"=="(SysTime(DateTime.init, UTC())._stdTime, 0);
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 12, 30, 33), UTC())._stdTime, 450_330_000_000L);
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 12, 30, 33), UTC())._stdTime, -413_670_000_000L);
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 0, 0, 0), UTC())._stdTime, 0);
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 0, 0, 1), UTC())._stdTime, 10_000_000L);
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC())._stdTime, -10_000_000L);
+
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 0, 0, 0), new SimpleTimeZone(-60)).stdTime, 36_000_000_000L);
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 0, 0, 0), new SimpleTimeZone(0)).stdTime, 0);
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 0, 0, 0), new SimpleTimeZone(60)).stdTime, -36_000_000_000L);
+ }
+
+
+ /++
+ Params:
+ dateTime = The DateTime to use to set this SysTime's internal std time.
+ As DateTime has no concept of time zone, tz is used as its
+ time zone.
+ fsec = The fractional seconds portion of the time.
+ tz = The TimeZone to use for this SysTime. If null, LocalTime will
+ be used. The given DateTime is assumed to be in the given
+ time zone.
+ +/
+ this(in DateTime dateTime, in FracSec fsec, immutable TimeZone tz = null) nothrow
+ {
+ if(tz is null)
+ _timezone = LocalTime();
+ else
+ _timezone = tz;
+
+ try
+ {
+ immutable dateDiff = (dateTime.date - Date(1, 1, 1)).total!"hnsecs";
+ immutable todDiff = (dateTime.timeOfDay - TimeOfDay(0, 0, 0)).total!"hnsecs";
+
+ immutable adjustedTime = dateDiff + todDiff + fsec.hnsecs;
+ immutable standardTime = _timezone.tzToUTC(adjustedTime);
+
+ this(standardTime, _timezone.get);
+ }
+ catch(Exception e)
+ assert(0, "Date, TimeOfDay, or DateTime's constructor threw when it shouldn't have.");
+ }
+
+ unittest
+ {
+ assertPred!"=="(SysTime(DateTime.init, FracSec.init, UTC())._stdTime, 0);
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 12, 30, 33), FracSec.init, UTC())._stdTime, 450_330_000_000L);
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 12, 30, 33), FracSec.init, UTC())._stdTime, -413_670_000_000L);
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"msecs"(1), UTC())._stdTime, 10_000L);
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"msecs"(999), UTC())._stdTime, -10_000L);
+
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999), UTC()).stdTime, -1);
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1), UTC()).stdTime, -9_999_999);
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(0), UTC()).stdTime, -10_000_000);
+ }
+
+
+ /++
+ Params:
+ date = The Date to use to set this SysTime's internal std time.
+ As Date has no concept of time zone, tz is used as its
+ time zone.
+ tz = The TimeZone to use for this SysTime. If null, LocalTime will
+ be used. The given Date is assumed to be in the given time zone.
+ +/
+ this(in Date date, immutable TimeZone tz = null) nothrow
+ {
+ if(tz is null)
+ _timezone = LocalTime();
+ else
+ _timezone = tz;
+
+ try
+ {
+ immutable adjustedTime = (date - Date(1, 1, 1)).total!"hnsecs";
+ immutable standardTime = _timezone.tzToUTC(adjustedTime);
+
+ this(standardTime, _timezone.get);
+ }
+ catch(Exception e)
+ assert(0, "Date's constructor through when it shouldn't have");
+ }
+
+ unittest
+ {
+ assertPred!"=="(SysTime(Date.init, UTC())._stdTime, 0);
+ assertPred!"=="(SysTime(Date(1, 1, 1), UTC())._stdTime, 0);
+ assertPred!"=="(SysTime(Date(1, 1, 2), UTC())._stdTime, 864000000000);
+ assertPred!"=="(SysTime(Date(0, 12, 31), UTC())._stdTime, -864000000000);
+ }
+
+
+ /++
+ Note:
+ Whereas the other constructors take in the given date/time, assume
+ that it's in the given time zone, and convert it to hnsecs in UTC
+ since midnight, January 1st, 1 A.D. UTC - i.e. std time - this constructor
+ takes a std time, which is specifically already in UTC, so no conversion
+ takes place. Of course, the various getter properties and functions
+ will use the given time zone's conversion function to convert the
+ results to that time zone, but no conversion of the arguments to
+ this constructor takes place.
+
+ Params:
+ stdTime = The number of hnsecs since midnight, January 1st, 1 A.D. UTC.
+ tz = The TimeZone to use for this SysTime. If null, LocalTime will be used.
+ +/
+ this(long stdTime, immutable TimeZone tz = null) pure nothrow
+ {
+ _stdTime = stdTime;
+
+ if(tz is null)
+ _timezone = LocalTime();
+ else
+ _timezone = tz;
+ }
+
+ unittest
+ {
+ assertPred!"=="(SysTime(0)._stdTime, 0);
+ }
+
+
+ /++
+ Params:
+ rhs = The SysTime to assign to this one.
+ +/
+ ref SysTime opAssign(const ref SysTime rhs) pure nothrow
+ {
+ _stdTime = rhs._stdTime;
+ _timezone = rhs._timezone.get;
+
+ return this;
+ }
+
+
+ /++
+ Params:
+ rhs = The SysTime to assign to this one.
+ +/
+ ref SysTime opAssign(SysTime rhs) pure nothrow
+ {
+ _stdTime = rhs._stdTime;
+ _timezone = rhs._timezone.get;
+
+ return this;
+ }
+
+
+ /++
+ Checks for equality between this SysTime and the given
+ SysTime.
+
+ Note that the time zone is ignored. Only the internal
+ std times (which are in UTC) are compared.
+ +/
+ bool opEquals(const ref SysTime rhs) const pure nothrow
+ {
+ return _stdTime == rhs._stdTime;
+ }
+
+ unittest
+ {
+ auto a = SysTime(DateTime.init, UTC());
+ auto b = SysTime(0, UTC());
+ assert(a == b);
+ assertPred!"=="(a, b);
+ assertPred!"=="(SysTime(DateTime.init, UTC()), SysTime(0, UTC()));
+ assertPred!"=="(SysTime(Date.init, UTC()), SysTime(0, UTC()));
+ assertPred!"=="(SysTime(0), SysTime(0));
+
+ assertPred!"=="(SysTime(Date(1999, 1, 1)), SysTime(Date(1999, 1, 1)));
+ assertPred!"=="(SysTime(Date(1999, 1, 1)), SysTime(Date(1999, 1, 1)));
+ assertPred!"=="(SysTime(Date(1, 7, 1)), SysTime(Date(1, 7, 1)));
+ assertPred!"=="(SysTime(Date(1, 1, 6)), SysTime(Date(1, 1, 6)));
+
+ assertPred!"=="(SysTime(Date(1999, 7, 1)), SysTime(Date(1999, 7, 1)));
+ assertPred!"=="(SysTime(Date(1999, 7, 6)), SysTime(Date(1999, 7, 6)));
+
+ assertPred!"=="(SysTime(Date(1, 7, 6)), SysTime(Date(1, 7, 6)));
+
+ assertPred!"=="(SysTime(DateTime(1999, 1, 1, 0, 0, 0)), SysTime(Date(1999, 1, 1)));
+ assertPred!"=="(SysTime(Date(1999, 1, 1)), SysTime(DateTime(1999, 1, 1, 0, 0, 0)));
+
+ assertPred!"!="(SysTime(DateTime(1999, 1, 1, 11, 30, 20)), SysTime(Date(1999, 1, 1)));
+ assertPred!"!="(SysTime(Date(1999, 1, 1)), SysTime(DateTime(1999, 1, 1, 11, 30, 20)));
+
+ assertPred!"=="(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0))));
+ assertPred!"=="(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0))));
+ assertPred!"=="(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 0))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 0))));
+ assertPred!"=="(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))));
+
+ assertPred!"=="(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))));
+ assertPred!"=="(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))));
+
+ assertPred!"=="(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))));
+ assertPred!"=="(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))));
+
+ {
+ auto sysUTC = SysTime(Date(1999, 1, 1));
+ sysUTC.timezone = UTC();
+
+ auto sysLocal = SysTime(Date(1999, 1, 1));
+ sysUTC.timezone = LocalTime();
+
+ assertPred!"=="(sysUTC, sysLocal);
+ assertPred!"=="(sysLocal, sysUTC);
+
+ assertPred!"!="(SysTime(Date(1999, 1, 1), UTC()), SysTime(Date(1999, 1, 1), LocalTime()));
+ assertPred!"!="(SysTime(Date(1999, 7, 1), LocalTime()), SysTime(Date(1999, 7, 1), UTC()));
+ }
+
+ {
+ auto sysUTC = SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)));
+ sysUTC.timezone = UTC();
+
+ auto sysSimple = SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)));
+ sysSimple.timezone = new SimpleTimeZone(-360);
+
+ assertPred!"=="(sysUTC, sysSimple);
+ assertPred!"=="(sysSimple, sysUTC);
+
+ assertPred!"!="(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), UTC()),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), sysSimple.timezone));
+ assertPred!"!="(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), sysSimple.timezone),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), UTC()));
+ }
+
+ {
+ auto sysUTC = SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), UTC());
+ auto sysSimple = SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), new SimpleTimeZone(240));
+
+ assertPred!"!="(sysUTC, sysSimple);
+ assertPred!"!="(sysSimple, sysUTC);
+
+ sysUTC = SysTime(DateTime(Date(1999, 7, 5), TimeOfDay(20, 0, 0)), UTC());
+
+ assertPred!"=="(sysUTC, sysSimple);
+ assertPred!"=="(sysSimple, sysUTC);
+ }
+
+ auto st = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
+ static assert(__traits(compiles, st == st));
+ static assert(__traits(compiles, st == cst));
+ //static assert(__traits(compiles, st == ist));
+ static assert(__traits(compiles, cst == st));
+ static assert(__traits(compiles, cst == cst));
+ //static assert(__traits(compiles, cst == ist));
+ //static assert(__traits(compiles, ist == st));
+ //static assert(__traits(compiles, ist == cst));
+ //static assert(__traits(compiles, ist == ist));
+ }
+
+
+ /++
+ Compares this SysTime with the given SysTime.
+
+ Time zone is irrelevant to comparing SysTimes.
+
+ Returns:
+ $(TABLE
+ $(TR $(TD this < rhs) $(TD < 0))
+ $(TR $(TD this == rhs) $(TD 0))
+ $(TR $(TD this > rhs) $(TD > 0))
+ )
+ +/
+ int opCmp(in SysTime rhs) const pure nothrow
+ {
+ if(_stdTime < rhs._stdTime)
+ return -1;
+ if(_stdTime > rhs._stdTime)
+ return 1;
+
+ return 0;
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!("opCmp", "==")(SysTime(DateTime.init, UTC()), SysTime(0));
+ assertPred!("opCmp", "==")(SysTime(Date.init, UTC()), SysTime(0));
+
+ assertPred!("opCmp", "==")(SysTime(Date(1999, 1, 1)), SysTime(Date(1999, 1, 1)));
+ assertPred!("opCmp", "==")(SysTime(Date(1999, 1, 1)), SysTime(Date(1999, 1, 1)));
+ assertPred!("opCmp", "==")(SysTime(Date(1, 7, 1)), SysTime(Date(1, 7, 1)));
+ assertPred!("opCmp", "==")(SysTime(Date(1, 1, 6)), SysTime(Date(1, 1, 6)));
+
+ assertPred!("opCmp", "==")(SysTime(Date(1999, 7, 1)), SysTime(Date(1999, 7, 1)));
+ assertPred!("opCmp", "==")(SysTime(Date(1999, 7, 6)), SysTime(Date(1999, 7, 6)));
+
+ assertPred!("opCmp", "==")(SysTime(Date(1, 7, 6)), SysTime(Date(1, 7, 6)));
+
+ assertPred!("opCmp", ">")(SysTime(DateTime(1999, 1, 1, 11, 30, 20)), SysTime(Date(1999, 1, 1)));
+ assertPred!("opCmp", "<")(SysTime(Date(1999, 1, 1)), SysTime(DateTime(1999, 1, 1, 11, 30, 20)));
+
+ assertPred!("opCmp", "<")(SysTime(Date(1999, 7, 6)), SysTime(Date(2000, 7, 6)));
+ assertPred!("opCmp", ">")(SysTime(Date(2000, 7, 6)), SysTime(Date(1999, 7, 6)));
+ assertPred!("opCmp", "<")(SysTime(Date(1999, 7, 6)), SysTime(Date(1999, 8, 6)));
+ assertPred!("opCmp", ">")(SysTime(Date(1999, 8, 6)), SysTime(Date(1999, 7, 6)));
+ assertPred!("opCmp", "<")(SysTime(Date(1999, 7, 6)), SysTime(Date(1999, 7, 7)));
+ assertPred!("opCmp", ">")(SysTime(Date(1999, 7, 7)), SysTime(Date(1999, 7, 6)));
+
+ assertPred!("opCmp", "<")(SysTime(Date(1999, 8, 7)), SysTime(Date(2000, 7, 6)));
+ assertPred!("opCmp", ">")(SysTime(Date(2000, 8, 6)), SysTime(Date(1999, 7, 7)));
+ assertPred!("opCmp", "<")(SysTime(Date(1999, 7, 7)), SysTime(Date(2000, 7, 6)));
+ assertPred!("opCmp", ">")(SysTime(Date(2000, 7, 6)), SysTime(Date(1999, 7, 7)));
+ assertPred!("opCmp", "<")(SysTime(Date(1999, 7, 7)), SysTime(Date(1999, 8, 6)));
+ assertPred!("opCmp", ">")(SysTime(Date(1999, 8, 6)), SysTime(Date(1999, 7, 7)));
+
+ assertPred!("opCmp", "==")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0))));
+ assertPred!("opCmp", "==")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0))));
+ assertPred!("opCmp", "==")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 0))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 0)))),
+ assertPred!("opCmp", "==")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))));
+
+ assertPred!("opCmp", "==")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))));
+ assertPred!("opCmp", "==")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))));
+
+ assertPred!("opCmp", "==")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))));
+ assertPred!("opCmp", "==")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))));
+
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))));
+
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))));
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))));
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))));
+
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))));
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))));
+
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))),
+ SysTime(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))));
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))),
+ SysTime(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))));
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))),
+ SysTime(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))));
+
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))),
+ SysTime(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))));
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))),
+ SysTime(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))));
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))),
+ SysTime(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))));
+
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))));
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))),
+ SysTime(DateTime(Date(1999, 7, 7), TimeOfDay(12, 31, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))),
+ SysTime(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))));
+
+ //Test B.C.
+ assertPred!("opCmp", "==")(SysTime(DateTime(Date(-1, 1, 1), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1, 1, 1), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", "==")(SysTime(DateTime(Date(-1, 7, 1), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1, 7, 1), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", "==")(SysTime(DateTime(Date(-1, 1, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1, 1, 6), TimeOfDay(12, 30, 33))));
+
+ assertPred!("opCmp", "==")(SysTime(DateTime(Date(-1999, 7, 1), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1999, 7, 1), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", "==")(SysTime(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))));
+
+ assertPred!("opCmp", "==")(SysTime(DateTime(Date(-1, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1, 7, 6), TimeOfDay(12, 30, 33))));
+
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))));
+
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(-2000, 8, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))));
+
+ //Test Both
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))));
+
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))));
+
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))));
+
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33))));
+
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(1999, 6, 6), TimeOfDay(12, 30, 33))));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(1999, 6, 8), TimeOfDay(12, 30, 33))),
+ SysTime(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))));
+
+ {
+ auto sysUTC = SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)));
+ sysUTC.timezone = UTC();
+
+ auto sysSimple = SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)));
+ sysSimple.timezone = new SimpleTimeZone(-360);
+
+ assertPred!("opCmp", "==")(sysUTC, sysSimple);
+ assertPred!("opCmp", "==")(sysSimple, sysUTC);
+
+ assertPred!("opCmp", "<")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), UTC()),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), sysSimple.timezone));
+ assertPred!("opCmp", ">")(SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), sysSimple.timezone),
+ SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), UTC()));
+ }
+
+ {
+ auto sysUTC = SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), UTC());
+ auto sysSimple = SysTime(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), new SimpleTimeZone(240));
+
+ assertPred!("opCmp", ">")(sysUTC, sysSimple);
+ assertPred!("opCmp", "<")(sysSimple, sysUTC);
+
+ sysUTC = SysTime(DateTime(Date(1999, 7, 5), TimeOfDay(20, 0, 0)), UTC());
+
+ assertPred!("opCmp", "==")(sysUTC, sysSimple);
+ assertPred!("opCmp", "==")(sysSimple, sysUTC);
+ }
+
+ auto st = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
+ static assert(__traits(compiles, st.opCmp(st)));
+ static assert(__traits(compiles, st.opCmp(cst)));
+ //static assert(__traits(compiles, st.opCmp(ist)));
+ static assert(__traits(compiles, cst.opCmp(st)));
+ static assert(__traits(compiles, cst.opCmp(cst)));
+ //static assert(__traits(compiles, cst.opCmp(ist)));
+ //static assert(__traits(compiles, ist.opCmp(st)));
+ //static assert(__traits(compiles, ist.opCmp(cst)));
+ //static assert(__traits(compiles, ist.opCmp(ist)));
+ }
+
+
+ /++
+ Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
+ are B.C.
+ +/
+ @property short year() const nothrow
+ {
+ return (cast(Date)this).year;
+ }
+
+ unittest
+ {
+ assertPred!"=="(SysTime(0, UTC()).year, 1);
+ assertPred!"=="(SysTime(1, UTC()).year, 1);
+ assertPred!"=="(SysTime(-1, UTC()).year, 0);
+ assertPred!"=="(SysTime(DateTime(12, 1, 1, 0, 0, 0)).year, 12);
+ assertPred!"=="(SysTime(DateTime(-12, 1, 1, 0, 0, 0)).year, -12);
+ assertPred!"=="(SysTime(Date(1999, 7, 6)).year, 1999);
+ assertPred!"=="(SysTime(Date(-1999, 7, 6)).year, -1999);
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cst.year));
+ //static assert(__traits(compiles, ist.year));
+ }
+
+
+ /++
+ Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
+ are B.C.
+
+ Params:
+ year = The year to set this SysTime's year to.
+
+ Throws:
+ DateTimeException if the new year is not a leap year and the resulting
+ date would be on February 29th.
+
+ Examples:
+--------------------
+assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).year == 1999);
+assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).year == 2010);
+assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).year == -7);
+--------------------
+ +/
+ @property void year(int year)
+ {
+ auto hnsecs = adjTime;
+ auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
+
+ if(hnsecs < 0)
+ {
+ hnsecs += convert!("hours", "hnsecs")(24);
+ --days;
+ }
+
+ auto date = Date(cast(int)days);
+ date.year = year;
+
+ immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
+
+ adjTime = newDaysHNSecs + hnsecs;
+ }
+
+ unittest
+ {
+ static void testST(SysTime st, int year, in SysTime expected, size_t line = __LINE__)
+ {
+ st.year = year;
+ assertPred!"=="(st, expected, "", __FILE__, line);
+ }
+
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), 1999, SysTime(Date(1999, 1, 1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), 0, SysTime(Date(0, 1, 1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), -1999, SysTime(Date(-1999, 1, 1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 1999, SysTime(DateTime(1999, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 0, SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), -1999, SysTime(DateTime(-1999, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), 1999, SysTime(Date(1999, 1, 1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), 0, SysTime(Date(0, 1, 1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), -1999, SysTime(Date(-1999, 1, 1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 1999, SysTime(DateTime(1999, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 0, SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), -1999, SysTime(DateTime(-1999, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(Date(1, 7, 2)), 12, SysTime(Date(12, 7, 2)));
+ testST(SysTime(Date(5007, 7, 2)), 5, SysTime(Date(5, 7, 2)));
+ testST(SysTime(Date(0, 7, 2)), 999, SysTime(Date(999, 7, 2)));
+ testST(SysTime(Date(-1202, 7, 2)), 2300, SysTime(Date(2300, 7, 2)));
+
+ testST(SysTime(Date(1, 7, 2)), -12, SysTime(Date(-12, 7, 2)));
+ testST(SysTime(Date(5007, 7, 2)), -5, SysTime(Date(-5, 7, 2)));
+ testST(SysTime(Date(0, 7, 2)), -999, SysTime(Date(-999, 7, 2)));
+ testST(SysTime(Date(-1202, 7, 2)), -2300, SysTime(Date(-2300, 7, 2)));
+
+ testST(SysTime(DateTime(1, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(0)), 12, SysTime(DateTime(12, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(DateTime(1, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 12, SysTime(DateTime(12, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(1, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 0, SysTime(DateTime(0, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(1, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), -1, SysTime(DateTime(-1, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(1, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 1, SysTime(DateTime(1, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(1, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 999, SysTime(DateTime(999, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(1, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 2010, SysTime(DateTime(2010, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+
+ testST(SysTime(DateTime(5007, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(0)), 5, SysTime(DateTime(5, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(DateTime(5007, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 5, SysTime(DateTime(5, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(5007, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 0, SysTime(DateTime(0, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(5007, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), -507, SysTime(DateTime(-507, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(5007, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 2300, SysTime(DateTime(2300, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(5007, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 5007, SysTime(DateTime(5007, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+
+ testST(SysTime(DateTime(0, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(0)), 12, SysTime(DateTime(12, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(DateTime(0, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 12, SysTime(DateTime(12, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(0, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 0, SysTime(DateTime(0, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(0, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), -1, SysTime(DateTime(-1, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(0, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 1, SysTime(DateTime(1, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(0, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 999, SysTime(DateTime(999, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(0, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 2010, SysTime(DateTime(2010, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+
+ testST(SysTime(DateTime(-1202, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(0)), 5, SysTime(DateTime(5, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(DateTime(-1202, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 5, SysTime(DateTime(5, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(-1202, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 0, SysTime(DateTime(0, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(-1202, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), -507, SysTime(DateTime(-507, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(-1202, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 2300, SysTime(DateTime(2300, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(-1202, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 5007, SysTime(DateTime(5007, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+
+ testST(SysTime(0, UTC()), 12, SysTime(DateTime(12, 1, 1, 0, 0, 0), UTC()));
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst.year = 7));
+ //static assert(!__traits(compiles, ist.year = 7));
+
+ //Verify Examples.
+ assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).year == 1999);
+ assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).year == 2010);
+ assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).year == -7);
+ }
+
+
+ /++
+ Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
+
+ Throws:
+ DateTimeException if $(D isAD) is true.
+
+ Examples:
+--------------------
+assert(SysTime(DateTime(0, 1, 1, 12, 30, 33)).yearBC == 1);
+assert(SysTime(DateTime(-1, 1, 1, 10, 7, 2)).yearBC == 2);
+assert(SysTime(DateTime(-100, 1, 1, 4, 59, 0)).yearBC == 101);
+--------------------
+ +/
+ @property ushort yearBC() const
+ {
+ return (cast(Date)this).yearBC;
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException((in SysTime st){st.yearBC;}(SysTime(Date(1, 1, 1), UTC())));
+ assertThrown!DateTimeException((in SysTime st){st.yearBC;}(SysTime(0, UTC())));
+ assertThrown!DateTimeException((in SysTime st){st.yearBC;}(SysTime(1, UTC())));
+
+ assertPred!"=="(SysTime(-1, UTC()).yearBC, 1);
+ assertPred!"=="(SysTime(DateTime(-12, 1, 1, 0, 0, 0)).yearBC, 13);
+
+ auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, st.year = 12));
+ static assert(!__traits(compiles, cst.year = 12));
+ //static assert(!__traits(compiles, ist.year = 12));
+
+ //Verify Examples.
+ assert(SysTime(DateTime(0, 1, 1, 12, 30, 33)).yearBC == 1);
+ assert(SysTime(DateTime(-1, 1, 1, 10, 7, 2)).yearBC == 2);
+ assert(SysTime(DateTime(-100, 1, 1, 4, 59, 0)).yearBC == 101);
+ }
+
+
+ /++
+ Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
+
+ Params:
+ year = The year B.C. to set this SysTime's year to.
+
+ Throws:
+ DateTimeException if a non-positive value is given.
+
+ Examples:
+--------------------
+auto st = SysTime(DateTime(2010, 1, 1, 7, 30, 0));
+st.yearBC = 1;
+assert(st == SysTime(DateTime(0, 1, 1, 7, 30, 0)));
+
+st.yearBC = 10;
+assert(st == SysTime(DateTime(-9, 1, 1, 7, 30, 0)));
+--------------------
+ +/
+ @property void yearBC(int year)
+ {
+ auto hnsecs = adjTime;
+ auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
+
+ if(hnsecs < 0)
+ {
+ hnsecs += convert!("hours", "hnsecs")(24);
+ --days;
+ }
+
+ auto date = Date(cast(int)days);
+ date.yearBC = year;
+
+ immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
+
+ adjTime = newDaysHNSecs + hnsecs;
+ }
+
+ unittest
+ {
+ static void testSTInvalid(SysTime st, int year)
+ {
+ st.yearBC = year;
+ }
+
+ static void testST(SysTime st, int year, in SysTime expected, size_t line = __LINE__)
+ {
+ st.yearBC = year;
+ assertPred!"=="(st, expected, "", __FILE__, line);
+ }
+
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 1, 1)), 0));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 1, 1)), -1));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 1, 1)), -1202));
+
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), 1999, SysTime(Date(-1998, 1, 1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), 1, SysTime(Date(0, 1, 1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 1999, SysTime(DateTime(-1998, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(Date(1, 7, 2)), 12, SysTime(Date(-11, 7, 2)));
+ testST(SysTime(Date(5007, 7, 2)), 5, SysTime(Date(-4, 7, 2)));
+ testST(SysTime(Date(0, 7, 2)), 999, SysTime(Date(-998, 7, 2)));
+ testST(SysTime(Date(-1202, 7, 2)), 2300, SysTime(Date(-2299, 7, 2)));
+
+ testST(SysTime(DateTime(1, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(0)), 12, SysTime(DateTime(-11, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(DateTime(1, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 12, SysTime(DateTime(-11, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(1, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 1, SysTime(DateTime(0, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(1, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 999, SysTime(DateTime(-998, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(1, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 2010, SysTime(DateTime(-2009, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+
+ testST(SysTime(DateTime(5007, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(0)), 5, SysTime(DateTime(-4, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(DateTime(5007, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 5, SysTime(DateTime(-4, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(5007, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 2300, SysTime(DateTime(-2299, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(5007, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 5007, SysTime(DateTime(-5006, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+
+ testST(SysTime(DateTime(0, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(0)), 12, SysTime(DateTime(-11, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(DateTime(0, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 12, SysTime(DateTime(-11, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(0, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 1, SysTime(DateTime(0, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(0, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 999, SysTime(DateTime(-998, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(0, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 2010, SysTime(DateTime(-2009, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+
+ testST(SysTime(DateTime(-1202, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(0)), 5, SysTime(DateTime(-4, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(DateTime(-1202, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 5, SysTime(DateTime(-4, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(-1202, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 2300, SysTime(DateTime(-2299, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+ testST(SysTime(DateTime(-1202, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)), 5007, SysTime(DateTime(-5006, 7, 2, 1, 3, 2), FracSec.from!"hnsecs"(5007)));
+
+ testST(SysTime(0, UTC()), 12, SysTime(DateTime(-11, 1, 1, 0, 0, 0), UTC()));
+
+ {
+ auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, st.yearBC = 12));
+ static assert(!__traits(compiles, cst.yearBC = 12));
+ //static assert(!__traits(compiles, ist.yearBC = 12));
+ }
+
+ //Verify Examples.
+ {
+ auto st = SysTime(DateTime(2010, 1, 1, 7, 30, 0));
+ st.yearBC = 1;
+ assert(st == SysTime(DateTime(0, 1, 1, 7, 30, 0)));
+
+ st.yearBC = 10;
+ assert(st == SysTime(DateTime(-9, 1, 1, 7, 30, 0)));
+ }
+ }
+
+
+ /++
+ Month of a Gregorian Year.
+
+ Examples:
+--------------------
+assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).month == 7);
+assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).month == 10);
+assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).month == 4);
+--------------------
+ +/
+ @property Month month() const nothrow
+ {
+ return (cast(Date)this).month;
+ }
+
+ unittest
+ {
+ assertPred!"=="(SysTime(0, UTC()).month, 1);
+ assertPred!"=="(SysTime(1, UTC()).month, 1);
+ assertPred!"=="(SysTime(-1, UTC()).month, 12);
+ assertPred!"=="(SysTime(DateTime(1, 12, 1, 0, 0, 0)).month, 12);
+ assertPred!"=="(SysTime(DateTime(0, 12, 1, 0, 0, 0)).month, 12);
+ assertPred!"=="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)).month, 7);
+ assertPred!"=="(SysTime(DateTime(-1999, 7, 6, 12, 30, 33)).month, 7);
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cst.month));
+ //static assert(__traits(compiles, ist.month));
+
+ //Verify Examples.
+ assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).month == 7);
+ assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).month == 10);
+ assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).month == 4);
+ }
+
+
+ /++
+ Month of a Gregorian Year.
+
+ Params:
+ month = The month to set this SysTime's month to.
+
+ Throws:
+ DateTimeException if the given month is not a valid month.
+ +/
+ @property void month(Month month)
+ {
+ auto hnsecs = adjTime;
+ auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
+
+ if(hnsecs < 0)
+ {
+ hnsecs += convert!("hours", "hnsecs")(24);
+ --days;
+ }
+
+ auto date = Date(cast(int)days);
+ date.month = month;
+
+ immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
+
+ adjTime = newDaysHNSecs + hnsecs;
+ }
+
+ unittest
+ {
+ static void testSTInvalid(SysTime st, Month month)
+ {
+ st.month = month;
+ }
+
+ static void testST(SysTime st, Month month, in SysTime expected, size_t line = __LINE__)
+ {
+ st.month = month;
+ assertPred!"=="(st, expected, "", __FILE__, line);
+ }
+
+ assertThrown!DateTimeException(testSTInvalid(SysTime(DateTime(1, 1, 1, 12, 30, 33)), cast(Month)0));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(DateTime(1, 1, 1, 12, 30, 33)), cast(Month)13));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(DateTime(1, 1, 29, 12, 30, 33)), cast(Month)2));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(DateTime(1, 7, 31, 12, 30, 33)), cast(Month)6));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(DateTime(4, 7, 30, 12, 30, 33)), cast(Month)2));
+
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), cast(Month)1, SysTime(Date(1, 1, 1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), cast(Month)7, SysTime(Date(1, 7, 1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), cast(Month)12, SysTime(Date(1, 12, 1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), cast(Month)1, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), cast(Month)7, SysTime(DateTime(1, 7, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), cast(Month)12, SysTime(DateTime(1, 12, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), cast(Month)1, SysTime(Date(0, 1, 1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), cast(Month)7, SysTime(Date(0, 7, 1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), cast(Month)12, SysTime(Date(0, 12, 1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), cast(Month)1, SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), cast(Month)7, SysTime(DateTime(0, 7, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), cast(Month)12, SysTime(DateTime(0, 12, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(Date(1, 7, 2)), cast(Month)12, SysTime(Date(1, 12, 2)));
+ testST(SysTime(Date(5007, 7, 2)), cast(Month)5, SysTime(Date(5007, 5, 2)));
+ testST(SysTime(Date(0, 7, 2)), cast(Month)7, SysTime(Date(0, 7, 2)));
+ testST(SysTime(Date(-1202, 7, 2)), cast(Month)1, SysTime(Date(-1202, 1, 2)));
+
+ testST(SysTime(DateTime(1, 12, 29, 9, 13, 2), FracSec.from!"hnsecs"(0)), cast(Month)12, SysTime(DateTime(1, 12, 29, 9, 13, 2), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(DateTime(1, 12, 29, 9, 13, 2), FracSec.from!"hnsecs"(1)), cast(Month)12, SysTime(DateTime(1, 12, 29, 9, 13, 2), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 12, 29, 9, 13, 2), FracSec.from!"hnsecs"(2)), cast(Month)7, SysTime(DateTime(1, 7, 29, 9, 13, 2), FracSec.from!"hnsecs"(2)));
+ testST(SysTime(DateTime(1, 11, 28, 10, 13, 2), FracSec.from!"hnsecs"(3)), cast(Month)1, SysTime(DateTime(1, 1, 28, 10, 13, 2), FracSec.from!"hnsecs"(3)));
+ testST(SysTime(DateTime(1, 1, 28, 10, 13, 2), FracSec.from!"hnsecs"(4)), cast(Month)2, SysTime(DateTime(1, 2, 28, 10, 13, 2), FracSec.from!"hnsecs"(4)));
+ testST(SysTime(DateTime(1, 7, 28, 10, 13, 2), FracSec.from!"hnsecs"(5)),cast(Month) 6, SysTime(DateTime(1, 6, 28, 10, 13, 2), FracSec.from!"hnsecs"(5)));
+ testST(SysTime(DateTime(4, 7, 29, 10, 13, 2), FracSec.from!"hnsecs"(6)), cast(Month)2, SysTime(DateTime(4, 2, 29, 10, 13, 2), FracSec.from!"hnsecs"(6)));
+ testST(SysTime(DateTime(4, 7, 31, 10, 13, 2), FracSec.from!"hnsecs"(6)), cast(Month)8, SysTime(DateTime(4, 8, 31, 10, 13, 2), FracSec.from!"hnsecs"(6)));
+
+ testST(SysTime(DateTime(1207, 12, 29, 9, 12, 2), FracSec.from!"hnsecs"(0)), cast(Month)12, SysTime(DateTime(1207, 12, 29, 9, 12, 2), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(DateTime(1207, 12, 29, 9, 12, 2), FracSec.from!"hnsecs"(11)), cast(Month)12, SysTime(DateTime(1207, 12, 29, 9, 12, 2), FracSec.from!"hnsecs"(11)));
+ testST(SysTime(DateTime(1207, 12, 29, 9, 12, 3), FracSec.from!"hnsecs"(10)), cast(Month)7, SysTime(DateTime(1207, 7, 29, 9, 12, 3), FracSec.from!"hnsecs"(10)));
+ testST(SysTime(DateTime(1207, 11, 28, 10, 12, 3), FracSec.from!"hnsecs"(9)), cast(Month)1, SysTime(DateTime(1207, 1, 28, 10, 12, 3), FracSec.from!"hnsecs"(9)));
+ testST(SysTime(DateTime(1207, 1, 28, 10, 12, 3), FracSec.from!"hnsecs"(8)), cast(Month)2, SysTime(DateTime(1207, 2, 28, 10, 12, 3), FracSec.from!"hnsecs"(8)));
+ testST(SysTime(DateTime(1207, 7, 28, 10, 12, 3), FracSec.from!"hnsecs"(7)), cast(Month)6, SysTime(DateTime(1207, 6, 28, 10, 12, 3), FracSec.from!"hnsecs"(7)));
+
+ testST(SysTime(DateTime(0, 12, 29, 9, 13, 2), FracSec.from!"hnsecs"(0)), cast(Month)12, SysTime(DateTime(0, 12, 29, 9, 13, 2), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(DateTime(0, 12, 29, 9, 13, 2), FracSec.from!"hnsecs"(1)), cast(Month)12, SysTime(DateTime(0, 12, 29, 9, 13, 2), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 12, 29, 9, 13, 2), FracSec.from!"hnsecs"(2)), cast(Month)7, SysTime(DateTime(0, 7, 29, 9, 13, 2), FracSec.from!"hnsecs"(2)));
+ testST(SysTime(DateTime(0, 11, 28, 10, 13, 2), FracSec.from!"hnsecs"(3)), cast(Month)1, SysTime(DateTime(0, 1, 28, 10, 13, 2), FracSec.from!"hnsecs"(3)));
+ testST(SysTime(DateTime(0, 1, 28, 10, 13, 2), FracSec.from!"hnsecs"(4)), cast(Month)2, SysTime(DateTime(0, 2, 28, 10, 13, 2), FracSec.from!"hnsecs"(4)));
+ testST(SysTime(DateTime(0, 7, 28, 10, 13, 2), FracSec.from!"hnsecs"(5)), cast(Month)6, SysTime(DateTime(0, 6, 28, 10, 13, 2), FracSec.from!"hnsecs"(5)));
+
+ testST(SysTime(DateTime(0, 12, 30, 0, 0, 0), FracSec.from!"hnsecs"(1)), cast(Month)11, SysTime(DateTime(0, 11, 30, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(-1, 7, 28, 0, 0, 0), FracSec.from!"hnsecs"(1)), cast(Month)2, SysTime(DateTime(-1, 2, 28, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 7, 29, 0, 0, 0), FracSec.from!"hnsecs"(1)), cast(Month)2, SysTime(DateTime(0, 2, 29, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 7, 29, 10, 13, 2), FracSec.from!"hnsecs"(6)), cast(Month)2, SysTime(DateTime(0, 2, 29, 10, 13, 2), FracSec.from!"hnsecs"(6)));
+ testST(SysTime(DateTime(0, 7, 31, 10, 13, 2), FracSec.from!"hnsecs"(6)), cast(Month)8, SysTime(DateTime(0, 8, 31, 10, 13, 2), FracSec.from!"hnsecs"(6)));
+
+ testST(SysTime(DateTime(-9999, 12, 29, 9, 12, 2), FracSec.from!"hnsecs"(0)), cast(Month)12, SysTime(DateTime(-9999, 12, 29, 9, 12, 2), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(DateTime(-9999, 12, 29, 9, 12, 2), FracSec.from!"hnsecs"(11)), cast(Month)12, SysTime(DateTime(-9999, 12, 29, 9, 12, 2), FracSec.from!"hnsecs"(11)));
+ testST(SysTime(DateTime(-9999, 12, 29, 9, 12, 3), FracSec.from!"hnsecs"(10)), cast(Month)7, SysTime(DateTime(-9999, 7, 29, 9, 12, 3), FracSec.from!"hnsecs"(10)));
+ testST(SysTime(DateTime(-9999, 11, 28, 10, 12, 3), FracSec.from!"hnsecs"(9)), cast(Month)1, SysTime(DateTime(-9999, 1, 28, 10, 12, 3), FracSec.from!"hnsecs"(9)));
+ testST(SysTime(DateTime(-9999, 1, 28, 10, 12, 3), FracSec.from!"hnsecs"(8)), cast(Month)2, SysTime(DateTime(-9999, 2, 28, 10, 12, 3), FracSec.from!"hnsecs"(8)));
+ testST(SysTime(DateTime(-9999, 7, 28, 10, 12, 3), FracSec.from!"hnsecs"(7)), cast(Month)6, SysTime(DateTime(-9999, 6, 28, 10, 12, 3), FracSec.from!"hnsecs"(7)));
+
+ testST(SysTime(0, UTC()), cast(Month)12, SysTime(DateTime(1, 12, 1, 0, 0, 0), UTC()));
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst.month = 12));
+ //static assert(!__traits(compiles, ist.month = 12));
+ }
+
+
+ /++
+ Day of a Gregorian Month.
+
+ Examples:
+--------------------
+assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).day == 6);
+assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).day == 4);
+assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).day == 5);
+--------------------
+ +/
+ @property ubyte day() const nothrow
+ {
+ return (cast(Date)this).day;
+ }
+
+ unittest
+ {
+ assertPred!"=="(SysTime(0, UTC()).day, 1);
+ assertPred!"=="(SysTime(1, UTC()).day, 1);
+ assertPred!"=="(SysTime(-1, UTC()).day, 31);
+ assertPred!"=="(SysTime(DateTime(50, 2, 4)).day, 4);
+ assertPred!"=="(SysTime(DateTime(50, 2, 4, 0, 0, 1)).day, 4);
+ assertPred!"=="(SysTime(DateTime(1999, 7, 6)).day, 6);
+ assertPred!"=="(SysTime(DateTime(1999, 7, 6, 0, 0, 0)).day, 6);
+ assertPred!"=="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)).day, 6);
+ assertPred!"=="(SysTime(DateTime(-50, 2, 4)).day, 4);
+ assertPred!"=="(SysTime(DateTime(-50, 2, 4, 0, 0, 1)).day, 4);
+ assertPred!"=="(SysTime(Date(-1999, 7, 6)).day, 6);
+ assertPred!"=="(SysTime(DateTime(-1999, 7, 6, 0, 0, 0)).day, 6);
+ assertPred!"=="(SysTime(DateTime(-1999, 7, 6, 12, 30, 33)).day, 6);
+
+ assertPred!"=="(SysTime(DateTime(1, 1, 12, 0, 0, 0)).day, 12);
+ assertPred!"=="(SysTime(DateTime(0, 1, 12, 0, 0, 0)).day, 12);
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cst.day));
+ //static assert(__traits(compiles, ist.day));
+
+ //Verify Examples.
+ assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).day == 6);
+ assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).day == 4);
+ assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).day == 5);
+ }
+
+
+ /++
+ Day of a Gregorian Month.
+
+ Params:
+ day = The day of the month to set this SysTime's day to.
+
+ Throws:
+ DateTimeException if the given day is not a valid day of the current
+ month.
+ +/
+ @property void day(int day)
+ {
+ auto hnsecs = adjTime;
+ auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
+
+ if(hnsecs < 0)
+ {
+ hnsecs += convert!("hours", "hnsecs")(24);
+ --days;
+ }
+
+ auto date = Date(cast(int)days);
+ date.day = day;
+
+ immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
+
+ adjTime = newDaysHNSecs + hnsecs;
+ }
+
+ unittest
+ {
+ static void testSTInvalid(SysTime st, int day)
+ {
+ st.day = day;
+ }
+
+ static void testST(SysTime st, int day, in SysTime expected, size_t line = __LINE__)
+ {
+ st.day = day;
+ assertPred!"=="(st, expected, "", __FILE__, line);
+ }
+
+ //Test A.D.
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 1, 1)), 0));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 1, 1)), 32));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 2, 1)), 29));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(4, 2, 1)), 30));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 3, 1)), 32));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 4, 1)), 31));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 5, 1)), 32));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 6, 1)), 31));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 7, 1)), 32));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 8, 1)), 32));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 9, 1)), 31));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 10, 1)), 32));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 11, 1)), 31));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 12, 1)), 32));
+
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 1, 1)), 31));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 2, 1)), 28));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(4, 2, 1)), 29));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 3, 1)), 31));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 4, 1)), 30));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 5, 1)), 31));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 6, 1)), 30));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 7, 1)), 31));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 8, 1)), 31));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 9, 1)), 30));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 10, 1)), 31));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 11, 1)), 30));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(1, 12, 1)), 31));
+
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), 1, SysTime(Date(1, 1, 1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), 7, SysTime(Date(1, 1, 7)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), 12, SysTime(Date(1, 1, 12)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 7, SysTime(DateTime(1, 1, 7, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 12, SysTime(DateTime(1, 1, 12, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(Date(1, 7, 2)), 12, SysTime(Date(1, 7, 12)));
+ testST(SysTime(Date(5007, 7, 2)), 5, SysTime(Date(5007, 7, 5)));
+
+ testST(SysTime(DateTime(1, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(7)), 6, SysTime(DateTime(1, 1, 6, 12, 22, 17), FracSec.from!"hnsecs"(7)));
+ testST(SysTime(DateTime(1, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(70)), 1, SysTime(DateTime(1, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(70)));
+ testST(SysTime(DateTime(1, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(700)), 1, SysTime(DateTime(1, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(700)));
+ testST(SysTime(DateTime(1, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(7000)), 5, SysTime(DateTime(1, 2, 5, 12, 22, 17), FracSec.from!"hnsecs"(7000)));
+ testST(SysTime(DateTime(1, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(70_000)), 1, SysTime(DateTime(1, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(70_000)));
+ testST(SysTime(DateTime(1, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(700_000)), 29, SysTime(DateTime(1, 12, 29, 12, 22, 17), FracSec.from!"hnsecs"(700_000)));
+
+ testST(SysTime(DateTime(999, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(9)), 6, SysTime(DateTime(999, 1, 6, 12, 22, 17), FracSec.from!"hnsecs"(9)));
+ testST(SysTime(DateTime(999, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(90)), 1, SysTime(DateTime(999, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(90)));
+ testST(SysTime(DateTime(999, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(900)), 1, SysTime(DateTime(999, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(900)));
+ testST(SysTime(DateTime(999, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(9000)), 5, SysTime(DateTime(999, 2, 5, 12, 22, 17), FracSec.from!"hnsecs"(9000)));
+ testST(SysTime(DateTime(999, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(90_000)), 1, SysTime(DateTime(999, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(90_000)));
+ testST(SysTime(DateTime(999, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(900_000)), 29, SysTime(DateTime(999, 12, 29, 12, 22, 17), FracSec.from!"hnsecs"(900_000)));
+
+ //Test B.C.
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 1, 1)), 0));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 1, 1)), 32));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 2, 1)), 29));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(0, 2, 1)), 30));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 3, 1)), 32));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 4, 1)), 31));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 5, 1)), 32));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 6, 1)), 31));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 7, 1)), 32));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 8, 1)), 32));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 9, 1)), 31));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 10, 1)), 32));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 11, 1)), 31));
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 12, 1)), 32));
+
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 1, 1)), 31));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 2, 1)), 28));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(0, 2, 1)), 29));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 3, 1)), 31));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 4, 1)), 30));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 5, 1)), 31));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 6, 1)), 30));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 7, 1)), 31));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 8, 1)), 31));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 9, 1)), 30));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 10, 1)), 31));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 11, 1)), 30));
+ assertNotThrown!DateTimeException(testSTInvalid(SysTime(Date(-1, 12, 1)), 31));
+
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), 1, SysTime(Date(0, 1, 1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), 7, SysTime(Date(0, 1, 7)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), 12, SysTime(Date(0, 1, 12)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 7, SysTime(DateTime(0, 1, 7, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 12, SysTime(DateTime(0, 1, 12, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(Date(0, 7, 2)), 7, SysTime(Date(0, 7, 7)));
+ testST(SysTime(Date(-1202, 7, 2)), 1, SysTime(Date(-1202, 7, 1)));
+
+ testST(SysTime(DateTime(0, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(7)), 6, SysTime(DateTime(0, 1, 6, 12, 22, 17), FracSec.from!"hnsecs"(7)));
+ testST(SysTime(DateTime(0, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(70)), 1, SysTime(DateTime(0, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(70)));
+ testST(SysTime(DateTime(0, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(700)), 1, SysTime(DateTime(0, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(700)));
+ testST(SysTime(DateTime(0, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(7000)), 5, SysTime(DateTime(0, 2, 5, 12, 22, 17), FracSec.from!"hnsecs"(7000)));
+ testST(SysTime(DateTime(0, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(70_000)), 1, SysTime(DateTime(0, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(70_000)));
+ testST(SysTime(DateTime(0, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(700_000)), 29, SysTime(DateTime(0, 12, 29, 12, 22, 17), FracSec.from!"hnsecs"(700_000)));
+
+ testST(SysTime(DateTime(-1, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(9)), 6, SysTime(DateTime(-1, 1, 6, 12, 22, 17), FracSec.from!"hnsecs"(9)));
+ testST(SysTime(DateTime(-1, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(90)), 1, SysTime(DateTime(-1, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(90)));
+ testST(SysTime(DateTime(-1, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(900)), 1, SysTime(DateTime(-1, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(900)));
+ testST(SysTime(DateTime(-1, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(9000)), 5, SysTime(DateTime(-1, 2, 5, 12, 22, 17), FracSec.from!"hnsecs"(9000)));
+ testST(SysTime(DateTime(-1, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(90_000)), 1, SysTime(DateTime(-1, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(90_000)));
+ testST(SysTime(DateTime(-1, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(900_000)), 29, SysTime(DateTime(-1, 12, 29, 12, 22, 17), FracSec.from!"hnsecs"(900_000)));
+
+ testST(SysTime(0, UTC()), 12, SysTime(DateTime(1, 1, 12, 0, 0, 0), UTC()));
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst.day = 27));
+ //static assert(!__traits(compiles, ist.day = 27));
+ }
+
+
+ /++
+ Hours past midnight.
+ +/
+ @property ubyte hour() const nothrow
+ {
+ auto hnsecs = adjTime;
+ auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
+
+ if(hnsecs < 0)
+ {
+ hnsecs += convert!("hours", "hnsecs")(24);
+ --days;
+ }
+
+ return cast(ubyte)getUnitsFromHNSecs!"hours"(hnsecs);
+ }
+
+ unittest
+ {
+ assertPred!"=="(SysTime(0, UTC()).hour, 0);
+ assertPred!"=="(SysTime(1, UTC()).hour, 0);
+ assertPred!"=="(SysTime(-1, UTC()).hour, 23);
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 12, 0, 0)).hour, 12);
+ assertPred!"=="(SysTime(DateTime(0, 1, 1, 12, 0, 0)).hour, 12);
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cst.hour));
+ //static assert(__traits(compiles, ist.hour));
+ }
+
+
+ /++
+ Hours past midnight.
+
+ Params:
+ hour = The hours to set this SysTime's hour to.
+
+ Throws:
+ DateTimeException if the given hour are not a valid hour of the day.
+ +/
+ @property void hour(int hour)
+ {
+ enforceValid!"hours"(hour);
+
+ auto hnsecs = adjTime;
+ auto days = splitUnitsFromHNSecs!"days"(hnsecs);
+ immutable daysHNSecs = convert!("days", "hnsecs")(days);
+ immutable negative = hnsecs < 0;
+
+ if(negative)
+ hnsecs += convert!("hours", "hnsecs")(24);
+
+ hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
+ hnsecs += convert!("hours", "hnsecs")(hour);
+
+ if(negative)
+ hnsecs -= convert!("hours", "hnsecs")(24);
+
+ adjTime = daysHNSecs + hnsecs;
+ }
+
+ unittest
+ {
+ static void testSTInvalid(SysTime st, int hour)
+ {
+ st.hour = hour;
+ }
+
+ static void testST(SysTime st, int hour, in SysTime expected, size_t line = __LINE__)
+ {
+ st.hour = hour;
+ assertPred!"=="(st, expected, "", __FILE__, line);
+ }
+
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(1999, 7, 6)), 24));
+
+ //Test A.D.
+ testST(SysTime(Date(1, 1, 1)), 1, SysTime(DateTime(1, 1, 1, 1, 0, 0)));
+ testST(SysTime(Date(1, 1, 1)), 7, SysTime(DateTime(1, 1, 1, 7, 0, 0)));
+ testST(SysTime(Date(1, 1, 1)), 12, SysTime(DateTime(1, 1, 1, 12, 0, 0)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(1, 1, 1, 1, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 7, SysTime(DateTime(1, 1, 1, 7, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 12, SysTime(DateTime(1, 1, 1, 12, 0, 0), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59)), 1, SysTime(DateTime(1, 12, 31, 1, 59, 59)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59)), 7, SysTime(DateTime(1, 12, 31, 7, 59, 59)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59)), 12, SysTime(DateTime(1, 12, 31, 12, 59, 59)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(1, 12, 31, 1, 59, 59), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 7, SysTime(DateTime(1, 12, 31, 7, 59, 59), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 12, SysTime(DateTime(1, 12, 31, 12, 59, 59), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(Date(1, 7, 2)), 12, SysTime(DateTime(1, 7, 2, 12, 0, 0)));
+ testST(SysTime(Date(5007, 7, 2)), 5, SysTime(DateTime(5007, 7, 2, 5, 0, 0)));
+
+ testST(SysTime(DateTime(1, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(7)), 6, SysTime(DateTime(1, 1, 7, 6, 22, 17), FracSec.from!"hnsecs"(7)));
+ testST(SysTime(DateTime(1, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(70)), 1, SysTime(DateTime(1, 1, 1, 1, 22, 17), FracSec.from!"hnsecs"(70)));
+ testST(SysTime(DateTime(1, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(700)), 1, SysTime(DateTime(1, 2, 1, 1, 22, 17), FracSec.from!"hnsecs"(700)));
+ testST(SysTime(DateTime(1, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(7000)), 5, SysTime(DateTime(1, 2, 27, 5, 22, 17), FracSec.from!"hnsecs"(7000)));
+ testST(SysTime(DateTime(1, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(70_000)), 1, SysTime(DateTime(1, 12, 1, 1, 22, 17), FracSec.from!"hnsecs"(70_000)));
+ testST(SysTime(DateTime(1, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(700_000)), 23, SysTime(DateTime(1, 12, 31, 23, 22, 17), FracSec.from!"hnsecs"(700_000)));
+
+ testST(SysTime(DateTime(999, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(9)), 6, SysTime(DateTime(999, 1, 7, 6, 22, 17), FracSec.from!"hnsecs"(9)));
+ testST(SysTime(DateTime(999, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(90)), 1, SysTime(DateTime(999, 1, 1, 1, 22, 17), FracSec.from!"hnsecs"(90)));
+ testST(SysTime(DateTime(999, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(900)), 1, SysTime(DateTime(999, 2, 1, 1, 22, 17), FracSec.from!"hnsecs"(900)));
+ testST(SysTime(DateTime(999, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(9000)), 5, SysTime(DateTime(999, 2, 27, 5, 22, 17), FracSec.from!"hnsecs"(9000)));
+ testST(SysTime(DateTime(999, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(90_000)), 1, SysTime(DateTime(999, 12, 1, 1, 22, 17), FracSec.from!"hnsecs"(90_000)));
+ testST(SysTime(DateTime(999, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(900_000)), 23, SysTime(DateTime(999, 12, 31, 23, 22, 17), FracSec.from!"hnsecs"(900_000)));
+
+ //Test B.C.
+ testST(SysTime(Date(0, 1, 1)), 1, SysTime(DateTime(0, 1, 1, 1, 0, 0)));
+ testST(SysTime(Date(0, 1, 1)), 7, SysTime(DateTime(0, 1, 1, 7, 0, 0)));
+ testST(SysTime(Date(0, 1, 1)), 12, SysTime(DateTime(0, 1, 1, 12, 0, 0)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(0, 1, 1, 1, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 7, SysTime(DateTime(0, 1, 1, 7, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 12, SysTime(DateTime(0, 1, 1, 12, 0, 0), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59)), 1, SysTime(DateTime(0, 12, 31, 1, 59, 59)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59)), 7, SysTime(DateTime(0, 12, 31, 7, 59, 59)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59)), 12, SysTime(DateTime(0, 12, 31, 12, 59, 59)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(0, 12, 31, 1, 59, 59), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 7, SysTime(DateTime(0, 12, 31, 7, 59, 59), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 12, SysTime(DateTime(0, 12, 31, 12, 59, 59), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(Date(0, 7, 2)), 7, SysTime(DateTime(0, 7, 2, 7, 0, 0)));
+ testST(SysTime(Date(-1202, 7, 2)), 1, SysTime(DateTime(-1202, 7, 2, 1, 0, 0)));
+
+ testST(SysTime(DateTime(0, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(7)), 6, SysTime(DateTime(0, 1, 7, 6, 22, 17), FracSec.from!"hnsecs"(7)));
+ testST(SysTime(DateTime(0, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(70)), 1, SysTime(DateTime(0, 1, 1, 1, 22, 17), FracSec.from!"hnsecs"(70)));
+ testST(SysTime(DateTime(0, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(700)), 1, SysTime(DateTime(0, 2, 1, 1, 22, 17), FracSec.from!"hnsecs"(700)));
+ testST(SysTime(DateTime(0, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(7000)), 5, SysTime(DateTime(0, 2, 27, 5, 22, 17), FracSec.from!"hnsecs"(7000)));
+ testST(SysTime(DateTime(0, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(70_000)), 1, SysTime(DateTime(0, 12, 1, 1, 22, 17), FracSec.from!"hnsecs"(70_000)));
+ testST(SysTime(DateTime(0, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(700_000)), 23, SysTime(DateTime(0, 12, 31, 23, 22, 17), FracSec.from!"hnsecs"(700_000)));
+
+ testST(SysTime(DateTime(-1, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(9)), 6, SysTime(DateTime(-1, 1, 7, 6, 22, 17), FracSec.from!"hnsecs"(9)));
+ testST(SysTime(DateTime(-1, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(90)), 1, SysTime(DateTime(-1, 1, 1, 1, 22, 17), FracSec.from!"hnsecs"(90)));
+ testST(SysTime(DateTime(-1, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(900)), 1, SysTime(DateTime(-1, 2, 1, 1, 22, 17), FracSec.from!"hnsecs"(900)));
+ testST(SysTime(DateTime(-1, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(9000)), 5, SysTime(DateTime(-1, 2, 27, 5, 22, 17), FracSec.from!"hnsecs"(9000)));
+ testST(SysTime(DateTime(-1, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(90_000)), 1, SysTime(DateTime(-1, 12, 1, 1, 22, 17), FracSec.from!"hnsecs"(90_000)));
+ testST(SysTime(DateTime(-1, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(900_000)), 23, SysTime(DateTime(-1, 12, 31, 23, 22, 17), FracSec.from!"hnsecs"(900_000)));
+
+ testST(SysTime(0, UTC()), 12, SysTime(DateTime(1, 1, 1, 12, 0, 0), UTC()));
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst.hour = 27));
+ //static assert(!__traits(compiles, ist.hour = 27));
+ }
+
+
+ /++
+ Minutes past the current hour.
+ +/
+ @property ubyte minute() const nothrow
+ {
+ auto hnsecs = adjTime;
+ auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
+
+ if(hnsecs < 0)
+ {
+ hnsecs += convert!("hours", "hnsecs")(24);
+ --days;
+ }
+
+ hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
+
+ return cast(ubyte)getUnitsFromHNSecs!"minutes"(hnsecs);
+ }
+
+ unittest
+ {
+ assertPred!"=="(SysTime(0, UTC()).minute, 0);
+ assertPred!"=="(SysTime(1, UTC()).minute, 0);
+ assertPred!"=="(SysTime(-1, UTC()).minute, 59);
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 0, 30, 0)).minute, 30);
+ assertPred!"=="(SysTime(DateTime(0, 1, 1, 0, 30, 0)).minute, 30);
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cst.minute));
+ //static assert(__traits(compiles, ist.minute));
+ }
+
+
+ /++
+ Minutes past the current hour.
+
+ Params:
+ minutes = The minute to set this SysTime's minute to.
+
+ Throws:
+ DateTimeException if the given minute are not a valid minute of an
+ hour.
+ +/
+ @property void minute(int minute)
+ {
+ enforceValid!"minutes"(minute);
+
+ auto hnsecs = adjTime;
+ auto days = splitUnitsFromHNSecs!"days"(hnsecs);
+ immutable daysHNSecs = convert!("days", "hnsecs")(days);
+ immutable negative = hnsecs < 0;
+
+ if(negative)
+ hnsecs += convert!("hours", "hnsecs")(24);
+
+ immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
+ hnsecs = removeUnitsFromHNSecs!"minutes"(hnsecs);
+
+ hnsecs += convert!("hours", "hnsecs")(hour);
+ hnsecs += convert!("minutes", "hnsecs")(minute);
+
+ if(negative)
+ hnsecs -= convert!("hours", "hnsecs")(24);
+
+ adjTime = daysHNSecs + hnsecs;
+ }
+
+ unittest
+ {
+ static void testSTInvalid(SysTime st, int minute)
+ {
+ st.minute = minute;
+ }
+
+ static void testST(SysTime st, int minute, in SysTime expected, size_t line = __LINE__)
+ {
+ st.minute = minute;
+ assertPred!"=="(st, expected, "", __FILE__, line);
+ }
+
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(1999, 7, 6)), 60));
+
+ //Test A.D.
+ testST(SysTime(Date(1, 1, 1)), 1, SysTime(DateTime(1, 1, 1, 0, 1, 0)));
+ testST(SysTime(Date(1, 1, 1)), 7, SysTime(DateTime(1, 1, 1, 0, 7, 0)));
+ testST(SysTime(Date(1, 1, 1)), 12, SysTime(DateTime(1, 1, 1, 0, 12, 0)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(1, 1, 1, 0, 1, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 7, SysTime(DateTime(1, 1, 1, 0, 7, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 12, SysTime(DateTime(1, 1, 1, 0, 12, 0), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59)), 1, SysTime(DateTime(1, 12, 31, 23, 1, 59)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59)), 7, SysTime(DateTime(1, 12, 31, 23, 7, 59)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59)), 12, SysTime(DateTime(1, 12, 31, 23, 12, 59)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(1, 12, 31, 23, 1, 59), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 7, SysTime(DateTime(1, 12, 31, 23, 7, 59), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 12, SysTime(DateTime(1, 12, 31, 23, 12, 59), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(Date(1, 7, 2)), 12, SysTime(DateTime(1, 7, 2, 0, 12, 0)));
+ testST(SysTime(Date(5007, 7, 2)), 5, SysTime(DateTime(5007, 7, 2, 0, 5, 0)));
+
+ testST(SysTime(DateTime(1, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(7)), 6, SysTime(DateTime(1, 1, 7, 12, 6, 17), FracSec.from!"hnsecs"(7)));
+ testST(SysTime(DateTime(1, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(70)), 1, SysTime(DateTime(1, 1, 1, 12, 1, 17), FracSec.from!"hnsecs"(70)));
+ testST(SysTime(DateTime(1, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(700)), 1, SysTime(DateTime(1, 2, 1, 12, 1, 17), FracSec.from!"hnsecs"(700)));
+ testST(SysTime(DateTime(1, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(7000)), 5, SysTime(DateTime(1, 2, 27, 12, 5, 17), FracSec.from!"hnsecs"(7000)));
+ testST(SysTime(DateTime(1, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(70_000)), 1, SysTime(DateTime(1, 12, 1, 12, 1, 17), FracSec.from!"hnsecs"(70_000)));
+ testST(SysTime(DateTime(1, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(700_000)), 23, SysTime(DateTime(1, 12, 31, 12, 23, 17), FracSec.from!"hnsecs"(700_000)));
+
+ testST(SysTime(DateTime(999, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(9)), 6, SysTime(DateTime(999, 1, 7, 12, 6, 17), FracSec.from!"hnsecs"(9)));
+ testST(SysTime(DateTime(999, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(90)), 1, SysTime(DateTime(999, 1, 1, 12, 1, 17), FracSec.from!"hnsecs"(90)));
+ testST(SysTime(DateTime(999, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(900)), 1, SysTime(DateTime(999, 2, 1, 12, 1, 17), FracSec.from!"hnsecs"(900)));
+ testST(SysTime(DateTime(999, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(9000)), 5, SysTime(DateTime(999, 2, 27, 12, 5, 17), FracSec.from!"hnsecs"(9000)));
+ testST(SysTime(DateTime(999, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(90_000)), 1, SysTime(DateTime(999, 12, 1, 12, 1, 17), FracSec.from!"hnsecs"(90_000)));
+ testST(SysTime(DateTime(999, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(900_000)), 23, SysTime(DateTime(999, 12, 31, 12, 23, 17), FracSec.from!"hnsecs"(900_000)));
+
+ //Test B.C.
+ testST(SysTime(Date(0, 1, 1)), 1, SysTime(DateTime(0, 1, 1, 0, 1, 0)));
+ testST(SysTime(Date(0, 1, 1)), 7, SysTime(DateTime(0, 1, 1, 0, 7, 0)));
+ testST(SysTime(Date(0, 1, 1)), 12, SysTime(DateTime(0, 1, 1, 0, 12, 0)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(0, 1, 1, 0, 1, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 7, SysTime(DateTime(0, 1, 1, 0, 7, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 12, SysTime(DateTime(0, 1, 1, 0, 12, 0), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59)), 1, SysTime(DateTime(0, 12, 31, 23, 1, 59)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59)), 7, SysTime(DateTime(0, 12, 31, 23, 7, 59)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59)), 12, SysTime(DateTime(0, 12, 31, 23, 12, 59)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(0, 12, 31, 23, 1, 59), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 7, SysTime(DateTime(0, 12, 31, 23, 7, 59), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 12, SysTime(DateTime(0, 12, 31, 23, 12, 59), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(Date(0, 7, 2)), 7, SysTime(DateTime(0, 7, 2, 0, 7, 0)));
+ testST(SysTime(Date(-1202, 7, 2)), 1, SysTime(DateTime(-1202, 7, 2, 0, 1, 0)));
+
+ testST(SysTime(DateTime(0, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(7)), 6, SysTime(DateTime(0, 1, 7, 12, 6, 17), FracSec.from!"hnsecs"(7)));
+ testST(SysTime(DateTime(0, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(70)), 1, SysTime(DateTime(0, 1, 1, 12, 1, 17), FracSec.from!"hnsecs"(70)));
+ testST(SysTime(DateTime(0, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(700)), 1, SysTime(DateTime(0, 2, 1, 12, 1, 17), FracSec.from!"hnsecs"(700)));
+ testST(SysTime(DateTime(0, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(7000)), 5, SysTime(DateTime(0, 2, 27, 12, 5, 17), FracSec.from!"hnsecs"(7000)));
+ testST(SysTime(DateTime(0, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(70_000)), 1, SysTime(DateTime(0, 12, 1, 12, 1, 17), FracSec.from!"hnsecs"(70_000)));
+ testST(SysTime(DateTime(0, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(700_000)), 23, SysTime(DateTime(0, 12, 31, 12, 23, 17), FracSec.from!"hnsecs"(700_000)));
+
+ testST(SysTime(DateTime(-1, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(9)), 6, SysTime(DateTime(-1, 1, 7, 12, 6, 17), FracSec.from!"hnsecs"(9)));
+ testST(SysTime(DateTime(-1, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(90)), 1, SysTime(DateTime(-1, 1, 1, 12, 1, 17), FracSec.from!"hnsecs"(90)));
+ testST(SysTime(DateTime(-1, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(900)), 1, SysTime(DateTime(-1, 2, 1, 12, 1, 17), FracSec.from!"hnsecs"(900)));
+ testST(SysTime(DateTime(-1, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(9000)), 5, SysTime(DateTime(-1, 2, 27, 12, 5, 17), FracSec.from!"hnsecs"(9000)));
+ testST(SysTime(DateTime(-1, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(90_000)), 1, SysTime(DateTime(-1, 12, 1, 12, 1, 17), FracSec.from!"hnsecs"(90_000)));
+ testST(SysTime(DateTime(-1, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(900_000)), 23, SysTime(DateTime(-1, 12, 31, 12, 23, 17), FracSec.from!"hnsecs"(900_000)));
+
+ testST(SysTime(0, UTC()), 12, SysTime(DateTime(1, 1, 1, 0, 12, 0), UTC()));
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst.minute = 27));
+ //static assert(!__traits(compiles, ist.minute = 27));
+ }
+
+
+ /++
+ Seconds past the current minute.
+ +/
+ @property ubyte second() const nothrow
+ {
+ auto hnsecs = adjTime;
+ auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
+
+ if(hnsecs < 0)
+ {
+ hnsecs += convert!("hours", "hnsecs")(24);
+ --days;
+ }
+
+ hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
+ hnsecs = removeUnitsFromHNSecs!"minutes"(hnsecs);
+
+ return cast(ubyte)getUnitsFromHNSecs!"seconds"(hnsecs);
+ }
+
+ unittest
+ {
+ assertPred!"=="(SysTime(0, UTC()).second, 0);
+ assertPred!"=="(SysTime(1, UTC()).second, 0);
+ assertPred!"=="(SysTime(-1, UTC()).second, 59);
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 0, 0, 33)).second, 33);
+ assertPred!"=="(SysTime(DateTime(0, 1, 1, 0, 0, 33)).second, 33);
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cst.second));
+ //static assert(__traits(compiles, ist.second));
+ }
+
+
+ /++
+ Seconds past the current minute.
+
+ Params
+ second = The second to set this SysTime's second to.
+
+ Throws:
+ DateTimeException if the given second are not a valid second of a minute.
+ +/
+ @property void second(int second)
+ {
+ enforceValid!"seconds"(second);
+
+ auto hnsecs = adjTime;
+ auto days = splitUnitsFromHNSecs!"days"(hnsecs);
+ immutable daysHNSecs = convert!("days", "hnsecs")(days);
+ immutable negative = hnsecs < 0;
+
+ if(negative)
+ hnsecs += convert!("hours", "hnsecs")(24);
+
+ immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
+ immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
+ hnsecs = removeUnitsFromHNSecs!"seconds"(hnsecs);
+
+ hnsecs += convert!("hours", "hnsecs")(hour);
+ hnsecs += convert!("minutes", "hnsecs")(minute);
+ hnsecs += convert!("seconds", "hnsecs")(second);
+
+ if(negative)
+ hnsecs -= convert!("hours", "hnsecs")(24);
+
+ adjTime = daysHNSecs + hnsecs;
+ }
+
+ unittest
+ {
+ static void testSTInvalid(SysTime st, int second)
+ {
+ st.second = second;
+ }
+
+ static void testST(SysTime st, int second, in SysTime expected, size_t line = __LINE__)
+ {
+ st.second = second;
+ assertPred!"=="(st, expected, "", __FILE__, line);
+ }
+
+ assertThrown!DateTimeException(testSTInvalid(SysTime(Date(1999, 7, 6)), 60));
+
+ //Test A.D.
+ testST(SysTime(Date(1, 1, 1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 1)));
+ testST(SysTime(Date(1, 1, 1)), 7, SysTime(DateTime(1, 1, 1, 0, 0, 7)));
+ testST(SysTime(Date(1, 1, 1)), 12, SysTime(DateTime(1, 1, 1, 0, 0, 12)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 1), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 7, SysTime(DateTime(1, 1, 1, 0, 0, 7), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 12, SysTime(DateTime(1, 1, 1, 0, 0, 12), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59)), 1, SysTime(DateTime(1, 12, 31, 23, 59, 1)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59)), 7, SysTime(DateTime(1, 12, 31, 23, 59, 7)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59)), 12, SysTime(DateTime(1, 12, 31, 23, 59, 12)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(1, 12, 31, 23, 59, 1), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 7, SysTime(DateTime(1, 12, 31, 23, 59, 7), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 12, SysTime(DateTime(1, 12, 31, 23, 59, 12), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(Date(1, 7, 2)), 12, SysTime(DateTime(1, 7, 2, 0, 0, 12)));
+ testST(SysTime(Date(5007, 7, 2)), 5, SysTime(DateTime(5007, 7, 2, 0, 0, 5)));
+
+ testST(SysTime(DateTime(1, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(7)), 6, SysTime(DateTime(1, 1, 7, 12, 22, 6), FracSec.from!"hnsecs"(7)));
+ testST(SysTime(DateTime(1, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(70)), 1, SysTime(DateTime(1, 1, 1, 12, 22, 1), FracSec.from!"hnsecs"(70)));
+ testST(SysTime(DateTime(1, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(700)), 1, SysTime(DateTime(1, 2, 1, 12, 22, 1), FracSec.from!"hnsecs"(700)));
+ testST(SysTime(DateTime(1, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(7000)), 5, SysTime(DateTime(1, 2, 27, 12, 22, 5), FracSec.from!"hnsecs"(7000)));
+ testST(SysTime(DateTime(1, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(70_000)), 1, SysTime(DateTime(1, 12, 1, 12, 22, 1), FracSec.from!"hnsecs"(70_000)));
+ testST(SysTime(DateTime(1, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(700_000)), 23, SysTime(DateTime(1, 12, 31, 12, 22, 23), FracSec.from!"hnsecs"(700_000)));
+
+ testST(SysTime(DateTime(999, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(9)), 6, SysTime(DateTime(999, 1, 7, 12, 22, 6), FracSec.from!"hnsecs"(9)));
+ testST(SysTime(DateTime(999, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(90)), 1, SysTime(DateTime(999, 1, 1, 12, 22, 1), FracSec.from!"hnsecs"(90)));
+ testST(SysTime(DateTime(999, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(900)), 1, SysTime(DateTime(999, 2, 1, 12, 22, 1), FracSec.from!"hnsecs"(900)));
+ testST(SysTime(DateTime(999, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(9000)), 5, SysTime(DateTime(999, 2, 27, 12, 22, 5), FracSec.from!"hnsecs"(9000)));
+ testST(SysTime(DateTime(999, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(90_000)), 1, SysTime(DateTime(999, 12, 1, 12, 22, 1), FracSec.from!"hnsecs"(90_000)));
+ testST(SysTime(DateTime(999, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(900_000)), 23, SysTime(DateTime(999, 12, 31, 12, 22, 23), FracSec.from!"hnsecs"(900_000)));
+
+ //Test B.C.
+ testST(SysTime(Date(0, 1, 1)), 1, SysTime(DateTime(0, 1, 1, 0, 0, 1)));
+ testST(SysTime(Date(0, 1, 1)), 7, SysTime(DateTime(0, 1, 1, 0, 0, 7)));
+ testST(SysTime(Date(0, 1, 1)), 12, SysTime(DateTime(0, 1, 1, 0, 0, 12)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(0, 1, 1, 0, 0, 1), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 7, SysTime(DateTime(0, 1, 1, 0, 0, 7), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 12, SysTime(DateTime(0, 1, 1, 0, 0, 12), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59)), 1, SysTime(DateTime(0, 12, 31, 23, 59, 1)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59)), 7, SysTime(DateTime(0, 12, 31, 23, 59, 7)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59)), 12, SysTime(DateTime(0, 12, 31, 23, 59, 12)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(0, 12, 31, 23, 59, 1), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 7, SysTime(DateTime(0, 12, 31, 23, 59, 7), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 12, SysTime(DateTime(0, 12, 31, 23, 59, 12), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(Date(0, 7, 2)), 7, SysTime(DateTime(0, 7, 2, 0, 0, 7)));
+ testST(SysTime(Date(-1202, 7, 2)), 1, SysTime(DateTime(-1202, 7, 2, 0, 0, 1)));
+
+ testST(SysTime(DateTime(0, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(7)), 6, SysTime(DateTime(0, 1, 7, 12, 22, 6), FracSec.from!"hnsecs"(7)));
+ testST(SysTime(DateTime(0, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(70)), 1, SysTime(DateTime(0, 1, 1, 12, 22, 1), FracSec.from!"hnsecs"(70)));
+ testST(SysTime(DateTime(0, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(700)), 1, SysTime(DateTime(0, 2, 1, 12, 22, 1), FracSec.from!"hnsecs"(700)));
+ testST(SysTime(DateTime(0, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(7000)), 5, SysTime(DateTime(0, 2, 27, 12, 22, 5), FracSec.from!"hnsecs"(7000)));
+ testST(SysTime(DateTime(0, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(70_000)), 1, SysTime(DateTime(0, 12, 1, 12, 22, 1), FracSec.from!"hnsecs"(70_000)));
+ testST(SysTime(DateTime(0, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(700_000)), 23, SysTime(DateTime(0, 12, 31, 12, 22, 23), FracSec.from!"hnsecs"(700_000)));
+
+ testST(SysTime(DateTime(-1, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(9)), 6, SysTime(DateTime(-1, 1, 7, 12, 22, 6), FracSec.from!"hnsecs"(9)));
+ testST(SysTime(DateTime(-1, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(90)), 1, SysTime(DateTime(-1, 1, 1, 12, 22, 1), FracSec.from!"hnsecs"(90)));
+ testST(SysTime(DateTime(-1, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(900)), 1, SysTime(DateTime(-1, 2, 1, 12, 22, 1), FracSec.from!"hnsecs"(900)));
+ testST(SysTime(DateTime(-1, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(9000)), 5, SysTime(DateTime(-1, 2, 27, 12, 22, 5), FracSec.from!"hnsecs"(9000)));
+ testST(SysTime(DateTime(-1, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(90_000)), 1, SysTime(DateTime(-1, 12, 1, 12, 22, 1), FracSec.from!"hnsecs"(90_000)));
+ testST(SysTime(DateTime(-1, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(900_000)), 23, SysTime(DateTime(-1, 12, 31, 12, 22, 23), FracSec.from!"hnsecs"(900_000)));
+
+ testST(SysTime(0, UTC()), 12, SysTime(DateTime(1, 1, 1, 0, 0, 12), UTC()));
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst.seconds = 27));
+ //static assert(!__traits(compiles, ist.seconds = 27));
+ }
+
+
+ /++
+ Fractional seconds passed the second.
+ +/
+ @property FracSec fracSec() const nothrow
+ {
+ try
+ {
+ auto hnsecs = removeUnitsFromHNSecs!"days"(adjTime);
+
+ if(hnsecs < 0)
+ hnsecs += convert!("hours", "hnsecs")(24);
+
+ hnsecs = removeUnitsFromHNSecs!"seconds"(hnsecs);
+
+ return FracSec.from!"hnsecs"(cast(int)hnsecs);
+ }
+ catch(Exception e)
+ assert(0, "FracSec.from!\"hnsecs\"() threw.");
+ }
+
+ unittest
+ {
+ assertPred!"=="(SysTime(0, UTC()).fracSec.hnsecs, 0);
+ assertPred!"=="(SysTime(1, UTC()).fracSec.hnsecs, 1);
+ assertPred!"=="(SysTime(-1, UTC()).fracSec.hnsecs, 9_999_999);
+
+ assertPred!"=="(SysTime(DateTime(200, 3, 30, 1, 27, 19), FracSec.from!"hnsecs"(348), UTC()).fracSec.hnsecs, 348);
+ assertPred!"=="(SysTime(DateTime(-1, 2, 17, 4, 5, 22), FracSec.from!"hnsecs"(347), UTC()).fracSec.hnsecs, 347);
+
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 0, 0, 33), FracSec.from!"hnsecs"(502)).fracSec, FracSec.from!"hnsecs"(502));
+ assertPred!"=="(SysTime(DateTime(0, 1, 1, 0, 0, 33), FracSec.from!"hnsecs"(502)).fracSec, FracSec.from!"hnsecs"(502));
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cst.fracSec));
+ //static assert(__traits(compiles, ist.fracSec));
+ }
+
+
+ /++
+ Fractional seconds passed the second.
+
+ Params
+ fracSec = The fractional seconds to set this SysTimes's fractional
+ seconds to.
+ +/
+ @property void fracSec(FracSec fracSec) nothrow
+ {
+ auto hnsecs = adjTime;
+ auto days = splitUnitsFromHNSecs!"days"(hnsecs);
+ immutable daysHNSecs = convert!("days", "hnsecs")(days);
+ immutable negative = hnsecs < 0;
+
+ if(negative)
+ hnsecs += convert!("hours", "hnsecs")(24);
+
+ immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
+ immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
+ immutable second = getUnitsFromHNSecs!"seconds"(hnsecs);
+
+ hnsecs = fracSec.hnsecs;
+ hnsecs += convert!("hours", "hnsecs")(hour);
+ hnsecs += convert!("minutes", "hnsecs")(minute);
+ hnsecs += convert!("seconds", "hnsecs")(second);
+
+ if(negative)
+ hnsecs -= convert!("hours", "hnsecs")(24);
+
+ adjTime = daysHNSecs + hnsecs;
+ }
+
+ unittest
+ {
+ static void testST(SysTime st, int hnsecs, in SysTime expected, size_t line = __LINE__)
+ {
+ st.fracSec = FracSec.from!"hnsecs"(hnsecs);
+ assertPred!"=="(st, expected, "", __FILE__, line);
+ }
+
+ //Test A.D.
+ testST(SysTime(Date(1, 1, 1)), 0, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(Date(1, 1, 1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(Date(1, 1, 1)), 7, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(7)));
+ testST(SysTime(Date(1, 1, 1)), 12, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(12)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 7, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(7)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 12, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(12)));
+
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59)), 0, SysTime(DateTime(1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59)), 1, SysTime(DateTime(1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59)), 7, SysTime(DateTime(1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(7)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59)), 12, SysTime(DateTime(1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(12)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 7, SysTime(DateTime(1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(7)));
+ testST(SysTime(DateTime(1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 12, SysTime(DateTime(1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(12)));
+
+ testST(SysTime(Date(1, 7, 2)), 12, SysTime(DateTime(1, 7, 2, 0, 0, 0), FracSec.from!"hnsecs"(12)));
+ testST(SysTime(Date(5007, 7, 2)), 5, SysTime(DateTime(5007, 7, 2, 0, 0, 0), FracSec.from!"hnsecs"(5)));
+
+ testST(SysTime(DateTime(1, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(7)), 6, SysTime(DateTime(1, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(6)));
+ testST(SysTime(DateTime(1, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(70)), 1, SysTime(DateTime(1, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(700)), 1, SysTime(DateTime(1, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(7000)), 5, SysTime(DateTime(1, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(5)));
+ testST(SysTime(DateTime(1, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(70_000)), 1, SysTime(DateTime(1, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(700_000)), 23, SysTime(DateTime(1, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(23)));
+
+ testST(SysTime(DateTime(999, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(9)), 6, SysTime(DateTime(999, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(6)));
+ testST(SysTime(DateTime(999, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(90)), 1, SysTime(DateTime(999, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(999, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(900)), 1, SysTime(DateTime(999, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(999, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(9000)), 5, SysTime(DateTime(999, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(5)));
+ testST(SysTime(DateTime(999, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(90_000)), 1, SysTime(DateTime(999, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(999, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(900_000)), 23, SysTime(DateTime(999, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(23)));
+
+ //Test B.C.
+ testST(SysTime(Date(0, 1, 1)), 0, SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(Date(0, 1, 1)), 1, SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(Date(0, 1, 1)), 7, SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(7)));
+ testST(SysTime(Date(0, 1, 1)), 12, SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(12)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 0, SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 7, SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(7)));
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 12, SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(12)));
+
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59)), 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59)), 7, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(7)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59)), 12, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(12)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 7, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(7)));
+ testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)), 12, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(12)));
+
+ testST(SysTime(Date(0, 7, 2)), 7, SysTime(DateTime(0, 7, 2, 0, 0, 0), FracSec.from!"hnsecs"(7)));
+ testST(SysTime(Date(-1202, 7, 2)), 1, SysTime(DateTime(-1202, 7, 2, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+
+ testST(SysTime(DateTime(0, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(7)), 6, SysTime(DateTime(0, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(6)));
+ testST(SysTime(DateTime(0, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(70)), 1, SysTime(DateTime(0, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(700)), 1, SysTime(DateTime(0, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(7000)), 5, SysTime(DateTime(0, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(5)));
+ testST(SysTime(DateTime(0, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(70_000)), 1, SysTime(DateTime(0, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(700_000)), 23, SysTime(DateTime(0, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(23)));
+
+ testST(SysTime(DateTime(-1, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(9)), 6, SysTime(DateTime(-1, 1, 7, 12, 22, 17), FracSec.from!"hnsecs"(6)));
+ testST(SysTime(DateTime(-1, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(90)), 1, SysTime(DateTime(-1, 1, 1, 12, 22, 17), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(-1, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(900)), 1, SysTime(DateTime(-1, 2, 1, 12, 22, 17), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(-1, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(9000)), 5, SysTime(DateTime(-1, 2, 27, 12, 22, 17), FracSec.from!"hnsecs"(5)));
+ testST(SysTime(DateTime(-1, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(90_000)), 1, SysTime(DateTime(-1, 12, 1, 12, 22, 17), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(-1, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(900_000)), 23, SysTime(DateTime(-1, 12, 31, 12, 22, 17), FracSec.from!"hnsecs"(23)));
+
+ testST(SysTime(0, UTC()), 12, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(12), UTC()));
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst.fracSec = FracSec.from!"msecs"(7)));
+ //static assert(!__traits(compiles, ist.fracSec = FracSec.from!"msecs"(7)));
+ }
+
+
+ /++
+ The total hnsecs from midnight, January 1st, 1 A.D. UTC. This is the internal
+ representation of SysTime.
+ +/
+ @property long stdTime() const pure nothrow
+ {
+ return _stdTime;
+ }
+
+ unittest
+ {
+ assertPred!"=="(SysTime(0).stdTime, 0);
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 0, 0, 33), FracSec.from!"hnsecs"(502), UTC()).stdTime, 330000502L);
+ assertPred!"=="(SysTime(DateTime(1970, 1, 1, 0, 0, 0), UTC()).stdTime, 621355968000000000L);
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cst.stdTime));
+ //static assert(__traits(compiles, ist.stdTime));
+ }
+
+
+ /++
+ The total hnsecs from midnight, January 1st, 1 A.D. UTC. This is the internal
+ representation of SysTime.
+
+ Params
+ stdTime = The number of hnsecs since January 1st, 1 A.D. UTC.
+ +/
+ @property void stdTime(long stdTime) pure nothrow
+ {
+ _stdTime = stdTime;
+ }
+
+ unittest
+ {
+ {
+ auto st = SysTime(0, UTC());
+ st.stdTime = 330000502L;
+ assertPred!"=="(st, SysTime(DateTime(1, 1, 1, 0, 0, 33), FracSec.from!"hnsecs"(502), UTC()));
+ }
+
+ {
+ auto st = SysTime(0, UTC());
+ st.stdTime = 621355968000000000L;
+ assertPred!"=="(st, SysTime(DateTime(1970, 1, 1, 0, 0, 0), UTC()));
+ }
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst.stdTime = 27));
+ //static assert(!__traits(compiles, ist.stdTime = 27));
+ }
+
+
+ /++
+ The current time zone of this SysTime. Its internal time is always kept
+ in UTC, so there are no conversion issues between time zones due to DST.
+ Functions which return all or part of the time - such as hours - adjust
+ the time to this SysTime's time zone before returning.
+ +/
+ @property immutable(TimeZone) timezone() const pure nothrow
+ {
+ return _timezone.get;
+ }
+
+
+ /++
+ The current time zone of this SysTime. It's internal time is always kept
+ in UTC, so there are no conversion issues between time zones due to DST.
+ Functions which return all or part of the time - such as hours - adjust
+ the time to this SysTime's time zone before returning.
+ +/
+ @property void timezone(immutable TimeZone timezone) pure nothrow
+ {
+ _timezone = timezone;
+ }
+
+
+ /++
+ Returns whether DST is in effect for this SysTime.
+ +/
+ @property bool dstInEffect() const nothrow
+ {
+ return _timezone.dstInEffect(_stdTime);
+ //This function's unit testing is done in the time zone classes.
+ }
+
+
+ /++
+ Returns a SysTime with the same std time as this one, but with LocalTime
+ as its time zone.
+ +/
+ SysTime toLocalTime() const nothrow
+ {
+ return SysTime(_stdTime, LocalTime());
+ }
+
+ unittest
+ {
+ {
+ auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), FracSec.from!"hnsecs"(27));
+ assertPred!"=="(sysTime, sysTime.toLocalTime());
+ assertPred!"=="(sysTime._stdTime, sysTime.toLocalTime()._stdTime);
+ assert(sysTime.toLocalTime().timezone is LocalTime());
+ assert(sysTime.toLocalTime().timezone is sysTime.timezone);
+ assert(sysTime.toLocalTime().timezone !is UTC());
+ }
+
+ {
+ immutable stz = new SimpleTimeZone(-3 * 60);
+ auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), FracSec.from!"hnsecs"(27), stz);
+ assertPred!"=="(sysTime, sysTime.toLocalTime());
+ assertPred!"=="(sysTime._stdTime, sysTime.toLocalTime()._stdTime);
+ assert(sysTime.toLocalTime().timezone is LocalTime());
+ assert(sysTime.toLocalTime().timezone !is UTC());
+ assert(sysTime.toLocalTime().timezone !is stz);
+ }
+ }
+
+
+ /++
+ Returns a SysTime with the same std time as this one, but with UTC as
+ its time zone.
+ +/
+ SysTime toUTC() const pure nothrow
+ {
+ return SysTime(_stdTime, UTC());
+ }
+
+ unittest
+ {
+ auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), FracSec.from!"hnsecs"(27));
+ assertPred!"=="(sysTime, sysTime.toUTC());
+ assertPred!"=="(sysTime._stdTime, sysTime.toUTC()._stdTime);
+ assert(sysTime.toUTC().timezone is UTC());
+ assert(sysTime.toUTC().timezone !is LocalTime());
+ assert(sysTime.toUTC().timezone !is sysTime.timezone);
+ }
+
+
+ /++
+ Returns a SysTime with the same std time as this one, but with given
+ time zone as its time zone.
+ +/
+ SysTime toOtherTZ(immutable TimeZone tz) const pure nothrow
+ {
+ return SysTime(_stdTime, tz);
+ }
+
+ unittest
+ {
+ immutable stz = new SimpleTimeZone(11 * 60);
+ auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), FracSec.from!"hnsecs"(27));
+ assertPred!"=="(sysTime, sysTime.toOtherTZ(stz));
+ assertPred!"=="(sysTime._stdTime, sysTime.toOtherTZ(stz)._stdTime);
+ assert(sysTime.toOtherTZ(stz).timezone is stz);
+ assert(sysTime.toOtherTZ(stz).timezone !is LocalTime());
+ assert(sysTime.toOtherTZ(stz).timezone !is UTC());
+ }
+
+
+ /++
+ Returns a time_t which represents this SysTime.
+
+ If time_t is 32 bits, rather than 64, and the result can't fit in a 32-bit value, then the
+ closest value that can be held in 32 bits will be used (so time_t.max if it goes over or time_t.min
+ if it goes under).
+ +/
+ time_t toUnixTime() const pure nothrow
+ {
+ return stdTimeToUnixTime(_stdTime);
+ }
+
+ unittest
+ {
+ assertPred!"=="(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime, 0);
+ assertPred!"=="(SysTime(DateTime(1970, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1), UTC()).toUnixTime, 0);
+ assertPred!"=="(SysTime(DateTime(1970, 1, 1, 0, 0, 0), FracSec.from!"usecs"(1), UTC()).toUnixTime, 0);
+ assertPred!"=="(SysTime(DateTime(1970, 1, 1, 0, 0, 0), FracSec.from!"msecs"(1), UTC()).toUnixTime, 0);
+ assertPred!"=="(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toUnixTime, 1);
+ assertPred!"=="(SysTime(DateTime(1969, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999), UTC()).toUnixTime, 0);
+ assertPred!"=="(SysTime(DateTime(1969, 12, 31, 23, 59, 59), FracSec.from!"usecs"(999_999), UTC()).toUnixTime, 0);
+ assertPred!"=="(SysTime(DateTime(1969, 12, 31, 23, 59, 59), FracSec.from!"msecs"(999), UTC()).toUnixTime, 0);
+ assertPred!"=="(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toUnixTime, -1);
+ }
+
+
+ /++
+ Returns a tm which represents this SysTime.
+ +/
+ tm toTM() const nothrow
+ {
+ try
+ {
+ auto dateTime = cast(DateTime)this;
+ tm timeInfo;
+
+ timeInfo.tm_sec = dateTime.second;
+ timeInfo.tm_min = dateTime.minute;
+ timeInfo.tm_hour = dateTime.hour;
+ timeInfo.tm_mday = dateTime.day;
+ timeInfo.tm_mon = dateTime.month - 1;
+ timeInfo.tm_year = dateTime.year - 1900;
+ timeInfo.tm_wday = dateTime.dayOfWeek;
+ timeInfo.tm_yday = dateTime.dayOfYear - 1;
+ timeInfo.tm_isdst = _timezone.dstInEffect(_stdTime);
+
+ version(Posix)
+ {
+ char[] zone = (timeInfo.tm_isdst ? _timezone.dstName : _timezone.stdName).dup;
+ zone ~= "\0";
+
+ timeInfo.tm_gmtoff = cast(int)convert!("hnsecs", "seconds")(adjTime - _stdTime);
+ timeInfo.tm_zone = zone.ptr;
+ }
+
+ return timeInfo;
+ }
+ catch(Exception e)
+ assert(0, "Either DateTime's constructor threw.");
+ }
+
+ unittest
+ {
+ version(Posix)
+ {
+ scope(exit) clearTZEnvVar();
+ setTZEnvVar("America/Los_Angeles");
+ }
+
+ {
+ auto timeInfo = SysTime(DateTime(1970, 1, 1)).toTM();
+
+ assertPred!"=="(timeInfo.tm_sec, 0);
+ assertPred!"=="(timeInfo.tm_min, 0);
+ assertPred!"=="(timeInfo.tm_hour, 0);
+ assertPred!"=="(timeInfo.tm_mday, 1);
+ assertPred!"=="(timeInfo.tm_mon, 0);
+ assertPred!"=="(timeInfo.tm_year, 70);
+ assertPred!"=="(timeInfo.tm_wday, 4);
+ assertPred!"=="(timeInfo.tm_yday, 0);
+
+ version(Posix)
+ assertPred!"=="(timeInfo.tm_isdst, 0);
+ else version(Windows)
+ assert(timeInfo.tm_isdst == 0 || timeInfo.tm_isdst == 1);
+
+ version(Posix)
+ {
+ assertPred!"=="(timeInfo.tm_gmtoff, -8 * 60 * 60);
+ assertPred!"=="(to!string(timeInfo.tm_zone), "PST");
+ }
+ }
+
+ {
+ auto timeInfo = SysTime(DateTime(2010, 7, 4, 12, 15, 7), FracSec.from!"hnsecs"(15)).toTM();
+
+ assertPred!"=="(timeInfo.tm_sec, 7);
+ assertPred!"=="(timeInfo.tm_min, 15);
+ assertPred!"=="(timeInfo.tm_hour, 12);
+ assertPred!"=="(timeInfo.tm_mday, 4);
+ assertPred!"=="(timeInfo.tm_mon, 6);
+ assertPred!"=="(timeInfo.tm_year, 110);
+ assertPred!"=="(timeInfo.tm_wday, 0);
+ assertPred!"=="(timeInfo.tm_yday, 184);
+
+ version(Posix)
+ assertPred!"=="(timeInfo.tm_isdst, 1);
+ else version(Windows)
+ assert(timeInfo.tm_isdst == 0 || timeInfo.tm_isdst == 1);
+
+ version(Posix)
+ {
+ assertPred!"=="(timeInfo.tm_gmtoff, -7 * 60 * 60);
+ assertPred!"=="(to!string(timeInfo.tm_zone), "PDT");
+ }
+ }
+ }
+
+
+ /++
+ Adds the given number of years or months to this SysTime. A negative
+ number will subtract.
+
+ Note that if day overflow is allowed, and the date with the adjusted
+ year/month overflows the number of days in the new month, then the month
+ will be incremented by one, and the days set to the number of days overflowed.
+ (e.g. if the day were 31 and the new month were June, then the month would
+ be incremented to July, and the new day would be 1). If day overflow is not
+ allowed, then the day will be set to the last valid day in the month
+ (e.g. June 31st would become June 30th).
+
+ Params:
+ units = The type of units to add ("years" or "months").
+ value = The number of months or years to add to this SysTime.
+ allowOverflow = Whether the days should be allowed to overflow, causing
+ the month to increment.
+
+ Examples:
+--------------------
+auto st1 = SysTime(DateTime(2010, 1, 1, 12, 30, 33));
+st1.add!"months"(11);
+assert(st1 == SysTime(DateTime(2010, 12, 1, 12, 30, 33)));
+
+auto st2 = SysTime(DateTime(2010, 1, 1, 12, 30, 33));
+st2.add!"months"(-11);
+assert(st2 == SysTime(DateTime(2009, 2, 1, 12, 30, 33)));
+
+auto st3 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
+st3.add!"years"(1);
+assert(st3 == SysTime(DateTime(2001, 3, 1, 12, 30, 33)));
+
+auto st4 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
+st4.add!"years"(1, AllowDayOverflow.no);
+assert(st4 == SysTime(DateTime(2001, 2, 28, 12, 30, 33)));
+--------------------
+ +/
+ ref SysTime add(string units)(long years, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) nothrow
+ if(units == "years" ||
+ units == "months")
+ {
+ auto hnsecs = adjTime;
+ auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
+
+ if(hnsecs < 0)
+ {
+ hnsecs += convert!("hours", "hnsecs")(24);
+ --days;
+ }
+
+ auto date = Date(cast(int)days);
+ date.add!units(years, allowOverflow);
+ days = date.dayOfGregorianCal - 1;
+
+ if(days < 0)
+ {
+ hnsecs -= convert!("hours", "hnsecs")(24);
+ ++days;
+ }
+
+ immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
+
+ adjTime = newDaysHNSecs + hnsecs;
+
+ return this;
+ }
+
+ //Test add!"years"() with AllowDayOverlow.yes
+ unittest
+ {
+ //Test A.D.
+ {
+ auto sysTime = SysTime(Date(1999, 7, 6));
+ sysTime.add!"years"(7);
+ assertPred!"=="(sysTime, SysTime(Date(2006, 7, 6)));
+ sysTime.add!"years"(-9);
+ assertPred!"=="(sysTime, SysTime(Date(1997, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 2, 28));
+ sysTime.add!"years"(1);
+ assertPred!"=="(sysTime, SysTime(Date(2000, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(2000, 2, 29));
+ sysTime.add!"years"(-1);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 3, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 7, 3), FracSec.from!"msecs"(234));
+ sysTime.add!"years"(7);
+ assertPred!"=="(sysTime, SysTime(DateTime(2006, 7, 6, 12, 7, 3), FracSec.from!"msecs"(234)));
+ sysTime.add!"years"(-9);
+ assertPred!"=="(sysTime, SysTime(DateTime(1997, 7, 6, 12, 7, 3), FracSec.from!"msecs"(234)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1999, 2, 28, 0, 7, 2), FracSec.from!"usecs"(1207));
+ sysTime.add!"years"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(2000, 2, 28, 0, 7, 2), FracSec.from!"usecs"(1207)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(2000, 2, 29, 0, 7, 2), FracSec.from!"usecs"(1207));
+ sysTime.add!"years"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 3, 1, 0, 7, 2), FracSec.from!"usecs"(1207)));
+ }
+
+ //Test B.C.
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 6));
+ sysTime.add!"years"(-7);
+ assertPred!"=="(sysTime, SysTime(Date(-2006, 7, 6)));
+ sysTime.add!"years"(9);
+ assertPred!"=="(sysTime, SysTime(Date(-1997, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 2, 28));
+ sysTime.add!"years"(-1);
+ assertPred!"=="(sysTime, SysTime(Date(-2000, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-2000, 2, 29));
+ sysTime.add!"years"(1);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 3, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 7, 3), FracSec.from!"msecs"(234));
+ sysTime.add!"years"(-7);
+ assertPred!"=="(sysTime, SysTime(DateTime(-2006, 7, 6, 12, 7, 3), FracSec.from!"msecs"(234)));
+ sysTime.add!"years"(9);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1997, 7, 6, 12, 7, 3), FracSec.from!"msecs"(234)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-1999, 2, 28, 3, 3, 3), FracSec.from!"hnsecs"(3));
+ sysTime.add!"years"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(-2000, 2, 28, 3, 3, 3), FracSec.from!"hnsecs"(3)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-2000, 2, 29, 3, 3, 3), FracSec.from!"hnsecs"(3));
+ sysTime.add!"years"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1999, 3, 1, 3, 3, 3), FracSec.from!"hnsecs"(3)));
+ }
+
+ //Test Both
+ {
+ auto sysTime = SysTime(Date(4, 7, 6));
+ sysTime.add!"years"(-5);
+ assertPred!"=="(sysTime, SysTime(Date(-1, 7, 6)));
+ sysTime.add!"years"(5);
+ assertPred!"=="(sysTime, SysTime(Date(4, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-4, 7, 6));
+ sysTime.add!"years"(5);
+ assertPred!"=="(sysTime, SysTime(Date(1, 7, 6)));
+ sysTime.add!"years"(-5);
+ assertPred!"=="(sysTime, SysTime(Date(-4, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(4, 7, 6));
+ sysTime.add!"years"(-8);
+ assertPred!"=="(sysTime, SysTime(Date(-4, 7, 6)));
+ sysTime.add!"years"(8);
+ assertPred!"=="(sysTime, SysTime(Date(4, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-4, 7, 6));
+ sysTime.add!"years"(8);
+ assertPred!"=="(sysTime, SysTime(Date(4, 7, 6)));
+ sysTime.add!"years"(-8);
+ assertPred!"=="(sysTime, SysTime(Date(-4, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-4, 2, 29));
+ sysTime.add!"years"(5);
+ assertPred!"=="(sysTime, SysTime(Date(1, 3, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(4, 2, 29));
+ sysTime.add!"years"(-5);
+ assertPred!"=="(sysTime, SysTime(Date(-1, 3, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0));
+ sysTime.add!"years"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ sysTime.add!"years"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.add!"years"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.add!"years"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0));
+ sysTime.add!"years"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ sysTime.add!"years"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.add!"years"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.add!"years"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), FracSec.from!"usecs"(54329));
+ sysTime.add!"years"(-5);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1, 7, 6, 14, 7, 1), FracSec.from!"usecs"(54329)));
+ sysTime.add!"years"(5);
+ assertPred!"=="(sysTime, SysTime(DateTime(4, 7, 6, 14, 7, 1), FracSec.from!"usecs"(54329)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-4, 7, 6, 14, 7, 1), FracSec.from!"usecs"(54329));
+ sysTime.add!"years"(5);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 7, 6, 14, 7, 1), FracSec.from!"usecs"(54329)));
+ sysTime.add!"years"(-5);
+ assertPred!"=="(sysTime, SysTime(DateTime(-4, 7, 6, 14, 7, 1), FracSec.from!"usecs"(54329)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-4, 2, 29, 5, 5, 5), FracSec.from!"msecs"(555));
+ sysTime.add!"years"(5);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 3, 1, 5, 5, 5), FracSec.from!"msecs"(555)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), FracSec.from!"msecs"(555));
+ sysTime.add!"years"(-5);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1, 3, 1, 5, 5, 5), FracSec.from!"msecs"(555)));
+ }
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst.add!"years"(4)));
+ //static assert(!__traits(compiles, ist.add!"years"(4)));
+
+ //Verify Examples.
+ auto st1 = SysTime(DateTime(2010, 1, 1, 12, 30, 33));
+ st1.add!"months"(11);
+ assert(st1 == SysTime(DateTime(2010, 12, 1, 12, 30, 33)));
+
+ auto st2 = SysTime(DateTime(2010, 1, 1, 12, 30, 33));
+ st2.add!"months"(-11);
+ assert(st2 == SysTime(DateTime(2009, 2, 1, 12, 30, 33)));
+
+ auto st3 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
+ st3.add!"years"(1);
+ assert(st3 == SysTime(DateTime(2001, 3, 1, 12, 30, 33)));
+
+ auto st4 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
+ st4.add!"years"(1, AllowDayOverflow.no);
+ assert(st4 == SysTime(DateTime(2001, 2, 28, 12, 30, 33)));
+ }
+
+ //Test add!"years"() with AllowDayOverlow.no
+ unittest
+ {
+ //Test A.D.
+ {
+ auto sysTime = SysTime(Date(1999, 7, 6));
+ sysTime.add!"years"(7, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(2006, 7, 6)));
+ sysTime.add!"years"(-9, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1997, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 2, 28));
+ sysTime.add!"years"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(2000, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(2000, 2, 29));
+ sysTime.add!"years"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 7, 3), FracSec.from!"msecs"(234));
+ sysTime.add!"years"(7, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(2006, 7, 6, 12, 7, 3), FracSec.from!"msecs"(234)));
+ sysTime.add!"years"(-9, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1997, 7, 6, 12, 7, 3), FracSec.from!"msecs"(234)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1999, 2, 28, 0, 7, 2), FracSec.from!"usecs"(1207));
+ sysTime.add!"years"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(2000, 2, 28, 0, 7, 2), FracSec.from!"usecs"(1207)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(2000, 2, 29, 0, 7, 2), FracSec.from!"usecs"(1207));
+ sysTime.add!"years"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 2, 28, 0, 7, 2), FracSec.from!"usecs"(1207)));
+ }
+
+ //Test B.C.
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 6));
+ sysTime.add!"years"(-7, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-2006, 7, 6)));
+ sysTime.add!"years"(9, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1997, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 2, 28));
+ sysTime.add!"years"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-2000, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-2000, 2, 29));
+ sysTime.add!"years"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 7, 3), FracSec.from!"msecs"(234));
+ sysTime.add!"years"(-7, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-2006, 7, 6, 12, 7, 3), FracSec.from!"msecs"(234)));
+ sysTime.add!"years"(9, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1997, 7, 6, 12, 7, 3), FracSec.from!"msecs"(234)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-1999, 2, 28, 3, 3, 3), FracSec.from!"hnsecs"(3));
+ sysTime.add!"years"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-2000, 2, 28, 3, 3, 3), FracSec.from!"hnsecs"(3)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-2000, 2, 29, 3, 3, 3), FracSec.from!"hnsecs"(3));
+ sysTime.add!"years"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1999, 2, 28, 3, 3, 3), FracSec.from!"hnsecs"(3)));
+ }
+
+ //Test Both
+ {
+ auto sysTime = SysTime(Date(4, 7, 6));
+ sysTime.add!"years"(-5, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1, 7, 6)));
+ sysTime.add!"years"(5, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(4, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-4, 7, 6));
+ sysTime.add!"years"(5, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1, 7, 6)));
+ sysTime.add!"years"(-5, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-4, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(4, 7, 6));
+ sysTime.add!"years"(-8, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-4, 7, 6)));
+ sysTime.add!"years"(8, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(4, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-4, 7, 6));
+ sysTime.add!"years"(8, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(4, 7, 6)));
+ sysTime.add!"years"(-8, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-4, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-4, 2, 29));
+ sysTime.add!"years"(5, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(4, 2, 29));
+ sysTime.add!"years"(-5, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0));
+ sysTime.add!"years"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ sysTime.add!"years"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.add!"years"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.add!"years"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0));
+ sysTime.add!"years"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ sysTime.add!"years"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.add!"years"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.add!"years"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), FracSec.from!"usecs"(54329));
+ sysTime.add!"years"(-5);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1, 7, 6, 14, 7, 1), FracSec.from!"usecs"(54329)));
+ sysTime.add!"years"(5);
+ assertPred!"=="(sysTime, SysTime(DateTime(4, 7, 6, 14, 7, 1), FracSec.from!"usecs"(54329)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), FracSec.from!"usecs"(54329));
+ sysTime.add!"years"(-5, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1, 7, 6, 14, 7, 1), FracSec.from!"usecs"(54329)));
+ sysTime.add!"years"(5, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(4, 7, 6, 14, 7, 1), FracSec.from!"usecs"(54329)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-4, 7, 6, 14, 7, 1), FracSec.from!"usecs"(54329));
+ sysTime.add!"years"(5, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 7, 6, 14, 7, 1), FracSec.from!"usecs"(54329)));
+ sysTime.add!"years"(-5, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-4, 7, 6, 14, 7, 1), FracSec.from!"usecs"(54329)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-4, 2, 29, 5, 5, 5), FracSec.from!"msecs"(555));
+ sysTime.add!"years"(5, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 2, 28, 5, 5, 5), FracSec.from!"msecs"(555)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), FracSec.from!"msecs"(555));
+ sysTime.add!"years"(-5, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1, 2, 28, 5, 5, 5), FracSec.from!"msecs"(555)));
+ }
+ }
+
+ //Test add!"months"() with AllowDayOverlow.yes
+ unittest
+ {
+ //Test A.D.
+ {
+ auto sysTime = SysTime(Date(1999, 7, 6));
+ sysTime.add!"months"(3);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 10, 6)));
+ sysTime.add!"months"(-4);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 6, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 7, 6));
+ sysTime.add!"months"(6);
+ assertPred!"=="(sysTime, SysTime(Date(2000, 1, 6)));
+ sysTime.add!"months"(-6);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 7, 6));
+ sysTime.add!"months"(27);
+ assertPred!"=="(sysTime, SysTime(Date(2001, 10, 6)));
+ sysTime.add!"months"(-28);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 6, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 5, 31));
+ sysTime.add!"months"(1);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 7, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 5, 31));
+ sysTime.add!"months"(-1);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 5, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 2, 28));
+ sysTime.add!"months"(12);
+ assertPred!"=="(sysTime, SysTime(Date(2000, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(2000, 2, 29));
+ sysTime.add!"months"(12);
+ assertPred!"=="(sysTime, SysTime(Date(2001, 3, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 7, 31));
+ sysTime.add!"months"(1);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 8, 31)));
+ sysTime.add!"months"(1);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 10, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1998, 8, 31));
+ sysTime.add!"months"(13);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 10, 1)));
+ sysTime.add!"months"(-13);
+ assertPred!"=="(sysTime, SysTime(Date(1998, 9, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1997, 12, 31));
+ sysTime.add!"months"(13);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 1, 31)));
+ sysTime.add!"months"(-13);
+ assertPred!"=="(sysTime, SysTime(Date(1997, 12, 31)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1997, 12, 31));
+ sysTime.add!"months"(14);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 3, 3)));
+ sysTime.add!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(Date(1998, 1, 3)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1998, 12, 31));
+ sysTime.add!"months"(14);
+ assertPred!"=="(sysTime, SysTime(Date(2000, 3, 2)));
+ sysTime.add!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 1, 2)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 12, 31));
+ sysTime.add!"months"(14);
+ assertPred!"=="(sysTime, SysTime(Date(2001, 3, 3)));
+ sysTime.add!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(Date(2000, 1, 3)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), FracSec.from!"usecs"(5007));
+ sysTime.add!"months"(3);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 10, 6, 12, 2, 7), FracSec.from!"usecs"(5007)));
+ sysTime.add!"months"(-4);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 6, 6, 12, 2, 7), FracSec.from!"usecs"(5007)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), FracSec.from!"hnsecs"(422202));
+ sysTime.add!"months"(14);
+ assertPred!"=="(sysTime, SysTime(DateTime(2000, 3, 2, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ sysTime.add!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 1, 2, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), FracSec.from!"hnsecs"(422202));
+ sysTime.add!"months"(14);
+ assertPred!"=="(sysTime, SysTime(DateTime(2001, 3, 3, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ sysTime.add!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(DateTime(2000, 1, 3, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ }
+
+ //Test B.C.
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 6));
+ sysTime.add!"months"(3);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 10, 6)));
+ sysTime.add!"months"(-4);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 6, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 6));
+ sysTime.add!"months"(6);
+ assertPred!"=="(sysTime, SysTime(Date(-1998, 1, 6)));
+ sysTime.add!"months"(-6);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 6));
+ sysTime.add!"months"(-27);
+ assertPred!"=="(sysTime, SysTime(Date(-2001, 4, 6)));
+ sysTime.add!"months"(28);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 8, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 5, 31));
+ sysTime.add!"months"(1);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 7, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 5, 31));
+ sysTime.add!"months"(-1);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 5, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 2, 28));
+ sysTime.add!"months"(-12);
+ assertPred!"=="(sysTime, SysTime(Date(-2000, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-2000, 2, 29));
+ sysTime.add!"months"(-12);
+ assertPred!"=="(sysTime, SysTime(Date(-2001, 3, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 31));
+ sysTime.add!"months"(1);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 8, 31)));
+ sysTime.add!"months"(1);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 10, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1998, 8, 31));
+ sysTime.add!"months"(13);
+ assertPred!"=="(sysTime, SysTime(Date(-1997, 10, 1)));
+ sysTime.add!"months"(-13);
+ assertPred!"=="(sysTime, SysTime(Date(-1998, 9, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1997, 12, 31));
+ sysTime.add!"months"(13);
+ assertPred!"=="(sysTime, SysTime(Date(-1995, 1, 31)));
+ sysTime.add!"months"(-13);
+ assertPred!"=="(sysTime, SysTime(Date(-1997, 12, 31)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1997, 12, 31));
+ sysTime.add!"months"(14);
+ assertPred!"=="(sysTime, SysTime(Date(-1995, 3, 3)));
+ sysTime.add!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(Date(-1996, 1, 3)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-2002, 12, 31));
+ sysTime.add!"months"(14);
+ assertPred!"=="(sysTime, SysTime(Date(-2000, 3, 2)));
+ sysTime.add!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(Date(-2001, 1, 2)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-2001, 12, 31));
+ sysTime.add!"months"(14);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 3, 3)));
+ sysTime.add!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(Date(-2000, 1, 3)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), FracSec.from!"usecs"(5007));
+ sysTime.add!"months"(3);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1999, 10, 6, 12, 2, 7), FracSec.from!"usecs"(5007)));
+ sysTime.add!"months"(-4);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1999, 6, 6, 12, 2, 7), FracSec.from!"usecs"(5007)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), FracSec.from!"hnsecs"(422202));
+ sysTime.add!"months"(14);
+ assertPred!"=="(sysTime, SysTime(DateTime(-2000, 3, 2, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ sysTime.add!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(DateTime(-2001, 1, 2, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), FracSec.from!"hnsecs"(422202));
+ sysTime.add!"months"(14);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1999, 3, 3, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ sysTime.add!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(DateTime(-2000, 1, 3, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ }
+
+ //Test Both
+ {
+ auto sysTime = SysTime(Date(1, 1, 1));
+ sysTime.add!"months"(-1);
+ assertPred!"=="(sysTime, SysTime(Date(0, 12, 1)));
+ sysTime.add!"months"(1);
+ assertPred!"=="(sysTime, SysTime(Date(1, 1, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(4, 1, 1));
+ sysTime.add!"months"(-48);
+ assertPred!"=="(sysTime, SysTime(Date(0, 1, 1)));
+ sysTime.add!"months"(48);
+ assertPred!"=="(sysTime, SysTime(Date(4, 1, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(4, 3, 31));
+ sysTime.add!"months"(-49);
+ assertPred!"=="(sysTime, SysTime(Date(0, 3, 2)));
+ sysTime.add!"months"(49);
+ assertPred!"=="(sysTime, SysTime(Date(4, 4, 2)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(4, 3, 31));
+ sysTime.add!"months"(-85);
+ assertPred!"=="(sysTime, SysTime(Date(-3, 3, 3)));
+ sysTime.add!"months"(85);
+ assertPred!"=="(sysTime, SysTime(Date(4, 4, 3)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0));
+ sysTime.add!"months"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ sysTime.add!"months"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.add!"months"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.add!"months"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0), FracSec.from!"hnsecs"(0));
+ sysTime.add!"months"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ sysTime.add!"months"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.add!"months"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.add!"months"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), FracSec.from!"hnsecs"(17));
+ sysTime.add!"months"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 1, 0, 7, 9), FracSec.from!"hnsecs"(17)));
+ sysTime.add!"months"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 7, 9), FracSec.from!"hnsecs"(17)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), FracSec.from!"msecs"(9));
+ sysTime.add!"months"(-85);
+ assertPred!"=="(sysTime, SysTime(DateTime(-3, 3, 3, 12, 11, 10), FracSec.from!"msecs"(9)));
+ sysTime.add!"months"(85);
+ assertPred!"=="(sysTime, SysTime(DateTime(4, 4, 3, 12, 11, 10), FracSec.from!"msecs"(9)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), FracSec.from!"msecs"(9));
+ sysTime.add!"months"(85);
+ assertPred!"=="(sysTime, SysTime(DateTime(4, 5, 1, 12, 11, 10), FracSec.from!"msecs"(9)));
+ sysTime.add!"months"(-85);
+ assertPred!"=="(sysTime, SysTime(DateTime(-3, 4, 1, 12, 11, 10), FracSec.from!"msecs"(9)));
+ }
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst.add!"months"(4)));
+ //static assert(!__traits(compiles, ist.add!"months"(4)));
+
+ //Verify Examples.
+ auto st1 = SysTime(DateTime(2010, 1, 1, 12, 30 ,33));
+ st1.add!"months"(1);
+ assert(st1 == SysTime(DateTime(2010, 2, 1, 12, 30 ,33)));
+
+ auto st2 = SysTime(DateTime(2010, 1, 1, 12, 30 ,33));
+ st2.add!"months"(-1);
+ assert(st2 == SysTime(DateTime(2009, 12, 1, 12, 30 ,33)));
+
+ auto st3 = SysTime(DateTime(1999, 1, 29, 12, 30 ,33));
+ st3.add!"months"(1);
+ assert(st3 == SysTime(DateTime(1999, 3, 1, 12, 30 ,33)));
+
+ auto st4 = SysTime(DateTime(1999, 1, 29, 12, 30 ,33));
+ st4.add!"months"(1, AllowDayOverflow.no);
+ assert(st4 == SysTime(DateTime(1999, 2, 28, 12, 30 ,33)));
+ }
+
+ //Test add!"months"() with AllowDayOverlow.no
+ unittest
+ {
+ //Test A.D.
+ {
+ auto sysTime = SysTime(Date(1999, 7, 6));
+ sysTime.add!"months"(3, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 10, 6)));
+ sysTime.add!"months"(-4, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 6, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 7, 6));
+ sysTime.add!"months"(6, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(2000, 1, 6)));
+ sysTime.add!"months"(-6, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 7, 6));
+ sysTime.add!"months"(27, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(2001, 10, 6)));
+ sysTime.add!"months"(-28, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 6, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 5, 31));
+ sysTime.add!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 6, 30)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 5, 31));
+ sysTime.add!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 4, 30)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 2, 28));
+ sysTime.add!"months"(12, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(2000, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(2000, 2, 29));
+ sysTime.add!"months"(12, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(2001, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 7, 31));
+ sysTime.add!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 8, 31)));
+ sysTime.add!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 9, 30)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1998, 8, 31));
+ sysTime.add!"months"(13, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 9, 30)));
+ sysTime.add!"months"(-13, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1998, 8, 30)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1997, 12, 31));
+ sysTime.add!"months"(13, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 1, 31)));
+ sysTime.add!"months"(-13, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1997, 12, 31)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1997, 12, 31));
+ sysTime.add!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 2, 28)));
+ sysTime.add!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1997, 12, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1998, 12, 31));
+ sysTime.add!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(2000, 2, 29)));
+ sysTime.add!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1998, 12, 29)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 12, 31));
+ sysTime.add!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(2001, 2, 28)));
+ sysTime.add!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 12, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), FracSec.from!"usecs"(5007));
+ sysTime.add!"months"(3, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 10, 6, 12, 2, 7), FracSec.from!"usecs"(5007)));
+ sysTime.add!"months"(-4, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 6, 6, 12, 2, 7), FracSec.from!"usecs"(5007)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), FracSec.from!"hnsecs"(422202));
+ sysTime.add!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(2000, 2, 29, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ sysTime.add!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1998, 12, 29, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), FracSec.from!"hnsecs"(422202));
+ sysTime.add!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(2001, 2, 28, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ sysTime.add!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 12, 28, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ }
+
+ //Test B.C.
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 6));
+ sysTime.add!"months"(3, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 10, 6)));
+ sysTime.add!"months"(-4, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 6, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 6));
+ sysTime.add!"months"(6, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1998, 1, 6)));
+ sysTime.add!"months"(-6, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 6));
+ sysTime.add!"months"(-27, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-2001, 4, 6)));
+ sysTime.add!"months"(28, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 8, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 5, 31));
+ sysTime.add!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 6, 30)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 5, 31));
+ sysTime.add!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 4, 30)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 2, 28));
+ sysTime.add!"months"(-12, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-2000, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-2000, 2, 29));
+ sysTime.add!"months"(-12, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-2001, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 31));
+ sysTime.add!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 8, 31)));
+ sysTime.add!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 9, 30)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1998, 8, 31));
+ sysTime.add!"months"(13, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1997, 9, 30)));
+ sysTime.add!"months"(-13, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1998, 8, 30)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1997, 12, 31));
+ sysTime.add!"months"(13, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1995, 1, 31)));
+ sysTime.add!"months"(-13, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1997, 12, 31)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1997, 12, 31));
+ sysTime.add!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1995, 2, 28)));
+ sysTime.add!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1997, 12, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-2002, 12, 31));
+ sysTime.add!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-2000, 2, 29)));
+ sysTime.add!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-2002, 12, 29)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-2001, 12, 31));
+ sysTime.add!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 2, 28)));
+ sysTime.add!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-2001, 12, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), FracSec.from!"usecs"(5007));
+ sysTime.add!"months"(3, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1999, 10, 6, 12, 2, 7), FracSec.from!"usecs"(5007)));
+ sysTime.add!"months"(-4, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1999, 6, 6, 12, 2, 7), FracSec.from!"usecs"(5007)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), FracSec.from!"hnsecs"(422202));
+ sysTime.add!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-2000, 2, 29, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ sysTime.add!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-2002, 12, 29, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), FracSec.from!"hnsecs"(422202));
+ sysTime.add!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1999, 2, 28, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ sysTime.add!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-2001, 12, 28, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ }
+
+ //Test Both
+ {
+ auto sysTime = SysTime(Date(1, 1, 1));
+ sysTime.add!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(0, 12, 1)));
+ sysTime.add!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1, 1, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(4, 1, 1));
+ sysTime.add!"months"(-48, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(0, 1, 1)));
+ sysTime.add!"months"(48, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(4, 1, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(4, 3, 31));
+ sysTime.add!"months"(-49, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(0, 2, 29)));
+ sysTime.add!"months"(49, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(4, 3, 29)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(4, 3, 31));
+ sysTime.add!"months"(-85, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-3, 2, 28)));
+ sysTime.add!"months"(85, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(4, 3, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0));
+ sysTime.add!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ sysTime.add!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.add!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.add!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0), FracSec.from!"hnsecs"(0));
+ sysTime.add!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ sysTime.add!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.add!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.add!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), FracSec.from!"hnsecs"(17));
+ sysTime.add!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 1, 0, 7, 9), FracSec.from!"hnsecs"(17)));
+ sysTime.add!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 7, 9), FracSec.from!"hnsecs"(17)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), FracSec.from!"msecs"(9));
+ sysTime.add!"months"(-85, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-3, 2, 28, 12, 11, 10), FracSec.from!"msecs"(9)));
+ sysTime.add!"months"(85, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(4, 3, 28, 12, 11, 10), FracSec.from!"msecs"(9)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), FracSec.from!"msecs"(9));
+ sysTime.add!"months"(85, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(4, 4, 30, 12, 11, 10), FracSec.from!"msecs"(9)));
+ sysTime.add!"months"(-85, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-3, 3, 30, 12, 11, 10), FracSec.from!"msecs"(9)));
+ }
+ }
+
+
+ /++
+ Adds the given number of years to this SysTime. A negative number will
+ subtract.
+
+ For years, because they are the largest unit in SysTime, there is no
+ difference between adding or rolling.
+
+ Params:
+ years = The number of years to add to this SysTime.
+ allowOverflow = Whether the days should be allowed to overflow,
+ causing the month to increment.
+ +/
+ /+ref SysTime+/ void roll(string units)(long years, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) nothrow
+ if(units == "years")
+ {
+ add!"years"(years, allowOverflow);
+ }
+
+ unittest
+ {
+ auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, st.roll!"years"(4)));
+ static assert(!__traits(compiles, cst.roll!"years"(4)));
+ //static assert(!__traits(compiles, ist.roll!"years"(4)));
+ }
+
+
+ /++
+ Adds the given number of months to this SysTime. A negative number will
+ subtract.
+
+ The difference between rolling and adding is that rolling does not affect
+ larger units. So, if you roll the SysTime 12 months, you get the exact
+ same SysTime. However, the days can still be affected due to the differing
+ number of days in each month.
+
+ Params:
+ months = The number of months to add to this SysTime.
+ allowOverflow = Whether the days should be allowed to overflow,
+ causing the month to increment.
+
+ Examples:
+--------------------
+auto st1 = SysTime(DateTime(2010, 1, 1, 12, 33, 33));
+st1.roll!"months"(1);
+assert(st1 == SysTime(DateTime(2010, 2, 1, 12, 33, 33)));
+
+auto st2 = SysTime(DateTime(2010, 1, 1, 12, 33, 33));
+st2.roll!"months"(-1);
+assert(st2 == SysTime(DateTime(2010, 12, 1, 12, 33, 33)));
+
+auto st3 = SysTime(DateTime(1999, 1, 29, 12, 33, 33));
+st3.roll!"months"(1);
+assert(st3 == SysTime(DateTime(1999, 3, 1, 12, 33, 33)));
+
+auto st4 = SysTime(DateTime(1999, 1, 29, 12, 33, 33));
+st4.roll!"months"(1, AllowDayOverflow.no);
+assert(st4 == SysTime(DateTime(1999, 2, 28, 12, 33, 33)));
+--------------------
+ +/
+ /+ref SysTime+/ void roll(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) nothrow
+ if(units == "months")
+ {
+ auto hnsecs = adjTime;
+ auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
+
+ if(hnsecs < 0)
+ {
+ hnsecs += convert!("hours", "hnsecs")(24);
+ --days;
+ }
+
+ auto date = Date(cast(int)days);
+ date.roll!"months"(months, allowOverflow);
+ days = date.dayOfGregorianCal - 1;
+
+ if(days < 0)
+ {
+ hnsecs -= convert!("hours", "hnsecs")(24);
+ ++days;
+ }
+
+ immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
+
+ adjTime = newDaysHNSecs + hnsecs;
+ }
+
+ //Test roll!"months"() with AllowDayOverlow.yes
+ unittest
+ {
+ //Test A.D.
+ {
+ auto sysTime = SysTime(Date(1999, 7, 6));
+ sysTime.roll!"months"(3);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 10, 6)));
+ sysTime.roll!"months"(-4);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 6, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 7, 6));
+ sysTime.roll!"months"(6);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 1, 6)));
+ sysTime.roll!"months"(-6);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 7, 6));
+ sysTime.roll!"months"(27);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 10, 6)));
+ sysTime.roll!"months"(-28);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 6, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 5, 31));
+ sysTime.roll!"months"(1);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 7, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 5, 31));
+ sysTime.roll!"months"(-1);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 5, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 2, 28));
+ sysTime.roll!"months"(12);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(2000, 2, 29));
+ sysTime.roll!"months"(12);
+ assertPred!"=="(sysTime, SysTime(Date(2000, 2, 29)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 7, 31));
+ sysTime.roll!"months"(1);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 8, 31)));
+ sysTime.roll!"months"(1);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 10, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1998, 8, 31));
+ sysTime.roll!"months"(13);
+ assertPred!"=="(sysTime, SysTime(Date(1998, 10, 1)));
+ sysTime.roll!"months"(-13);
+ assertPred!"=="(sysTime, SysTime(Date(1998, 9, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1997, 12, 31));
+ sysTime.roll!"months"(13);
+ assertPred!"=="(sysTime, SysTime(Date(1997, 1, 31)));
+ sysTime.roll!"months"(-13);
+ assertPred!"=="(sysTime, SysTime(Date(1997, 12, 31)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1997, 12, 31));
+ sysTime.roll!"months"(14);
+ assertPred!"=="(sysTime, SysTime(Date(1997, 3, 3)));
+ sysTime.roll!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(Date(1997, 1, 3)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1998, 12, 31));
+ sysTime.roll!"months"(14);
+ assertPred!"=="(sysTime, SysTime(Date(1998, 3, 3)));
+ sysTime.roll!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(Date(1998, 1, 3)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 12, 31));
+ sysTime.roll!"months"(14);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 3, 3)));
+ sysTime.roll!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 1, 3)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), FracSec.from!"usecs"(5007));
+ sysTime.roll!"months"(3);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 10, 6, 12, 2, 7), FracSec.from!"usecs"(5007)));
+ sysTime.roll!"months"(-4);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 6, 6, 12, 2, 7), FracSec.from!"usecs"(5007)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), FracSec.from!"hnsecs"(422202));
+ sysTime.roll!"months"(14);
+ assertPred!"=="(sysTime, SysTime(DateTime(1998, 3, 3, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ sysTime.roll!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(DateTime(1998, 1, 3, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), FracSec.from!"hnsecs"(422202));
+ sysTime.roll!"months"(14);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 3, 3, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ sysTime.roll!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 1, 3, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ }
+
+ //Test B.C.
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 6));
+ sysTime.roll!"months"(3);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 10, 6)));
+ sysTime.roll!"months"(-4);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 6, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 6));
+ sysTime.roll!"months"(6);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 1, 6)));
+ sysTime.roll!"months"(-6);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 6));
+ sysTime.roll!"months"(-27);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 4, 6)));
+ sysTime.roll!"months"(28);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 8, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 5, 31));
+ sysTime.roll!"months"(1);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 7, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 5, 31));
+ sysTime.roll!"months"(-1);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 5, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 2, 28));
+ sysTime.roll!"months"(-12);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-2000, 2, 29));
+ sysTime.roll!"months"(-12);
+ assertPred!"=="(sysTime, SysTime(Date(-2000, 2, 29)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 31));
+ sysTime.roll!"months"(1);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 8, 31)));
+ sysTime.roll!"months"(1);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 10, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1998, 8, 31));
+ sysTime.roll!"months"(13);
+ assertPred!"=="(sysTime, SysTime(Date(-1998, 10, 1)));
+ sysTime.roll!"months"(-13);
+ assertPred!"=="(sysTime, SysTime(Date(-1998, 9, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1997, 12, 31));
+ sysTime.roll!"months"(13);
+ assertPred!"=="(sysTime, SysTime(Date(-1997, 1, 31)));
+ sysTime.roll!"months"(-13);
+ assertPred!"=="(sysTime, SysTime(Date(-1997, 12, 31)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1997, 12, 31));
+ sysTime.roll!"months"(14);
+ assertPred!"=="(sysTime, SysTime(Date(-1997, 3, 3)));
+ sysTime.roll!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(Date(-1997, 1, 3)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-2002, 12, 31));
+ sysTime.roll!"months"(14);
+ assertPred!"=="(sysTime, SysTime(Date(-2002, 3, 3)));
+ sysTime.roll!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(Date(-2002, 1, 3)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-2001, 12, 31));
+ sysTime.roll!"months"(14);
+ assertPred!"=="(sysTime, SysTime(Date(-2001, 3, 3)));
+ sysTime.roll!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(Date(-2001, 1, 3)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0));
+ sysTime.roll!"months"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 12, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ sysTime.roll!"months"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.roll!"months"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 12, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.roll!"months"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0), FracSec.from!"hnsecs"(0));
+ sysTime.roll!"months"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ sysTime.roll!"months"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.roll!"months"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.roll!"months"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), FracSec.from!"hnsecs"(5007));
+ sysTime.roll!"months"(3);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1999, 10, 6, 12, 2, 7), FracSec.from!"hnsecs"(5007)));
+ sysTime.roll!"months"(-4);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1999, 6, 6, 12, 2, 7), FracSec.from!"hnsecs"(5007)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), FracSec.from!"hnsecs"(422202));
+ sysTime.roll!"months"(14);
+ assertPred!"=="(sysTime, SysTime(DateTime(-2002, 3, 3, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ sysTime.roll!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(DateTime(-2002, 1, 3, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), FracSec.from!"hnsecs"(422202));
+ sysTime.roll!"months"(14);
+ assertPred!"=="(sysTime, SysTime(DateTime(-2001, 3, 3, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ sysTime.roll!"months"(-14);
+ assertPred!"=="(sysTime, SysTime(DateTime(-2001, 1, 3, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ }
+
+ //Test Both
+ {
+ auto sysTime = SysTime(Date(1, 1, 1));
+ sysTime.roll!"months"(-1);
+ assertPred!"=="(sysTime, SysTime(Date(1, 12, 1)));
+ sysTime.roll!"months"(1);
+ assertPred!"=="(sysTime, SysTime(Date(1, 1, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(4, 1, 1));
+ sysTime.roll!"months"(-48);
+ assertPred!"=="(sysTime, SysTime(Date(4, 1, 1)));
+ sysTime.roll!"months"(48);
+ assertPred!"=="(sysTime, SysTime(Date(4, 1, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(4, 3, 31));
+ sysTime.roll!"months"(-49);
+ assertPred!"=="(sysTime, SysTime(Date(4, 3, 2)));
+ sysTime.roll!"months"(49);
+ assertPred!"=="(sysTime, SysTime(Date(4, 4, 2)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(4, 3, 31));
+ sysTime.roll!"months"(-85);
+ assertPred!"=="(sysTime, SysTime(Date(4, 3, 2)));
+ sysTime.roll!"months"(85);
+ assertPred!"=="(sysTime, SysTime(Date(4, 4, 2)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1, 1, 1));
+ sysTime.roll!"months"(-1);
+ assertPred!"=="(sysTime, SysTime(Date(-1, 12, 1)));
+ sysTime.roll!"months"(1);
+ assertPred!"=="(sysTime, SysTime(Date(-1, 1, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-4, 1, 1));
+ sysTime.roll!"months"(-48);
+ assertPred!"=="(sysTime, SysTime(Date(-4, 1, 1)));
+ sysTime.roll!"months"(48);
+ assertPred!"=="(sysTime, SysTime(Date(-4, 1, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-4, 3, 31));
+ sysTime.roll!"months"(-49);
+ assertPred!"=="(sysTime, SysTime(Date(-4, 3, 2)));
+ sysTime.roll!"months"(49);
+ assertPred!"=="(sysTime, SysTime(Date(-4, 4, 2)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-4, 3, 31));
+ sysTime.roll!"months"(-85);
+ assertPred!"=="(sysTime, SysTime(Date(-4, 3, 2)));
+ sysTime.roll!"months"(85);
+ assertPred!"=="(sysTime, SysTime(Date(-4, 4, 2)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), FracSec.from!"hnsecs"(17));
+ sysTime.roll!"months"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 12, 1, 0, 7, 9), FracSec.from!"hnsecs"(17)));
+ sysTime.roll!"months"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 7, 9), FracSec.from!"hnsecs"(17)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), FracSec.from!"msecs"(9));
+ sysTime.roll!"months"(-85);
+ assertPred!"=="(sysTime, SysTime(DateTime(4, 3, 2, 12, 11, 10), FracSec.from!"msecs"(9)));
+ sysTime.roll!"months"(85);
+ assertPred!"=="(sysTime, SysTime(DateTime(4, 4, 2, 12, 11, 10), FracSec.from!"msecs"(9)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), FracSec.from!"msecs"(9));
+ sysTime.roll!"months"(85);
+ assertPred!"=="(sysTime, SysTime(DateTime(-3, 5, 1, 12, 11, 10), FracSec.from!"msecs"(9)));
+ sysTime.roll!"months"(-85);
+ assertPred!"=="(sysTime, SysTime(DateTime(-3, 4, 1, 12, 11, 10), FracSec.from!"msecs"(9)));
+ }
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst.roll!"months"(4)));
+ //static assert(!__traits(compiles, ist.roll!"months"(4)));
+
+ //Verify Examples.
+ auto st1 = SysTime(DateTime(2010, 1, 1, 12, 33, 33));
+ st1.roll!"months"(1);
+ assert(st1 == SysTime(DateTime(2010, 2, 1, 12, 33, 33)));
+
+ auto st2 = SysTime(DateTime(2010, 1, 1, 12, 33, 33));
+ st2.roll!"months"(-1);
+ assert(st2 == SysTime(DateTime(2010, 12, 1, 12, 33, 33)));
+
+ auto st3 = SysTime(DateTime(1999, 1, 29, 12, 33, 33));
+ st3.roll!"months"(1);
+ assert(st3 == SysTime(DateTime(1999, 3, 1, 12, 33, 33)));
+
+ auto st4 = SysTime(DateTime(1999, 1, 29, 12, 33, 33));
+ st4.roll!"months"(1, AllowDayOverflow.no);
+ assert(st4 == SysTime(DateTime(1999, 2, 28, 12, 33, 33)));
+ }
+
+ //Test roll!"months"() with AllowDayOverlow.no
+ unittest
+ {
+ //Test A.D.
+ {
+ auto sysTime = SysTime(Date(1999, 7, 6));
+ sysTime.roll!"months"(3, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 10, 6)));
+ sysTime.roll!"months"(-4, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 6, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 7, 6));
+ sysTime.roll!"months"(6, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 1, 6)));
+ sysTime.roll!"months"(-6, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 7, 6));
+ sysTime.roll!"months"(27, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 10, 6)));
+ sysTime.roll!"months"(-28, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 6, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 5, 31));
+ sysTime.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 6, 30)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 5, 31));
+ sysTime.roll!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 4, 30)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 2, 28));
+ sysTime.roll!"months"(12, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(2000, 2, 29));
+ sysTime.roll!"months"(12, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(2000, 2, 29)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 7, 31));
+ sysTime.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 8, 31)));
+ sysTime.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 9, 30)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1998, 8, 31));
+ sysTime.roll!"months"(13, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1998, 9, 30)));
+ sysTime.roll!"months"(-13, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1998, 8, 30)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1997, 12, 31));
+ sysTime.roll!"months"(13, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1997, 1, 31)));
+ sysTime.roll!"months"(-13, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1997, 12, 31)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1997, 12, 31));
+ sysTime.roll!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1997, 2, 28)));
+ sysTime.roll!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1997, 12, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1998, 12, 31));
+ sysTime.roll!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1998, 2, 28)));
+ sysTime.roll!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1998, 12, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 12, 31));
+ sysTime.roll!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 2, 28)));
+ sysTime.roll!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 12, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), FracSec.from!"usecs"(5007));
+ sysTime.roll!"months"(3, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 10, 6, 12, 2, 7), FracSec.from!"usecs"(5007)));
+ sysTime.roll!"months"(-4, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 6, 6, 12, 2, 7), FracSec.from!"usecs"(5007)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), FracSec.from!"hnsecs"(422202));
+ sysTime.roll!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1998, 2, 28, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ sysTime.roll!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1998, 12, 28, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), FracSec.from!"hnsecs"(422202));
+ sysTime.roll!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 2, 28, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ sysTime.roll!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 12, 28, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ }
+
+ //Test B.C.
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 6));
+ sysTime.roll!"months"(3, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 10, 6)));
+ sysTime.roll!"months"(-4, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 6, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 6));
+ sysTime.roll!"months"(6, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 1, 6)));
+ sysTime.roll!"months"(-6, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 6));
+ sysTime.roll!"months"(-27, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 4, 6)));
+ sysTime.roll!"months"(28, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 8, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 5, 31));
+ sysTime.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 6, 30)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 5, 31));
+ sysTime.roll!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 4, 30)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 2, 28));
+ sysTime.roll!"months"(-12, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-2000, 2, 29));
+ sysTime.roll!"months"(-12, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-2000, 2, 29)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 31));
+ sysTime.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 8, 31)));
+ sysTime.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 9, 30)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1998, 8, 31));
+ sysTime.roll!"months"(13, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1998, 9, 30)));
+ sysTime.roll!"months"(-13, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1998, 8, 30)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1997, 12, 31));
+ sysTime.roll!"months"(13, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1997, 1, 31)));
+ sysTime.roll!"months"(-13, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1997, 12, 31)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1997, 12, 31));
+ sysTime.roll!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1997, 2, 28)));
+ sysTime.roll!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1997, 12, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-2002, 12, 31));
+ sysTime.roll!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-2002, 2, 28)));
+ sysTime.roll!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-2002, 12, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-2001, 12, 31));
+ sysTime.roll!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-2001, 2, 28)));
+ sysTime.roll!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-2001, 12, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), FracSec.from!"usecs"(5007));
+ sysTime.roll!"months"(3, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1999, 10, 6, 12, 2, 7), FracSec.from!"usecs"(5007)));
+ sysTime.roll!"months"(-4, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1999, 6, 6, 12, 2, 7), FracSec.from!"usecs"(5007)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), FracSec.from!"hnsecs"(422202));
+ sysTime.roll!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-2002, 2, 28, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ sysTime.roll!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-2002, 12, 28, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), FracSec.from!"hnsecs"(422202));
+ sysTime.roll!"months"(14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-2001, 2, 28, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ sysTime.roll!"months"(-14, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-2001, 12, 28, 7, 7, 7), FracSec.from!"hnsecs"(422202)));
+ }
+
+ //Test Both
+ {
+ auto sysTime = SysTime(Date(1, 1, 1));
+ sysTime.roll!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1, 12, 1)));
+ sysTime.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(1, 1, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(4, 1, 1));
+ sysTime.roll!"months"(-48, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(4, 1, 1)));
+ sysTime.roll!"months"(48, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(4, 1, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(4, 3, 31));
+ sysTime.roll!"months"(-49, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(4, 2, 29)));
+ sysTime.roll!"months"(49, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(4, 3, 29)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(4, 3, 31));
+ sysTime.roll!"months"(-85, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(4, 2, 29)));
+ sysTime.roll!"months"(85, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(4, 3, 29)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1, 1, 1));
+ sysTime.roll!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1, 12, 1)));
+ sysTime.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-1, 1, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-4, 1, 1));
+ sysTime.roll!"months"(-48, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-4, 1, 1)));
+ sysTime.roll!"months"(48, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-4, 1, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-4, 3, 31));
+ sysTime.roll!"months"(-49, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-4, 2, 29)));
+ sysTime.roll!"months"(49, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-4, 3, 29)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-4, 3, 31));
+ sysTime.roll!"months"(-85, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-4, 2, 29)));
+ sysTime.roll!"months"(85, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(Date(-4, 3, 29)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0));
+ sysTime.roll!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 12, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ sysTime.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.roll!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 12, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0), FracSec.from!"hnsecs"(0));
+ sysTime.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ sysTime.roll!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.roll!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), FracSec.from!"hnsecs"(17));
+ sysTime.roll!"months"(-1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 12, 1, 0, 7, 9), FracSec.from!"hnsecs"(17)));
+ sysTime.roll!"months"(1, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 7, 9), FracSec.from!"hnsecs"(17)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), FracSec.from!"msecs"(9));
+ sysTime.roll!"months"(-85, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(4, 2, 29, 12, 11, 10), FracSec.from!"msecs"(9)));
+ sysTime.roll!"months"(85, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(4, 3, 29, 12, 11, 10), FracSec.from!"msecs"(9)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), FracSec.from!"msecs"(9));
+ sysTime.roll!"months"(85, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-3, 4, 30, 12, 11, 10), FracSec.from!"msecs"(9)));
+ sysTime.roll!"months"(-85, AllowDayOverflow.no);
+ assertPred!"=="(sysTime, SysTime(DateTime(-3, 3, 30, 12, 11, 10), FracSec.from!"msecs"(9)));
+ }
+ }
+
+
+ /++
+ Adds the given number of days to this SysTime. A negative number will
+ subtract.
+
+ The difference between rolling and adding is that rolling does not affect
+ larger units. So, if you roll the SysTime one year's worth of days, then
+ you get the exact same SysTime.
+
+ Note that TimeOfDay has no $(D add!"days"()) function because you can add
+ days to a SysTime by adding a duration to it.
+
+ Params:
+ days = The number of days to add to this SysTime.
+
+ Examples:
+--------------------
+auto st = SysTime(DateTime(2010, 1, 1, 11, 23, 12));
+st.roll!"days"(1);
+assert(st == SysTime(DateTime(2010, 1, 2, 11, 23, 12)));
+st.roll!"days"(365);
+assert(st == SysTime(DateTime(2010, 1, 26, 11, 23, 12)));
+st.roll!"days"(-32);
+assert(st == SysTime(DateTime(2010, 1, 25, 11, 23, 12)));
+--------------------
+ +/
+ /+ref SysTime+/ void roll(string units)(long days) nothrow
+ if(units == "days")
+ {
+ auto hnsecs = adjTime;
+ auto gdays = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
+
+ if(hnsecs < 0)
+ {
+ hnsecs += convert!("hours", "hnsecs")(24);
+ --gdays;
+ }
+
+ auto date = Date(cast(int)gdays);
+ date.roll!"days"(days);
+ gdays = date.dayOfGregorianCal - 1;
+
+ if(gdays < 0)
+ {
+ hnsecs -= convert!("hours", "hnsecs")(24);
+ ++gdays;
+ }
+
+ immutable newDaysHNSecs = convert!("days", "hnsecs")(gdays);
+
+ adjTime = newDaysHNSecs + hnsecs;
+ }
+
+ unittest
+ {
+ //Test A.D.
+ {
+ auto sysTime = SysTime(Date(1999, 2, 28));
+ sysTime.roll!"days"(1);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 2, 1)));
+ sysTime.roll!"days"(-1);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(2000, 2, 28));
+ sysTime.roll!"days"(1);
+ assertPred!"=="(sysTime, SysTime(Date(2000, 2, 29)));
+ sysTime.roll!"days"(1);
+ assertPred!"=="(sysTime, SysTime(Date(2000, 2, 1)));
+ sysTime.roll!"days"(-1);
+ assertPred!"=="(sysTime, SysTime(Date(2000, 2, 29)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 6, 30));
+ sysTime.roll!"days"(1);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 6, 1)));
+ sysTime.roll!"days"(-1);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 6, 30)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 7, 31));
+ sysTime.roll!"days"(1);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 7, 1)));
+ sysTime.roll!"days"(-1);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 7, 31)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 1, 1));
+ sysTime.roll!"days"(-1);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 1, 31)));
+ sysTime.roll!"days"(1);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 1, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 7, 6));
+ sysTime.roll!"days"(9);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 7, 15)));
+ sysTime.roll!"days"(-11);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 7, 4)));
+ sysTime.roll!"days"(30);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 7, 3)));
+ sysTime.roll!"days"(-3);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 7, 31)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 7, 6));
+ sysTime.roll!"days"(365);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 7, 30)));
+ sysTime.roll!"days"(-365);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 7, 6)));
+ sysTime.roll!"days"(366);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 7, 31)));
+ sysTime.roll!"days"(730);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 7, 17)));
+ sysTime.roll!"days"(-1096);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(1999, 2, 6));
+ sysTime.roll!"days"(365);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 2, 7)));
+ sysTime.roll!"days"(-365);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 2, 6)));
+ sysTime.roll!"days"(366);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 2, 8)));
+ sysTime.roll!"days"(730);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 2, 10)));
+ sysTime.roll!"days"(-1096);
+ assertPred!"=="(sysTime, SysTime(Date(1999, 2, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1999, 2, 28, 7, 9, 2), FracSec.from!"usecs"(234578));
+ sysTime.roll!"days"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 2, 1, 7, 9, 2), FracSec.from!"usecs"(234578)));
+ sysTime.roll!"days"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 2, 28, 7, 9, 2), FracSec.from!"usecs"(234578)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1999, 7, 6, 7, 9, 2), FracSec.from!"usecs"(234578));
+ sysTime.roll!"days"(9);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 7, 15, 7, 9, 2), FracSec.from!"usecs"(234578)));
+ sysTime.roll!"days"(-11);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 7, 4, 7, 9, 2), FracSec.from!"usecs"(234578)));
+ sysTime.roll!"days"(30);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 7, 3, 7, 9, 2), FracSec.from!"usecs"(234578)));
+ sysTime.roll!"days"(-3);
+ assertPred!"=="(sysTime, SysTime(DateTime(1999, 7, 31, 7, 9, 2), FracSec.from!"usecs"(234578)));
+ }
+
+ //Test B.C.
+ {
+ auto sysTime = SysTime(Date(-1999, 2, 28));
+ sysTime.roll!"days"(1);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 2, 1)));
+ sysTime.roll!"days"(-1);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 2, 28)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-2000, 2, 28));
+ sysTime.roll!"days"(1);
+ assertPred!"=="(sysTime, SysTime(Date(-2000, 2, 29)));
+ sysTime.roll!"days"(1);
+ assertPred!"=="(sysTime, SysTime(Date(-2000, 2, 1)));
+ sysTime.roll!"days"(-1);
+ assertPred!"=="(sysTime, SysTime(Date(-2000, 2, 29)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 6, 30));
+ sysTime.roll!"days"(1);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 6, 1)));
+ sysTime.roll!"days"(-1);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 6, 30)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 31));
+ sysTime.roll!"days"(1);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 7, 1)));
+ sysTime.roll!"days"(-1);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 7, 31)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 1, 1));
+ sysTime.roll!"days"(-1);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 1, 31)));
+ sysTime.roll!"days"(1);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 1, 1)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 6));
+ sysTime.roll!"days"(9);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 7, 15)));
+ sysTime.roll!"days"(-11);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 7, 4)));
+ sysTime.roll!"days"(30);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 7, 3)));
+ sysTime.roll!"days"(-3);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 7, 31)));
+ }
+
+ {
+ auto sysTime = SysTime(Date(-1999, 7, 6));
+ sysTime.roll!"days"(365);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 7, 30)));
+ sysTime.roll!"days"(-365);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 7, 6)));
+ sysTime.roll!"days"(366);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 7, 31)));
+ sysTime.roll!"days"(730);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 7, 17)));
+ sysTime.roll!"days"(-1096);
+ assertPred!"=="(sysTime, SysTime(Date(-1999, 7, 6)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-1999, 2, 28, 7, 9, 2), FracSec.from!"usecs"(234578));
+ sysTime.roll!"days"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1999, 2, 1, 7, 9, 2), FracSec.from!"usecs"(234578)));
+ sysTime.roll!"days"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1999, 2, 28, 7, 9, 2), FracSec.from!"usecs"(234578)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(-1999, 7, 6, 7, 9, 2), FracSec.from!"usecs"(234578));
+ sysTime.roll!"days"(9);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1999, 7, 15, 7, 9, 2), FracSec.from!"usecs"(234578)));
+ sysTime.roll!"days"(-11);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1999, 7, 4, 7, 9, 2), FracSec.from!"usecs"(234578)));
+ sysTime.roll!"days"(30);
+ assertPred!"=="(sysTime, SysTime(DateTime(-1999, 7, 3, 7, 9, 2), FracSec.from!"usecs"(234578)));
+ sysTime.roll!"days"(-3);
+ }
+
+ //Test Both
+ {
+ auto sysTime = SysTime(Date(1, 7, 6));
+ sysTime.roll!"days"(-365);
+ assertPred!"=="(sysTime, SysTime(Date(1, 7, 13)));
+ sysTime.roll!"days"(365);
+ assertPred!"=="(sysTime, SysTime(Date(1, 7, 6)));
+ sysTime.roll!"days"(-731);
+ assertPred!"=="(sysTime, SysTime(Date(1, 7, 19)));
+ sysTime.roll!"days"(730);
+ assertPred!"=="(sysTime, SysTime(Date(1, 7, 5)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0));
+ sysTime.roll!"days"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 31, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ sysTime.roll!"days"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.roll!"days"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.roll!"days"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 12, 31, 0, 0, 0), FracSec.from!"hnsecs"(0));
+ sysTime.roll!"days"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ sysTime.roll!"days"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 31, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.roll!"days"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.roll!"days"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 7, 6, 13, 13, 9), FracSec.from!"msecs"(22));
+ sysTime.roll!"days"(-365);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 7, 13, 13, 13, 9), FracSec.from!"msecs"(22)));
+ sysTime.roll!"days"(365);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 7, 6, 13, 13, 9), FracSec.from!"msecs"(22)));
+ sysTime.roll!"days"(-731);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 7, 19, 13, 13, 9), FracSec.from!"msecs"(22)));
+ sysTime.roll!"days"(730);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 7, 5, 13, 13, 9), FracSec.from!"msecs"(22)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 7, 6, 13, 13, 9), FracSec.from!"msecs"(22));
+ sysTime.roll!"days"(-365);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 7, 13, 13, 13, 9), FracSec.from!"msecs"(22)));
+ sysTime.roll!"days"(365);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 7, 6, 13, 13, 9), FracSec.from!"msecs"(22)));
+ sysTime.roll!"days"(-731);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 7, 19, 13, 13, 9), FracSec.from!"msecs"(22)));
+ sysTime.roll!"days"(730);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 7, 5, 13, 13, 9), FracSec.from!"msecs"(22)));
+ }
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst.roll!"days"(4)));
+ //static assert(!__traits(compiles, ist.roll!"days"(4)));
+
+ //Verify Examples.
+ auto st = SysTime(DateTime(2010, 1, 1, 11, 23, 12));
+ st.roll!"days"(1);
+ assert(st == SysTime(DateTime(2010, 1, 2, 11, 23, 12)));
+ st.roll!"days"(365);
+ assert(st == SysTime(DateTime(2010, 1, 26, 11, 23, 12)));
+ st.roll!"days"(-32);
+ assert(st == SysTime(DateTime(2010, 1, 25, 11, 23, 12)));
+ }
+
+
+
+ /++
+ Add hours to the time of day. Negative values will subtract.
+
+ The difference between rolling and adding is that rolling does not
+ affect larger units. So, if you roll the SysTime 24 hours, you get
+ the exact same SysTime.
+
+ Note that SysTime has no $(D add!"hours"()), $(D add!"minutes"()), or
+ $(D add!"seconds"()) function because you can add those units to
+ a SysTime by adding a duration to it.
+
+ Params:
+ hours = The number of hours to add to this SysTime.
+
+ Examples:
+--------------------
+auto st1 = SysTime(DateTime(2010, 7, 4, 12, 0, 0));
+st1.roll!"hours"(1);
+assert(st1 == SysTime(DateTime(2010, 7, 4, 13, 0, 0)));
+
+auto st2 = SysTime(DateTime(2010, 2, 12, 12, 0, 0));
+st2.roll!"hours"(-1);
+assert(st2 == SysTime(DateTime(2010, 2, 12, 11, 0, 0)));
+
+auto st3 = SysTime(DateTime(2009, 12, 31, 0, 0, 0));
+st3.roll!"minutes"(1);
+assert(st3 == SysTime(DateTime(2009, 12, 31, 0, 1, 0)));
+
+auto st4 = SysTime(DateTime(2010, 1, 1, 0, 0, 0));
+st4.roll!"minutes"(-1);
+assert(st4 == SysTime(DateTime(2010, 1, 1, 0, 59, 0)));
+
+auto st5 = SysTime(DateTime(2009, 12, 31, 0, 0, 0));
+st5.roll!"seconds"(1);
+assert(st5 == SysTime(DateTime(2009, 12, 31, 0, 0, 1)));
+
+auto st6 = SysTime(DateTime(2010, 1, 1, 0, 0, 0));
+st6.roll!"seconds"(-1);
+assert(st6 == SysTime(DateTime(2010, 1, 1, 0, 0, 59)));
+--------------------
+ +/
+ /+ref SysTime+/ void roll(string units)(long value) nothrow
+ if(units == "hours" ||
+ units == "minutes" ||
+ units == "seconds")
+ {
+ try
+ {
+ auto hnsecs = adjTime;
+ auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
+
+ if(hnsecs < 0)
+ {
+ hnsecs += convert!("hours", "hnsecs")(24);
+ --days;
+ }
+
+ immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
+ immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
+ immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
+
+ auto dateTime = DateTime(Date(cast(int)days), TimeOfDay(cast(int)hour, cast(int)minute, cast(int)second));
+ dateTime.roll!units(value);
+ --days;
+
+ hnsecs += convert!("hours", "hnsecs")(dateTime.hour);
+ hnsecs += convert!("minutes", "hnsecs")(dateTime.minute);
+ hnsecs += convert!("seconds", "hnsecs")(dateTime.second);
+
+ if(days < 0)
+ {
+ hnsecs -= convert!("hours", "hnsecs")(24);
+ ++days;
+ }
+
+ immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
+
+ adjTime = newDaysHNSecs + hnsecs;
+ }
+ catch(Exception e)
+ assert(0, "Either DateTime's constructor or TimeOfDay's constructor threw.");
+ }
+
+ //Test roll!"hours"().
+ unittest
+ {
+ static void TestST(SysTime orig, int hours, in SysTime expected, size_t line = __LINE__)
+ {
+ orig.roll!"hours"(hours);
+ assertPred!"=="(orig, expected, "", __FILE__, line);
+ }
+
+ //Test A.D.
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 1, SysTime(DateTime(1999, 7, 6, 13, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 2, SysTime(DateTime(1999, 7, 6, 14, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 3, SysTime(DateTime(1999, 7, 6, 15, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 4, SysTime(DateTime(1999, 7, 6, 16, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 5, SysTime(DateTime(1999, 7, 6, 17, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 6, SysTime(DateTime(1999, 7, 6, 18, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 7, SysTime(DateTime(1999, 7, 6, 19, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 8, SysTime(DateTime(1999, 7, 6, 20, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 9, SysTime(DateTime(1999, 7, 6, 21, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 10, SysTime(DateTime(1999, 7, 6, 22, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 11, SysTime(DateTime(1999, 7, 6, 23, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 12, SysTime(DateTime(1999, 7, 6, 0, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 13, SysTime(DateTime(1999, 7, 6, 1, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 14, SysTime(DateTime(1999, 7, 6, 2, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 15, SysTime(DateTime(1999, 7, 6, 3, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 16, SysTime(DateTime(1999, 7, 6, 4, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 17, SysTime(DateTime(1999, 7, 6, 5, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 18, SysTime(DateTime(1999, 7, 6, 6, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 19, SysTime(DateTime(1999, 7, 6, 7, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 20, SysTime(DateTime(1999, 7, 6, 8, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 21, SysTime(DateTime(1999, 7, 6, 9, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 22, SysTime(DateTime(1999, 7, 6, 10, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 23, SysTime(DateTime(1999, 7, 6, 11, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 24, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 25, SysTime(DateTime(1999, 7, 6, 13, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 50, SysTime(DateTime(1999, 7, 6, 14, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 10_000, SysTime(DateTime(1999, 7, 6, 4, 30, 33), FracSec.from!"msecs"(45)));
+
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -1, SysTime(DateTime(1999, 7, 6, 11, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -2, SysTime(DateTime(1999, 7, 6, 10, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -3, SysTime(DateTime(1999, 7, 6, 9, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -4, SysTime(DateTime(1999, 7, 6, 8, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -5, SysTime(DateTime(1999, 7, 6, 7, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -6, SysTime(DateTime(1999, 7, 6, 6, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -7, SysTime(DateTime(1999, 7, 6, 5, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -8, SysTime(DateTime(1999, 7, 6, 4, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -9, SysTime(DateTime(1999, 7, 6, 3, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -10, SysTime(DateTime(1999, 7, 6, 2, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -11, SysTime(DateTime(1999, 7, 6, 1, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -12, SysTime(DateTime(1999, 7, 6, 0, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -13, SysTime(DateTime(1999, 7, 6, 23, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -14, SysTime(DateTime(1999, 7, 6, 22, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -15, SysTime(DateTime(1999, 7, 6, 21, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -16, SysTime(DateTime(1999, 7, 6, 20, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -17, SysTime(DateTime(1999, 7, 6, 19, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -18, SysTime(DateTime(1999, 7, 6, 18, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -19, SysTime(DateTime(1999, 7, 6, 17, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -20, SysTime(DateTime(1999, 7, 6, 16, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -21, SysTime(DateTime(1999, 7, 6, 15, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -22, SysTime(DateTime(1999, 7, 6, 14, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -23, SysTime(DateTime(1999, 7, 6, 13, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -24, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -25, SysTime(DateTime(1999, 7, 6, 11, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -50, SysTime(DateTime(1999, 7, 6, 10, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -10_000, SysTime(DateTime(1999, 7, 6, 20, 30, 33), FracSec.from!"msecs"(45)));
+
+ TestST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), FracSec.from!"msecs"(45)), 1, SysTime(DateTime(1999, 7, 6, 1, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), FracSec.from!"msecs"(45)), 0, SysTime(DateTime(1999, 7, 6, 0, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), FracSec.from!"msecs"(45)), -1, SysTime(DateTime(1999, 7, 6, 23, 30, 33), FracSec.from!"msecs"(45)));
+
+ TestST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), FracSec.from!"msecs"(45)), 1, SysTime(DateTime(1999, 7, 6, 0, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), FracSec.from!"msecs"(45)), 0, SysTime(DateTime(1999, 7, 6, 23, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), FracSec.from!"msecs"(45)), -1, SysTime(DateTime(1999, 7, 6, 22, 30, 33), FracSec.from!"msecs"(45)));
+
+ TestST(SysTime(DateTime(1999, 7, 31, 23, 30, 33), FracSec.from!"msecs"(45)), 1, SysTime(DateTime(1999, 7, 31, 0, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 8, 1, 0, 30, 33), FracSec.from!"msecs"(45)), -1, SysTime(DateTime(1999, 8, 1, 23, 30, 33), FracSec.from!"msecs"(45)));
+
+ TestST(SysTime(DateTime(1999, 12, 31, 23, 30, 33), FracSec.from!"msecs"(45)), 1, SysTime(DateTime(1999, 12, 31, 0, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(2000, 1, 1, 0, 30, 33), FracSec.from!"msecs"(45)), -1, SysTime(DateTime(2000, 1, 1, 23, 30, 33), FracSec.from!"msecs"(45)));
+
+ TestST(SysTime(DateTime(1999, 2, 28, 23, 30, 33), FracSec.from!"msecs"(45)), 25, SysTime(DateTime(1999, 2, 28, 0, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1999, 3, 2, 0, 30, 33), FracSec.from!"msecs"(45)), -25, SysTime(DateTime(1999, 3, 2, 23, 30, 33), FracSec.from!"msecs"(45)));
+
+ TestST(SysTime(DateTime(2000, 2, 28, 23, 30, 33), FracSec.from!"msecs"(45)), 25, SysTime(DateTime(2000, 2, 28, 0, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(2000, 3, 1, 0, 30, 33), FracSec.from!"msecs"(45)), -25, SysTime(DateTime(2000, 3, 1, 23, 30, 33), FracSec.from!"msecs"(45)));
+
+ //Test B.C.
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 1, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 2, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 3, SysTime(DateTime(-1999, 7, 6, 15, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 4, SysTime(DateTime(-1999, 7, 6, 16, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 5, SysTime(DateTime(-1999, 7, 6, 17, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 6, SysTime(DateTime(-1999, 7, 6, 18, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 7, SysTime(DateTime(-1999, 7, 6, 19, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 8, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 9, SysTime(DateTime(-1999, 7, 6, 21, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 10, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 11, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 12, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 13, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 14, SysTime(DateTime(-1999, 7, 6, 2, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 15, SysTime(DateTime(-1999, 7, 6, 3, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 16, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 17, SysTime(DateTime(-1999, 7, 6, 5, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 18, SysTime(DateTime(-1999, 7, 6, 6, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 19, SysTime(DateTime(-1999, 7, 6, 7, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 20, SysTime(DateTime(-1999, 7, 6, 8, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 21, SysTime(DateTime(-1999, 7, 6, 9, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 22, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 23, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 24, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 25, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 50, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), 10_000, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), FracSec.from!"msecs"(45)));
+
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -1, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -2, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -3, SysTime(DateTime(-1999, 7, 6, 9, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -4, SysTime(DateTime(-1999, 7, 6, 8, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -5, SysTime(DateTime(-1999, 7, 6, 7, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -6, SysTime(DateTime(-1999, 7, 6, 6, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -7, SysTime(DateTime(-1999, 7, 6, 5, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -8, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -9, SysTime(DateTime(-1999, 7, 6, 3, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -10, SysTime(DateTime(-1999, 7, 6, 2, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -11, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -12, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -13, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -14, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -15, SysTime(DateTime(-1999, 7, 6, 21, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -16, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -17, SysTime(DateTime(-1999, 7, 6, 19, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -18, SysTime(DateTime(-1999, 7, 6, 18, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -19, SysTime(DateTime(-1999, 7, 6, 17, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -20, SysTime(DateTime(-1999, 7, 6, 16, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -21, SysTime(DateTime(-1999, 7, 6, 15, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -22, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -23, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -24, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -25, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -50, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(45)), -10_000, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), FracSec.from!"msecs"(45)));
+
+ TestST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), FracSec.from!"msecs"(45)), 1, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), FracSec.from!"msecs"(45)), 0, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), FracSec.from!"msecs"(45)), -1, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), FracSec.from!"msecs"(45)));
+
+ TestST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), FracSec.from!"msecs"(45)), 1, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), FracSec.from!"msecs"(45)), 0, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), FracSec.from!"msecs"(45)), -1, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), FracSec.from!"msecs"(45)));
+
+ TestST(SysTime(DateTime(-1999, 7, 31, 23, 30, 33), FracSec.from!"msecs"(45)), 1, SysTime(DateTime(-1999, 7, 31, 0, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-1999, 8, 1, 0, 30, 33), FracSec.from!"msecs"(45)), -1, SysTime(DateTime(-1999, 8, 1, 23, 30, 33), FracSec.from!"msecs"(45)));
+
+ TestST(SysTime(DateTime(-2001, 12, 31, 23, 30, 33), FracSec.from!"msecs"(45)), 1, SysTime(DateTime(-2001, 12, 31, 0, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-2000, 1, 1, 0, 30, 33), FracSec.from!"msecs"(45)), -1, SysTime(DateTime(-2000, 1, 1, 23, 30, 33), FracSec.from!"msecs"(45)));
+
+ TestST(SysTime(DateTime(-2001, 2, 28, 23, 30, 33), FracSec.from!"msecs"(45)), 25, SysTime(DateTime(-2001, 2, 28, 0, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-2001, 3, 2, 0, 30, 33), FracSec.from!"msecs"(45)), -25, SysTime(DateTime(-2001, 3, 2, 23, 30, 33), FracSec.from!"msecs"(45)));
+
+ TestST(SysTime(DateTime(-2000, 2, 28, 23, 30, 33), FracSec.from!"msecs"(45)), 25, SysTime(DateTime(-2000, 2, 28, 0, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(-2000, 3, 1, 0, 30, 33), FracSec.from!"msecs"(45)), -25, SysTime(DateTime(-2000, 3, 1, 23, 30, 33), FracSec.from!"msecs"(45)));
+
+ //Test Both
+ TestST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), FracSec.from!"msecs"(45)), 17_546, SysTime(DateTime(-1, 1, 1, 13, 30, 33), FracSec.from!"msecs"(45)));
+ TestST(SysTime(DateTime(1, 1, 1, 13, 30, 33), FracSec.from!"msecs"(45)), -17_546, SysTime(DateTime(1, 1, 1, 11, 30, 33), FracSec.from!"msecs"(45)));
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0));
+ sysTime.roll!"hours"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 23, 0, 0), FracSec.from!"hnsecs"(0)));
+ sysTime.roll!"hours"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 0, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.roll!"hours"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.roll!"hours"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 12, 31, 23, 0, 0), FracSec.from!"hnsecs"(0));
+ sysTime.roll!"hours"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 31, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ sysTime.roll!"hours"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 31, 23, 0, 0), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.roll!"hours"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 31, 0, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.roll!"hours"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst.roll!"hours"(4)));
+ //static assert(!__traits(compiles, ist.roll!"hours"(4)));
+
+ //Verify Examples.
+ auto st1 = SysTime(DateTime(2010, 7, 4, 12, 0, 0));
+ st1.roll!"hours"(1);
+ assert(st1 == SysTime(DateTime(2010, 7, 4, 13, 0, 0)));
+
+ auto st2 = SysTime(DateTime(2010, 2, 12, 12, 0, 0));
+ st2.roll!"hours"(-1);
+ assert(st2 == SysTime(DateTime(2010, 2, 12, 11, 0, 0)));
+
+ auto st3 = SysTime(DateTime(2009, 12, 31, 0, 0, 0));
+ st3.roll!"minutes"(1);
+ assert(st3 == SysTime(DateTime(2009, 12, 31, 0, 1, 0)));
+
+ auto st4 = SysTime(DateTime(2010, 1, 1, 0, 0, 0));
+ st4.roll!"minutes"(-1);
+ assert(st4 == SysTime(DateTime(2010, 1, 1, 0, 59, 0)));
+
+ auto st5 = SysTime(DateTime(2009, 12, 31, 0, 0, 0));
+ st5.roll!"seconds"(1);
+ assert(st5 == SysTime(DateTime(2009, 12, 31, 0, 0, 1)));
+
+ auto st6 = SysTime(DateTime(2010, 1, 1, 0, 0, 0));
+ st6.roll!"seconds"(-1);
+ assert(st6 == SysTime(DateTime(2010, 1, 1, 0, 0, 59)));
+ }
+
+ //Test roll!"minutes"().
+ unittest
+ {
+ static void TestST(SysTime orig, int minutes, in SysTime expected, size_t line = __LINE__)
+ {
+ orig.roll!"minutes"(minutes);
+ assertPred!"=="(orig, expected, "", __FILE__, line);
+ }
+
+ //Test A.D.
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 1, SysTime(DateTime(1999, 7, 6, 12, 31, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 2, SysTime(DateTime(1999, 7, 6, 12, 32, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 3, SysTime(DateTime(1999, 7, 6, 12, 33, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 4, SysTime(DateTime(1999, 7, 6, 12, 34, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 5, SysTime(DateTime(1999, 7, 6, 12, 35, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 10, SysTime(DateTime(1999, 7, 6, 12, 40, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 15, SysTime(DateTime(1999, 7, 6, 12, 45, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 29, SysTime(DateTime(1999, 7, 6, 12, 59, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 30, SysTime(DateTime(1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 45, SysTime(DateTime(1999, 7, 6, 12, 15, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 75, SysTime(DateTime(1999, 7, 6, 12, 45, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 90, SysTime(DateTime(1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 100, SysTime(DateTime(1999, 7, 6, 12, 10, 33), FracSec.from!"usecs"(7203)));
+
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 689, SysTime(DateTime(1999, 7, 6, 12, 59, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 690, SysTime(DateTime(1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 691, SysTime(DateTime(1999, 7, 6, 12, 1, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 960, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 1439, SysTime(DateTime(1999, 7, 6, 12, 29, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 1440, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 1441, SysTime(DateTime(1999, 7, 6, 12, 31, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 2880, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)));
+
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -1, SysTime(DateTime(1999, 7, 6, 12, 29, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -2, SysTime(DateTime(1999, 7, 6, 12, 28, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -3, SysTime(DateTime(1999, 7, 6, 12, 27, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -4, SysTime(DateTime(1999, 7, 6, 12, 26, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -5, SysTime(DateTime(1999, 7, 6, 12, 25, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -10, SysTime(DateTime(1999, 7, 6, 12, 20, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -15, SysTime(DateTime(1999, 7, 6, 12, 15, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -29, SysTime(DateTime(1999, 7, 6, 12, 1, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -30, SysTime(DateTime(1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -45, SysTime(DateTime(1999, 7, 6, 12, 45, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -75, SysTime(DateTime(1999, 7, 6, 12, 15, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -90, SysTime(DateTime(1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -100, SysTime(DateTime(1999, 7, 6, 12, 50, 33), FracSec.from!"usecs"(7203)));
+
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -749, SysTime(DateTime(1999, 7, 6, 12, 1, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -750, SysTime(DateTime(1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -751, SysTime(DateTime(1999, 7, 6, 12, 59, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -960, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -1439, SysTime(DateTime(1999, 7, 6, 12, 31, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -1440, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -1441, SysTime(DateTime(1999, 7, 6, 12, 29, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -2880, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)));
+
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)), 1, SysTime(DateTime(1999, 7, 6, 12, 1, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)), 0, SysTime(DateTime(1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)), -1, SysTime(DateTime(1999, 7, 6, 12, 59, 33), FracSec.from!"usecs"(7203)));
+
+ TestST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), FracSec.from!"usecs"(7203)), 1, SysTime(DateTime(1999, 7, 6, 11, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), FracSec.from!"usecs"(7203)), 0, SysTime(DateTime(1999, 7, 6, 11, 59, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), FracSec.from!"usecs"(7203)), -1, SysTime(DateTime(1999, 7, 6, 11, 58, 33), FracSec.from!"usecs"(7203)));
+
+ TestST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), FracSec.from!"usecs"(7203)), 1, SysTime(DateTime(1999, 7, 6, 0, 1, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), FracSec.from!"usecs"(7203)), 0, SysTime(DateTime(1999, 7, 6, 0, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), FracSec.from!"usecs"(7203)), -1, SysTime(DateTime(1999, 7, 6, 0, 59, 33), FracSec.from!"usecs"(7203)));
+
+ TestST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), FracSec.from!"usecs"(7203)), 1, SysTime(DateTime(1999, 7, 5, 23, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), FracSec.from!"usecs"(7203)), 0, SysTime(DateTime(1999, 7, 5, 23, 59, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), FracSec.from!"usecs"(7203)), -1, SysTime(DateTime(1999, 7, 5, 23, 58, 33), FracSec.from!"usecs"(7203)));
+
+ TestST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), FracSec.from!"usecs"(7203)), 1, SysTime(DateTime(1998, 12, 31, 23, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), FracSec.from!"usecs"(7203)), 0, SysTime(DateTime(1998, 12, 31, 23, 59, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), FracSec.from!"usecs"(7203)), -1, SysTime(DateTime(1998, 12, 31, 23, 58, 33), FracSec.from!"usecs"(7203)));
+
+ //Test B.C.
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 1, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 2, SysTime(DateTime(-1999, 7, 6, 12, 32, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 3, SysTime(DateTime(-1999, 7, 6, 12, 33, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 4, SysTime(DateTime(-1999, 7, 6, 12, 34, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 5, SysTime(DateTime(-1999, 7, 6, 12, 35, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 10, SysTime(DateTime(-1999, 7, 6, 12, 40, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 15, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 29, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 30, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 45, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 75, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 90, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 100, SysTime(DateTime(-1999, 7, 6, 12, 10, 33), FracSec.from!"usecs"(7203)));
+
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 689, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 690, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 691, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 960, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 1439, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 1440, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 1441, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), 2880, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)));
+
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -1, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -2, SysTime(DateTime(-1999, 7, 6, 12, 28, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -3, SysTime(DateTime(-1999, 7, 6, 12, 27, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -4, SysTime(DateTime(-1999, 7, 6, 12, 26, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -5, SysTime(DateTime(-1999, 7, 6, 12, 25, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -10, SysTime(DateTime(-1999, 7, 6, 12, 20, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -15, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -29, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -30, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -45, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -75, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -90, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -100, SysTime(DateTime(-1999, 7, 6, 12, 50, 33), FracSec.from!"usecs"(7203)));
+
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -749, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -750, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -751, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -960, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -1439, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -1440, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -1441, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)), -2880, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7203)));
+
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)), 1, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)), 0, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), FracSec.from!"usecs"(7203)), -1, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), FracSec.from!"usecs"(7203)));
+
+ TestST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), FracSec.from!"usecs"(7203)), 1, SysTime(DateTime(-1999, 7, 6, 11, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), FracSec.from!"usecs"(7203)), 0, SysTime(DateTime(-1999, 7, 6, 11, 59, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), FracSec.from!"usecs"(7203)), -1, SysTime(DateTime(-1999, 7, 6, 11, 58, 33), FracSec.from!"usecs"(7203)));
+
+ TestST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), FracSec.from!"usecs"(7203)), 1, SysTime(DateTime(-1999, 7, 6, 0, 1, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), FracSec.from!"usecs"(7203)), 0, SysTime(DateTime(-1999, 7, 6, 0, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), FracSec.from!"usecs"(7203)), -1, SysTime(DateTime(-1999, 7, 6, 0, 59, 33), FracSec.from!"usecs"(7203)));
+
+ TestST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), FracSec.from!"usecs"(7203)), 1, SysTime(DateTime(-1999, 7, 5, 23, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), FracSec.from!"usecs"(7203)), 0, SysTime(DateTime(-1999, 7, 5, 23, 59, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), FracSec.from!"usecs"(7203)), -1, SysTime(DateTime(-1999, 7, 5, 23, 58, 33), FracSec.from!"usecs"(7203)));
+
+ TestST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), FracSec.from!"usecs"(7203)), 1, SysTime(DateTime(-2000, 12, 31, 23, 0, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), FracSec.from!"usecs"(7203)), 0, SysTime(DateTime(-2000, 12, 31, 23, 59, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), FracSec.from!"usecs"(7203)), -1, SysTime(DateTime(-2000, 12, 31, 23, 58, 33), FracSec.from!"usecs"(7203)));
+
+ //Test Both
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), -1, SysTime(DateTime(1, 1, 1, 0, 59, 0)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 0)), 1, SysTime(DateTime(0, 12, 31, 23, 0, 0)));
+
+ TestST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), -1, SysTime(DateTime(0, 1, 1, 0, 59, 0)));
+ TestST(SysTime(DateTime(-1, 12, 31, 23, 59, 0)), 1, SysTime(DateTime(-1, 12, 31, 23, 0, 0)));
+
+ TestST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), FracSec.from!"usecs"(7203)), 1_052_760, SysTime(DateTime(-1, 1, 1, 11, 30, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1, 1, 1, 13, 30, 33), FracSec.from!"usecs"(7203)), -1_052_760, SysTime(DateTime(1, 1, 1, 13, 30, 33), FracSec.from!"usecs"(7203)));
+
+ TestST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), FracSec.from!"usecs"(7203)), 1_052_782, SysTime(DateTime(-1, 1, 1, 11, 52, 33), FracSec.from!"usecs"(7203)));
+ TestST(SysTime(DateTime(1, 1, 1, 13, 52, 33), FracSec.from!"usecs"(7203)), -1_052_782, SysTime(DateTime(1, 1, 1, 13, 30, 33), FracSec.from!"usecs"(7203)));
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0));
+ sysTime.roll!"minutes"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 59, 0), FracSec.from!"hnsecs"(0)));
+ sysTime.roll!"minutes"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 59), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.roll!"minutes"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.roll!"minutes"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 0, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 0), FracSec.from!"hnsecs"(0));
+ sysTime.roll!"minutes"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 31, 23, 0, 0), FracSec.from!"hnsecs"(0)));
+ sysTime.roll!"minutes"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 31, 23, 59, 0), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.roll!"minutes"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 31, 23, 0, 59), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.roll!"minutes"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst.roll!"minutes"(4)));
+ //static assert(!__traits(compiles, ist.roll!"minutes"(4)));
+ }
+
+ //Test roll!"seconds"().
+ unittest
+ {
+ static void TestST(SysTime orig, int seconds, in SysTime expected, size_t line = __LINE__)
+ {
+ orig.roll!"seconds"(seconds);
+ assertPred!"=="(orig, expected, "", __FILE__, line);
+ }
+
+ //Test A.D.
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 1, SysTime(DateTime(1999, 7, 6, 12, 30, 34), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 2, SysTime(DateTime(1999, 7, 6, 12, 30, 35), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 3, SysTime(DateTime(1999, 7, 6, 12, 30, 36), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 4, SysTime(DateTime(1999, 7, 6, 12, 30, 37), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 5, SysTime(DateTime(1999, 7, 6, 12, 30, 38), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 10, SysTime(DateTime(1999, 7, 6, 12, 30, 43), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 15, SysTime(DateTime(1999, 7, 6, 12, 30, 48), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 26, SysTime(DateTime(1999, 7, 6, 12, 30, 59), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 27, SysTime(DateTime(1999, 7, 6, 12, 30, 0), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 30, SysTime(DateTime(1999, 7, 6, 12, 30, 3), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 59, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 61, SysTime(DateTime(1999, 7, 6, 12, 30, 34), FracSec.from!"msecs"(274)));
+
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 1766, SysTime(DateTime(1999, 7, 6, 12, 30, 59), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 1767, SysTime(DateTime(1999, 7, 6, 12, 30, 0), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 1768, SysTime(DateTime(1999, 7, 6, 12, 30, 1), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 2007, SysTime(DateTime(1999, 7, 6, 12, 30, 0), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 3599, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 3600, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 3601, SysTime(DateTime(1999, 7, 6, 12, 30, 34), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 7200, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -1, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -2, SysTime(DateTime(1999, 7, 6, 12, 30, 31), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -3, SysTime(DateTime(1999, 7, 6, 12, 30, 30), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -4, SysTime(DateTime(1999, 7, 6, 12, 30, 29), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -5, SysTime(DateTime(1999, 7, 6, 12, 30, 28), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -10, SysTime(DateTime(1999, 7, 6, 12, 30, 23), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -15, SysTime(DateTime(1999, 7, 6, 12, 30, 18), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -33, SysTime(DateTime(1999, 7, 6, 12, 30, 0), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -34, SysTime(DateTime(1999, 7, 6, 12, 30, 59), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -35, SysTime(DateTime(1999, 7, 6, 12, 30, 58), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -59, SysTime(DateTime(1999, 7, 6, 12, 30, 34), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -61, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"msecs"(274)));
+
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), FracSec.from!"msecs"(274)), 1, SysTime(DateTime(1999, 7, 6, 12, 30, 1), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), FracSec.from!"msecs"(274)), 0, SysTime(DateTime(1999, 7, 6, 12, 30, 0), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), FracSec.from!"msecs"(274)), -1, SysTime(DateTime(1999, 7, 6, 12, 30, 59), FracSec.from!"msecs"(274)));
+
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), FracSec.from!"msecs"(274)), 1, SysTime(DateTime(1999, 7, 6, 12, 0, 1), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), FracSec.from!"msecs"(274)), 0, SysTime(DateTime(1999, 7, 6, 12, 0, 0), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), FracSec.from!"msecs"(274)), -1, SysTime(DateTime(1999, 7, 6, 12, 0, 59), FracSec.from!"msecs"(274)));
+
+ TestST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), FracSec.from!"msecs"(274)), 1, SysTime(DateTime(1999, 7, 6, 0, 0, 1), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), FracSec.from!"msecs"(274)), 0, SysTime(DateTime(1999, 7, 6, 0, 0, 0), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), FracSec.from!"msecs"(274)), -1, SysTime(DateTime(1999, 7, 6, 0, 0, 59), FracSec.from!"msecs"(274)));
+
+ TestST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), FracSec.from!"msecs"(274)), 1, SysTime(DateTime(1999, 7, 5, 23, 59, 0), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), FracSec.from!"msecs"(274)), 0, SysTime(DateTime(1999, 7, 5, 23, 59, 59), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), FracSec.from!"msecs"(274)), -1, SysTime(DateTime(1999, 7, 5, 23, 59, 58), FracSec.from!"msecs"(274)));
+
+ TestST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), FracSec.from!"msecs"(274)), 1, SysTime(DateTime(1998, 12, 31, 23, 59, 0), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), FracSec.from!"msecs"(274)), 0, SysTime(DateTime(1998, 12, 31, 23, 59, 59), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), FracSec.from!"msecs"(274)), -1, SysTime(DateTime(1998, 12, 31, 23, 59, 58), FracSec.from!"msecs"(274)));
+
+ //Test B.C.
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 35), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 3, SysTime(DateTime(-1999, 7, 6, 12, 30, 36), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 4, SysTime(DateTime(-1999, 7, 6, 12, 30, 37), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 5, SysTime(DateTime(-1999, 7, 6, 12, 30, 38), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 43), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 15, SysTime(DateTime(-1999, 7, 6, 12, 30, 48), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 26, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 27, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 30, SysTime(DateTime(-1999, 7, 6, 12, 30, 3), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 59, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 61, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), FracSec.from!"msecs"(274)));
+
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 1766, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 1767, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 1768, SysTime(DateTime(-1999, 7, 6, 12, 30, 1), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 2007, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 3599, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 3600, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 3601, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 7200, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 31), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -3, SysTime(DateTime(-1999, 7, 6, 12, 30, 30), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -4, SysTime(DateTime(-1999, 7, 6, 12, 30, 29), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -5, SysTime(DateTime(-1999, 7, 6, 12, 30, 28), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 23), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -15, SysTime(DateTime(-1999, 7, 6, 12, 30, 18), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -33, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -34, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -35, SysTime(DateTime(-1999, 7, 6, 12, 30, 58), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -59, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -61, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"msecs"(274)));
+
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), FracSec.from!"msecs"(274)), 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 1), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), FracSec.from!"msecs"(274)), 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), FracSec.from!"msecs"(274)), -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), FracSec.from!"msecs"(274)));
+
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), FracSec.from!"msecs"(274)), 1, SysTime(DateTime(-1999, 7, 6, 12, 0, 1), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), FracSec.from!"msecs"(274)), 0, SysTime(DateTime(-1999, 7, 6, 12, 0, 0), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), FracSec.from!"msecs"(274)), -1, SysTime(DateTime(-1999, 7, 6, 12, 0, 59), FracSec.from!"msecs"(274)));
+
+ TestST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), FracSec.from!"msecs"(274)), 1, SysTime(DateTime(-1999, 7, 6, 0, 0, 1), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), FracSec.from!"msecs"(274)), 0, SysTime(DateTime(-1999, 7, 6, 0, 0, 0), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), FracSec.from!"msecs"(274)), -1, SysTime(DateTime(-1999, 7, 6, 0, 0, 59), FracSec.from!"msecs"(274)));
+
+ TestST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), FracSec.from!"msecs"(274)), 1, SysTime(DateTime(-1999, 7, 5, 23, 59, 0), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), FracSec.from!"msecs"(274)), 0, SysTime(DateTime(-1999, 7, 5, 23, 59, 59), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), FracSec.from!"msecs"(274)), -1, SysTime(DateTime(-1999, 7, 5, 23, 59, 58), FracSec.from!"msecs"(274)));
+
+ TestST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), FracSec.from!"msecs"(274)), 1, SysTime(DateTime(-2000, 12, 31, 23, 59, 0), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), FracSec.from!"msecs"(274)), 0, SysTime(DateTime(-2000, 12, 31, 23, 59, 59), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), FracSec.from!"msecs"(274)), -1, SysTime(DateTime(-2000, 12, 31, 23, 59, 58), FracSec.from!"msecs"(274)));
+
+ //Test Both
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"msecs"(274)), -1, SysTime(DateTime(1, 1, 1, 0, 0, 59), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"msecs"(274)), 1, SysTime(DateTime(0, 12, 31, 23, 59, 0), FracSec.from!"msecs"(274)));
+
+ TestST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"msecs"(274)), -1, SysTime(DateTime(0, 1, 1, 0, 0, 59), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1, 12, 31, 23, 59, 59), FracSec.from!"msecs"(274)), 1, SysTime(DateTime(-1, 12, 31, 23, 59, 0), FracSec.from!"msecs"(274)));
+
+ TestST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), FracSec.from!"msecs"(274)), 63_165_600L, SysTime(DateTime(-1, 1, 1, 11, 30, 33), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1, 1, 1, 13, 30, 33), FracSec.from!"msecs"(274)), -63_165_600L, SysTime(DateTime(1, 1, 1, 13, 30, 33), FracSec.from!"msecs"(274)));
+
+ TestST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), FracSec.from!"msecs"(274)), 63_165_617L, SysTime(DateTime(-1, 1, 1, 11, 30, 50), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1, 1, 1, 13, 30, 50), FracSec.from!"msecs"(274)), -63_165_617L, SysTime(DateTime(1, 1, 1, 13, 30, 33), FracSec.from!"msecs"(274)));
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0));
+ sysTime.roll!"seconds"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 0, 59), FracSec.from!"hnsecs"(0)));
+ sysTime.roll!"seconds"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.roll!"seconds"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 0, 59), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.roll!"seconds"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(0));
+ sysTime.roll!"seconds"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 31, 23, 59, 0), FracSec.from!"hnsecs"(0)));
+ sysTime.roll!"seconds"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(0)));
+ }
+
+ {
+ auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ sysTime.roll!"seconds"(1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 31, 23, 59, 0), FracSec.from!"hnsecs"(9_999_999)));
+ sysTime.roll!"seconds"(-1);
+ assertPred!"=="(sysTime, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst.roll!"seconds"(4)));
+ //static assert(!__traits(compiles, ist.roll!"seconds"(4)));
+ }
+
+
+ /++
+ Add to the fractional seconds of the time of day. Negative values will
+ subtract.
+
+ The difference between rolling and adding is that rolling does not affect
+ larger units. So, if you roll the SysTime 1 second, you get the exact same
+ SysTime.
+
+ Note that SysTime has no $(D add!"msecs"()), $(D add!"usecs"()), or
+ $(D add!"hnsecs"()) function because you can add those units to
+ a SysTime by adding a duration to it.
+
+ Params:
+ units = The units to add to this SysTime.
+ value = The number of units to add to this SysTime.
+ +/
+ /+ref SysTime+/ void roll(string units)(long value) nothrow
+ if(units == "msecs" ||
+ units == "usecs" ||
+ units == "hnsecs")
+ {
+ auto hnsecs = adjTime;
+ immutable days = splitUnitsFromHNSecs!"days"(hnsecs);
+ immutable negative = hnsecs < 0;
+
+ if(negative)
+ hnsecs += convert!("hours", "hnsecs")(24);
+
+ immutable seconds = splitUnitsFromHNSecs!"seconds"(hnsecs);
+
+ hnsecs += convert!(units, "hnsecs")(value);
+ hnsecs %= convert!("seconds", "hnsecs")(1);
+
+ if(hnsecs < 0)
+ hnsecs += convert!("seconds", "hnsecs")(1);
+
+ hnsecs += convert!("seconds", "hnsecs")(seconds);
+
+ if(negative)
+ hnsecs -= convert!("hours", "hnsecs")(24);
+
+ immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
+
+ adjTime = newDaysHNSecs + hnsecs;
+ }
+
+
+ //Test roll!"msecs"().
+ unittest
+ {
+ static void TestST(SysTime orig, int milliseconds, in SysTime expected, size_t line = __LINE__)
+ {
+ orig.roll!"msecs"(milliseconds);
+ assertPred!"=="(orig, expected, "", __FILE__, line);
+ }
+
+ //Test A.D.
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(275)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(276)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(284)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(374)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(0)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(275)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(0)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(1)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(0)));
+
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(273)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(272)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(264)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(174)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(0)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(273)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(0)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(0)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(999)));
+
+ //Test B.C.
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(275)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(276)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(284)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(374)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(0)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(275)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(0)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(1)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(0)));
+
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(273)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(272)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(264)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(174)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(0)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(273)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(0)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(0)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(274)), -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(999)));
+
+ //Test Both
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"msecs"(0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"msecs"(1)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"msecs"(0)), 0, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"msecs"(0)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"msecs"(0)), -1, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"msecs"(999)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"msecs"(0)), -2, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"msecs"(998)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"msecs"(0)), -1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"msecs"(0)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"msecs"(0)), -2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"msecs"(0)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"msecs"(0)), -2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"msecs"(445)));
+
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_989_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(19_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(5_549_999)));
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst.addMSecs(4)));
+ //static assert(!__traits(compiles, ist.addMSecs(4)));
+ }
+
+ //Test roll!"usecs"().
+ unittest
+ {
+ static void TestST(SysTime orig, long microseconds, in SysTime expected, size_t line = __LINE__)
+ {
+ orig.roll!"usecs"(microseconds);
+ assertPred!"=="(orig, expected, "", __FILE__, line);
+ }
+
+ //Test A.D.
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(275)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(276)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(284)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(374)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(1000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(1274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(1275)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(2274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(26_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(27_000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(27_001)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(766_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(767_000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)));
+
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(273)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(272)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(264)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(174)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(0)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(999_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(999_274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(999_273)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(998_274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(967_000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(966_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(167_000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(166_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)));
+
+ //Test B.C.
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(275)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(276)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(284)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(374)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(1000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(1274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(1275)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(2274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(26_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(27_000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(27_001)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(766_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(767_000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)));
+
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(273)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(272)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(264)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(174)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(0)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(999_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(999_274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(999_273)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(998_274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(967_000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(966_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(167_000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(166_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)), -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(274)));
+
+ //Test Both
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(1)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(0)), 0, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(0)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(0)), -1, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(999_999)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(0)), -2, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(999_998)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(0)), -1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(999_000)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(0)), -2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(998_000)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(0)), -2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(997_445)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(0)), -1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(0)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(0)), -2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(0)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(0)), -2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"usecs"(666_667)));
+
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_989)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(19)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(19_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(25_549)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(3_333_329)));
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst.roll!"usecs"(4)));
+ //static assert(!__traits(compiles, ist.roll!"usecs"(4)));
+ }
+
+ //Test roll!"hnsecs"().
+ unittest
+ {
+ static void TestST(SysTime orig, long hnsecs, in SysTime expected, size_t line = __LINE__)
+ {
+ orig.roll!"hnsecs"(hnsecs);
+ assertPred!"=="(orig, expected, "", __FILE__, line);
+ }
+
+ //Test A.D.
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(275)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(276)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(284)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(374)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1275)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(26_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(27_000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(27_001)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_766_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_767_000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_000_274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(273)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(272)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(264)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(174)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(0)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(9_999_274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(9_999_273)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(9_998_274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(9_967_000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(9_966_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(8_167_000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(8_166_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(9_000_274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+
+ //Test B.C.
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(275)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(276)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(284)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(374)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1275)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(26_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(27_000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(27_001)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_766_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_767_000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_000_274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(273)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(272)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(264)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(174)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(0)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(9_999_274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(9_999_273)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(9_998_274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(9_967_000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(9_966_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(8_167_000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(8_166_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(9_000_274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+
+ //Test Both
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), 0, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -1, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -2, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_999_998)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_999_000)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_998_000)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_997_445)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_000_000)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(8_000_000)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(7_666_667)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_111_112)));
+
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_998)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(0)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(2554)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1_999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(2_333_332)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(888_887)));
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst.roll!"hnsecs"(4)));
+ //static assert(!__traits(compiles, ist.roll!"hnsecs"(4)));
+
+ //Verify Examples.
+ auto st1 = SysTime(DateTime(2010, 7, 4, 7, 32, 12));
+ st1.roll!"hnsecs"(1);
+ assert(st1 == SysTime(DateTime(2010, 7, 4, 7, 32, 12), FracSec.from!"hnsecs"(1)));
+
+ auto st2 = SysTime(DateTime(2010, 7, 4, 7, 32, 12));
+ st2.roll!"hnsecs"(-1);
+ assert(st2 == SysTime(DateTime(2010, 7, 4, 7, 32, 12), FracSec.from!"hnsecs"(9_999_999)));
+
+ auto st3 = SysTime(DateTime(2009, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ st3.roll!"hnsecs"(1);
+ assert(st3 == SysTime(DateTime(2009, 12, 31, 23, 59, 59)));
+
+ auto st4 = SysTime(DateTime(2010, 1, 1, 0, 0, 0));
+ st4.roll!"hnsecs"(-1);
+ assert(st4 == SysTime(DateTime(2010, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_999_999)));
+
+ auto st5 = SysTime(DateTime(2009, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999));
+ st5.roll!"hnsecs"(1);
+ assert(st5 == SysTime(DateTime(2009, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(0)));
+ }
+
+
+ /++
+ Gives the result of adding or subtracting a duration from this SysTime.
+
+ The legal types of arithmetic for SysTime using this operator are
+
+ $(TABLE
+ $(TR $(TD SysTime) $(TD +) $(TD duration) $(TD -->) $(TD SysTime))
+ $(TR $(TD SysTime) $(TD -) $(TD duration) $(TD -->) $(TD SysTime))
+ )
+
+ Params:
+ duration = The duration to add to or subtract from this SysTime.
+ +/
+ SysTime opBinary(string op, D)(in D duration) const pure nothrow
+ if((op == "+" || op == "-") &&
+ (is(Unqual!D == Duration) ||
+ is(Unqual!D == TickDuration)))
+ {
+ SysTime retval = SysTime(this._stdTime, this._timezone.get);
+
+ static if(is(Unqual!D == Duration))
+ immutable hnsecs = duration.total!"hnsecs";
+ else static if(is(Unqual!D == TickDuration))
+ immutable hnsecs = duration.hnsecs;
+
+ //Ideally, this would just be
+ //retval._stdTime += unaryFun!(op ~ "a")(hnsecs);
+ //But there isn't currently a pure version of unaryFun!().
+
+ static if(op == "+")
+ immutable signedHNSecs = hnsecs;
+ else static if(op == "-")
+ immutable signedHNSecs = -hnsecs;
+ else
+ static assert(0);
+
+ retval._stdTime += signedHNSecs;
+
+ return retval;
+ }
+
+ unittest
+ {
+ auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2_345_678));
+
+ assertPred!"=="(st + dur!"weeks"(7), SysTime(DateTime(1999, 8, 24, 12, 30, 33), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st + dur!"weeks"(-7), SysTime(DateTime(1999, 5, 18, 12, 30, 33), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st + dur!"days"(7), SysTime(DateTime(1999, 7, 13, 12, 30, 33), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st + dur!"days"(-7), SysTime(DateTime(1999, 6, 29, 12, 30, 33), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st + dur!"hours"(7), SysTime(DateTime(1999, 7, 6, 19, 30, 33), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st + dur!"hours"(-7), SysTime(DateTime(1999, 7, 6, 5, 30, 33), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st + dur!"minutes"(7), SysTime(DateTime(1999, 7, 6, 12, 37, 33), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st + dur!"minutes"(-7), SysTime(DateTime(1999, 7, 6, 12, 23, 33), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st + dur!"seconds"(7), SysTime(DateTime(1999, 7, 6, 12, 30, 40), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st + dur!"seconds"(-7), SysTime(DateTime(1999, 7, 6, 12, 30, 26), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st + dur!"msecs"(7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2_415_678)));
+ assertPred!"=="(st + dur!"msecs"(-7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2_275_678)));
+ assertPred!"=="(st + dur!"usecs"(7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2_345_748)));
+ assertPred!"=="(st + dur!"usecs"(-7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2_345_608)));
+ assertPred!"=="(st + dur!"hnsecs"(7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2_345_685)));
+ assertPred!"=="(st + dur!"hnsecs"(-7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2_345_671)));
+
+ //This probably only runs in cases where gettimeofday() is used, but it's
+ //hard to do this test correctly with variable ticksPerSec.
+ if(TickDuration.ticksPerSec == 1_000_000)
+ {
+ assertPred!"=="(st + TickDuration.from!"usecs"(7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2_345_748)));
+ assertPred!"=="(st + TickDuration.from!"usecs"(-7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2_345_608)));
+ }
+
+ assertPred!"=="(st - dur!"weeks"(-7), SysTime(DateTime(1999, 8, 24, 12, 30, 33), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st - dur!"weeks"(7), SysTime(DateTime(1999, 5, 18, 12, 30, 33), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st - dur!"days"(-7), SysTime(DateTime(1999, 7, 13, 12, 30, 33), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st - dur!"days"(7), SysTime(DateTime(1999, 6, 29, 12, 30, 33), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st - dur!"hours"(-7), SysTime(DateTime(1999, 7, 6, 19, 30, 33), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st - dur!"hours"(7), SysTime(DateTime(1999, 7, 6, 5, 30, 33), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st - dur!"minutes"(-7), SysTime(DateTime(1999, 7, 6, 12, 37, 33), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st - dur!"minutes"(7), SysTime(DateTime(1999, 7, 6, 12, 23, 33), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st - dur!"seconds"(-7), SysTime(DateTime(1999, 7, 6, 12, 30, 40), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st - dur!"seconds"(7), SysTime(DateTime(1999, 7, 6, 12, 30, 26), FracSec.from!"hnsecs"(2_345_678)));
+ assertPred!"=="(st - dur!"msecs"(-7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2_415_678)));
+ assertPred!"=="(st - dur!"msecs"(7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2_275_678)));
+ assertPred!"=="(st - dur!"usecs"(-7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2_345_748)));
+ assertPred!"=="(st - dur!"usecs"(7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2_345_608)));
+ assertPred!"=="(st - dur!"hnsecs"(-7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2_345_685)));
+ assertPred!"=="(st - dur!"hnsecs"(7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2_345_671)));
+
+ //This probably only runs in cases where gettimeofday() is used, but it's
+ //hard to do this test correctly with variable ticksPerSec.
+ if(TickDuration.ticksPerSec == 1_000_000)
+ {
+ assertPred!"=="(st - TickDuration.from!"usecs"(-7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2_345_748)));
+ assertPred!"=="(st - TickDuration.from!"usecs"(7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2_345_608)));
+ }
+
+ static void TestST(in SysTime orig, long hnsecs, in SysTime expected, size_t line = __LINE__)
+ {
+ assertPred!"=="(orig + dur!"hnsecs"(hnsecs), expected, "", __FILE__, line);
+ }
+
+ //Test A.D.
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(275)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(276)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(284)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(374)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1275)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(26_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(27_000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(27_001)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_766_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_767_000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_000_274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), FracSec.from!"hnsecs"(274)));
+
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(273)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(272)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(264)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(174)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(0)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_999_274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_999_273)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_998_274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_967_000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_966_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(8_167_000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(8_166_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_000_274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), FracSec.from!"hnsecs"(274)));
+
+ //Test B.C.
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(275)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(276)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(284)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(374)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1275)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(26_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(27_000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(27_001)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_766_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_767_000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_000_274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), FracSec.from!"hnsecs"(274)));
+
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(273)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(272)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(264)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(174)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(0)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_999_274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_999_273)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_998_274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_967_000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_966_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(8_167_000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(8_166_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_000_274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), FracSec.from!"hnsecs"(274)));
+
+ //Test Both
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), 0, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_998)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_000)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_998_000)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_997_445)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_000_000)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(8_000_000)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(7_666_667)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(0)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58), FracSec.from!"hnsecs"(0)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), FracSec.from!"hnsecs"(9_111_112)));
+
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_998)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(2554)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1_999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(2_333_332)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), FracSec.from!"hnsecs"(888_887)));
+
+ auto duration = dur!"seconds"(12);
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cst + duration));
+ //static assert(__traits(compiles, ist + duration));
+ static assert(__traits(compiles, cst - duration));
+ //static assert(__traits(compiles, ist - duration));
+ }
+
+
+ /++
+ Gives the result of adding or subtracting a duration from this SysTime,
+ as well as assigning the result to this SysTime.
+
+ The legal types of arithmetic for SysTime using this operator are
+
+ $(TABLE
+ $(TR $(TD SysTime) $(TD +) $(TD duration) $(TD -->) $(TD SysTime))
+ $(TR $(TD SysTime) $(TD -) $(TD duration) $(TD -->) $(TD SysTime))
+ )
+
+ Params:
+ duration = The duration to add to or subtract from this SysTime.
+ +/
+ /+ref+/ SysTime opOpAssign(string op, D)(in D duration) pure nothrow
+ if((op == "+" || op == "-") &&
+ (is(Unqual!D == Duration) ||
+ is(Unqual!D == TickDuration)))
+ {
+ static if(is(Unqual!D == Duration))
+ auto hnsecs = duration.total!"hnsecs";
+ else static if(is(Unqual!D == TickDuration))
+ auto hnsecs = duration.hnsecs;
+
+ //Ideally, this would just be
+ //_stdTime += unaryFun!(op ~ "a")(hnsecs);
+ //But there isn't currently a pure version of unaryFun!().
+
+ static if(op == "+")
+ immutable signedHNSecs = hnsecs;
+ else static if(op == "-")
+ immutable signedHNSecs = -hnsecs;
+ else
+ static assert(0);
+
+ _stdTime += signedHNSecs;
+
+ return this;
+ }
+
+ unittest
+ {
+ assertPred!"+="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"weeks"(7), SysTime(DateTime(1999, 8, 24, 12, 30, 33)));
+ assertPred!"+="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"weeks"(-7), SysTime(DateTime(1999, 5, 18, 12, 30, 33)));
+ assertPred!"+="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"days"(7), SysTime(DateTime(1999, 7, 13, 12, 30, 33)));
+ assertPred!"+="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"days"(-7), SysTime(DateTime(1999, 6, 29, 12, 30, 33)));
+
+ assertPred!"+="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"hours"(7), SysTime(DateTime(1999, 7, 6, 19, 30, 33)));
+ assertPred!"+="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"hours"(-7), SysTime(DateTime(1999, 7, 6, 5, 30, 33)));
+ assertPred!"+="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"minutes"(7), SysTime(DateTime(1999, 7, 6, 12, 37, 33)));
+ assertPred!"+="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"minutes"(-7), SysTime(DateTime(1999, 7, 6, 12, 23, 33)));
+ assertPred!"+="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"seconds"(7), SysTime(DateTime(1999, 7, 6, 12, 30, 40)));
+ assertPred!"+="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"seconds"(-7), SysTime(DateTime(1999, 7, 6, 12, 30, 26)));
+ assertPred!"+="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"msecs"(7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(7)));
+ assertPred!"+="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"msecs"(-7), SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"msecs"(993)));
+ assertPred!"+="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"usecs"(7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7)));
+ assertPred!"+="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"usecs"(-7), SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"usecs"(999_993)));
+ assertPred!"+="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"hnsecs"(7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(7)));
+ assertPred!"+="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"hnsecs"(-7), SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_999_993)));
+
+ assertPred!"-="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"weeks"(-7), SysTime(DateTime(1999, 8, 24, 12, 30, 33)));
+ assertPred!"-="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"weeks"(7), SysTime(DateTime(1999, 5, 18, 12, 30, 33)));
+ assertPred!"-="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"days"(-7), SysTime(DateTime(1999, 7, 13, 12, 30, 33)));
+ assertPred!"-="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"days"(7), SysTime(DateTime(1999, 6, 29, 12, 30, 33)));
+
+ assertPred!"-="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"hours"(-7), SysTime(DateTime(1999, 7, 6, 19, 30, 33)));
+ assertPred!"-="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"hours"(7), SysTime(DateTime(1999, 7, 6, 5, 30, 33)));
+ assertPred!"-="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"minutes"(-7), SysTime(DateTime(1999, 7, 6, 12, 37, 33)));
+ assertPred!"-="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"minutes"(7), SysTime(DateTime(1999, 7, 6, 12, 23, 33)));
+ assertPred!"-="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"seconds"(-7), SysTime(DateTime(1999, 7, 6, 12, 30, 40)));
+ assertPred!"-="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"seconds"(7), SysTime(DateTime(1999, 7, 6, 12, 30, 26)));
+ assertPred!"-="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"msecs"(-7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(7)));
+ assertPred!"-="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"msecs"(7), SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"msecs"(993)));
+ assertPred!"-="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"usecs"(-7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(7)));
+ assertPred!"-="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"usecs"(7), SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"usecs"(999_993)));
+ assertPred!"-="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"hnsecs"(-7), SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(7)));
+ assertPred!"-="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)), dur!"hnsecs"(7), SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_999_993)));
+
+ static void TestST(SysTime orig, long hnsecs, in SysTime expected, size_t line = __LINE__)
+ {
+ orig += dur!"hnsecs"(hnsecs);
+ assertPred!"=="(orig, expected, "", __FILE__, line);
+ }
+
+ //Test A.D.
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(275)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(276)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(284)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(374)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1275)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(26_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(27_000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(27_001)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_766_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_767_000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_000_274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), FracSec.from!"hnsecs"(274)));
+
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(273)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(272)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(264)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(174)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(0)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_999_274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_999_273)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_998_274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_967_000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_966_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(8_167_000)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(8_166_999)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_000_274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), FracSec.from!"hnsecs"(274)));
+
+ //Test B.C.
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(275)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(276)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(284)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(374)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1275)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(2274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(26_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(27_000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(27_001)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_766_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_767_000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_000_274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), FracSec.from!"hnsecs"(274)));
+
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(273)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(272)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(264)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(174)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(0)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_999_274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_999_273)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_998_274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_967_000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_966_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(8_167_000)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(8_166_999)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), FracSec.from!"hnsecs"(9_000_274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), FracSec.from!"hnsecs"(274)));
+ TestST(SysTime(DateTime(-1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(274)), -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), FracSec.from!"hnsecs"(274)));
+
+ //Test Both
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), 0, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_998)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_000)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_998_000)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_997_445)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_000_000)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(8_000_000)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(7_666_667)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(0)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58), FracSec.from!"hnsecs"(0)));
+ TestST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), FracSec.from!"hnsecs"(9_111_112)));
+
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_998)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(2554)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1_999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(2_333_332)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), FracSec.from!"hnsecs"(9_999_999)));
+ TestST(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), FracSec.from!"hnsecs"(888_887)));
+
+ auto duration = dur!"seconds"(12);
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst += duration));
+ //static assert(!__traits(compiles, ist += duration));
+ static assert(!__traits(compiles, cst -= duration));
+ //static assert(!__traits(compiles, ist -= duration));
+ }
+
+
+ /++
+ Gives the difference between two SysTimes.
+
+ The legal types of arithmetic for SysTime using this operator are
+
+ $(TABLE
+ $(TR $(TD SysTime) $(TD -) $(TD SysTime) $(TD -->) $(TD duration))
+ )
+ +/
+ Duration opBinary(string op)(in SysTime rhs) const pure nothrow
+ if(op == "-")
+ {
+ return dur!"hnsecs"(_stdTime - rhs._stdTime);
+ }
+
+ unittest
+ {
+ assertPred!"=="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1998, 7, 6, 12, 30, 33)),
+ dur!"seconds"(31_536_000));
+ assertPred!"=="(SysTime(DateTime(1998, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)),
+ dur!"seconds"(-31_536_000));
+
+ assertPred!"=="(SysTime(DateTime(1999, 8, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)),
+ dur!"seconds"(26_78_400));
+ assertPred!"=="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 8, 6, 12, 30, 33)),
+ dur!"seconds"(-26_78_400));
+
+ assertPred!"=="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 5, 12, 30, 33)),
+ dur!"seconds"(86_400));
+ assertPred!"=="(SysTime(DateTime(1999, 7, 5, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)),
+ dur!"seconds"(-86_400));
+
+ assertPred!"=="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 11, 30, 33)),
+ dur!"seconds"(3600));
+ assertPred!"=="(SysTime(DateTime(1999, 7, 6, 11, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)),
+ dur!"seconds"(-3600));
+
+ assertPred!"=="(SysTime(DateTime(1999, 7, 6, 12, 31, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)),
+ dur!"seconds"(60));
+ assertPred!"=="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 31, 33)),
+ dur!"seconds"(-60));
+
+ assertPred!"=="(SysTime(DateTime(1999, 7, 6, 12, 30, 34)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)),
+ dur!"seconds"(1));
+ assertPred!"=="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 34)),
+ dur!"seconds"(-1));
+
+ assertPred!"=="(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(532)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)),
+ dur!"msecs"(532));
+ assertPred!"=="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"msecs"(532)),
+ dur!"msecs"(-532));
+
+ assertPred!"=="(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(333_347)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)),
+ dur!"usecs"(333_347));
+ assertPred!"=="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"usecs"(333_347)),
+ dur!"usecs"(-333_347));
+
+ assertPred!"=="(SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_234_567)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)),
+ dur!"hnsecs"(1_234_567));
+ assertPred!"=="(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33), FracSec.from!"hnsecs"(1_234_567)),
+ dur!"hnsecs"(-1_234_567));
+
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)), dur!"seconds"(45033));
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(1, 1, 1, 12, 30, 33)), dur!"seconds"(-45033));
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)), dur!"seconds"(-41367));
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 12, 30, 33)), dur!"seconds"(41367));
+
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), dur!"hnsecs"(1));
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)), dur!"hnsecs"(-1));
+
+ auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, st - st));
+ static assert(__traits(compiles, cst - st));
+ //static assert(__traits(compiles, ist - st));
+
+ static assert(__traits(compiles, st - cst));
+ static assert(__traits(compiles, cst - cst));
+ //static assert(__traits(compiles, ist - cst));
+
+ //static assert(__traits(compiles, st - ist));
+ //static assert(__traits(compiles, cst - ist));
+ //static assert(__traits(compiles, ist - ist));
+ }
+
+
+ /++
+ Returns the difference between the two SysTimes in months.
+
+ You can get the difference in years by subtracting the year property
+ of two SysTimes, and you can get the difference in days or weeks by
+ subtracting the SysTimes themselves and using the Duration that results,
+ but because you cannot convert between months and smaller units without
+ a specific date (which the Duration from the subtraction of two SysTimes
+ won't have), you cannot get the difference in months without doing some
+ math using both the year and month properties, so this is a convenience
+ function for getting the difference in months.
+
+ Note that the number of days in the months or how far into the month either
+ date is is irrelevant. It is the difference in the month property combined
+ with the difference in years * 12. So, for instance, December 31st and
+ January 1st are one month apart just as December 1st and January 31st are
+ one month apart.
+
+ Params:
+ rhs = The SysTime to subtract from this one.
+
+ Examples:
+--------------------
+assert(SysTime(Date(1999, 2, 1)).diffMonths(SysTime(Date(1999, 1, 31))) == 1);
+assert(SysTime(Date(1999, 1, 31)).diffMonths(SysTime(Date(1999, 2, 1))) == -1);
+assert(SysTime(Date(1999, 3, 1)).diffMonths(SysTime(Date(1999, 1, 1))) == 2);
+assert(SysTime(Date(1999, 1, 1)).diffMonths(SysTime(Date(1999, 3, 31))) == -2);
+--------------------
+ +/
+ int diffMonths(in SysTime rhs) const nothrow
+ {
+ return (cast(Date)this).diffMonths(cast(Date)rhs);
+ }
+
+ unittest
+ {
+ auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, st.diffMonths(st)));
+ static assert(__traits(compiles, cst.diffMonths(st)));
+ //static assert(__traits(compiles, ist.diffMonths(st)));
+
+ static assert(__traits(compiles, st.diffMonths(cst)));
+ static assert(__traits(compiles, cst.diffMonths(cst)));
+ //static assert(__traits(compiles, ist.diffMonths(cst)));
+
+ //static assert(__traits(compiles, st.diffMonths(ist)));
+ //static assert(__traits(compiles, cst.diffMonths(ist)));
+ //static assert(__traits(compiles, ist.diffMonths(ist)));
+
+ //Verify Examples.
+ assert(SysTime(Date(1999, 2, 1)).diffMonths(SysTime(Date(1999, 1, 31))) == 1);
+ assert(SysTime(Date(1999, 1, 31)).diffMonths(SysTime(Date(1999, 2, 1))) == -1);
+ assert(SysTime(Date(1999, 3, 1)).diffMonths(SysTime(Date(1999, 1, 1))) == 2);
+ assert(SysTime(Date(1999, 1, 1)).diffMonths(SysTime(Date(1999, 3, 31))) == -2);
+ }
+
+
+ /++
+ Whether this SysTime is in a leap year.
+ +/
+ @property bool isLeapYear() const nothrow
+ {
+ return (cast(Date)this).isLeapYear;
+ }
+
+ unittest
+ {
+ auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, st.isLeapYear));
+ static assert(__traits(compiles, cst.isLeapYear));
+ //static assert(__traits(compiles, ist.isLeapYear));
+ }
+
+
+ /++
+ Day of the week this SysTime is on.
+ +/
+ @property DayOfWeek dayOfWeek() const nothrow
+ {
+ return getDayOfWeek(dayOfGregorianCal);
+ }
+
+ unittest
+ {
+ auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, st.dayOfWeek));
+ static assert(__traits(compiles, cst.dayOfWeek));
+ //static assert(__traits(compiles, ist.dayOfWeek));
+ }
+
+
+ /++
+ Day of the year this SysTime is on.
+
+ Examples:
+--------------------
+assert(SysTime(DateTime(1999, 1, 1, 12, 22, 7)).dayOfYear == 1);
+assert(SysTime(DateTime(1999, 12, 31, 7, 2, 59)).dayOfYear == 365);
+assert(SysTime(DateTime(2000, 12, 31, 21, 20, 0)).dayOfYear == 366);
+--------------------
+ +/
+ @property ushort dayOfYear() const nothrow
+ {
+ return (cast(Date)this).dayOfYear;
+ }
+
+ unittest
+ {
+ auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, st.dayOfYear));
+ static assert(__traits(compiles, cst.dayOfYear));
+ //static assert(__traits(compiles, ist.dayOfYear));
+
+ //Verify Examples.
+ assert(SysTime(DateTime(1999, 1, 1, 12, 22, 7)).dayOfYear == 1);
+ assert(SysTime(DateTime(1999, 12, 31, 7, 2, 59)).dayOfYear == 365);
+ assert(SysTime(DateTime(2000, 12, 31, 21, 20, 0)).dayOfYear == 366);
+ }
+
+
+ /++
+ Day of the year.
+
+ Params:
+ day = The day of the year to set which day of the year this SysTime is on.
+ +/
+ @property void dayOfYear(int day)
+ {
+ immutable hnsecs = adjTime;
+ immutable days = convert!("hnsecs", "days")(hnsecs);
+ immutable theRest = hnsecs - convert!("days", "hnsecs")(days);
+
+ auto date = Date(cast(int)days);
+ date.dayOfYear = day;
+
+ immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
+
+ adjTime = newDaysHNSecs + theRest;
+ }
+
+ unittest
+ {
+ auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, st.dayOfYear = 12));
+ static assert(!__traits(compiles, cst.dayOfYear = 12));
+ //static assert(!__traits(compiles, ist.dayOfYear = 12));
+ }
+
+
+ /++
+ The Xth day of the Gregorian Calendar that this SysTime is on.
+
+ Examples:
+--------------------
+assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1);
+assert(SysTime(DateTime(1, 12, 31, 23, 59, 59)).dayOfGregorianCal == 365);
+assert(SysTime(DateTime(2, 1, 1, 2, 2, 2)).dayOfGregorianCal == 366);
+
+assert(SysTime(DateTime(0, 12, 31, 7, 7, 7)).dayOfGregorianCal == 0);
+assert(SysTime(DateTime(0, 1, 1, 19, 30, 0)).dayOfGregorianCal == -365);
+assert(SysTime(DateTime(-1, 12, 31, 4, 7, 0)).dayOfGregorianCal == -366);
+
+assert(SysTime(DateTime(2000, 1, 1, 9, 30, 20)).dayOfGregorianCal == 730_120);
+assert(SysTime(DateTime(2010, 12, 31, 15, 45, 50)).dayOfGregorianCal == 734_137);
+--------------------
+ +/
+ @property int dayOfGregorianCal() const nothrow
+ {
+ immutable adjustedTime = adjTime;
+
+ //We have to add one because 0 would be midnight, January 1st, 1 A.D., which would be
+ //the 1st day of the Gregorian Calendar, not the 0th. So, simply casting to days
+ //is one day off.
+ if(adjustedTime > 0)
+ return cast(int)getUnitsFromHNSecs!"days"(adjustedTime) + 1;
+
+ auto hnsecs = adjustedTime;
+ immutable days = cast(int)splitUnitsFromHNSecs!"days"(hnsecs);
+
+ return hnsecs == 0 ? days + 1 : days;
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal, 1);
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)).dayOfGregorianCal, 1);
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal, 1);
+
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 1);
+ assertPred!"=="(SysTime(DateTime(1, 1, 2, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 2);
+ assertPred!"=="(SysTime(DateTime(1, 2, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 32);
+ assertPred!"=="(SysTime(DateTime(2, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 366);
+ assertPred!"=="(SysTime(DateTime(3, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 731);
+ assertPred!"=="(SysTime(DateTime(4, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 1096);
+ assertPred!"=="(SysTime(DateTime(5, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 1462);
+ assertPred!"=="(SysTime(DateTime(50, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 17_898);
+ assertPred!"=="(SysTime(DateTime(97, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 35_065);
+ assertPred!"=="(SysTime(DateTime(100, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 36_160);
+ assertPred!"=="(SysTime(DateTime(101, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 36_525);
+ assertPred!"=="(SysTime(DateTime(105, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 37_986);
+ assertPred!"=="(SysTime(DateTime(200, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 72_684);
+ assertPred!"=="(SysTime(DateTime(201, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 73_049);
+ assertPred!"=="(SysTime(DateTime(300, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 109_208);
+ assertPred!"=="(SysTime(DateTime(301, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 109_573);
+ assertPred!"=="(SysTime(DateTime(400, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 145_732);
+ assertPred!"=="(SysTime(DateTime(401, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 146_098);
+ assertPred!"=="(SysTime(DateTime(500, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 182_257);
+ assertPred!"=="(SysTime(DateTime(501, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 182_622);
+ assertPred!"=="(SysTime(DateTime(1000, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 364_878);
+ assertPred!"=="(SysTime(DateTime(1001, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 365_243);
+ assertPred!"=="(SysTime(DateTime(1600, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 584_023);
+ assertPred!"=="(SysTime(DateTime(1601, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 584_389);
+ assertPred!"=="(SysTime(DateTime(1900, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 693_596);
+ assertPred!"=="(SysTime(DateTime(1901, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 693_961);
+ assertPred!"=="(SysTime(DateTime(1945, 11, 12, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 710_347);
+ assertPred!"=="(SysTime(DateTime(1999, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 729_755);
+ assertPred!"=="(SysTime(DateTime(2000, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 730_120);
+ assertPred!"=="(SysTime(DateTime(2001, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 730_486);
+
+ assertPred!"=="(SysTime(DateTime(2010, 1, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 733_773);
+ assertPred!"=="(SysTime(DateTime(2010, 1, 31, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 733_803);
+ assertPred!"=="(SysTime(DateTime(2010, 2, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 733_804);
+ assertPred!"=="(SysTime(DateTime(2010, 2, 28, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 733_831);
+ assertPred!"=="(SysTime(DateTime(2010, 3, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 733_832);
+ assertPred!"=="(SysTime(DateTime(2010, 3, 31, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 733_862);
+ assertPred!"=="(SysTime(DateTime(2010, 4, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 733_863);
+ assertPred!"=="(SysTime(DateTime(2010, 4, 30, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 733_892);
+ assertPred!"=="(SysTime(DateTime(2010, 5, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 733_893);
+ assertPred!"=="(SysTime(DateTime(2010, 5, 31, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 733_923);
+ assertPred!"=="(SysTime(DateTime(2010, 6, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 733_924);
+ assertPred!"=="(SysTime(DateTime(2010, 6, 30, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 733_953);
+ assertPred!"=="(SysTime(DateTime(2010, 7, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 733_954);
+ assertPred!"=="(SysTime(DateTime(2010, 7, 31, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 733_984);
+ assertPred!"=="(SysTime(DateTime(2010, 8, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 733_985);
+ assertPred!"=="(SysTime(DateTime(2010, 8, 31, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 734_015);
+ assertPred!"=="(SysTime(DateTime(2010, 9, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 734_016);
+ assertPred!"=="(SysTime(DateTime(2010, 9, 30, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 734_045);
+ assertPred!"=="(SysTime(DateTime(2010, 10, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 734_046);
+ assertPred!"=="(SysTime(DateTime(2010, 10, 31, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 734_076);
+ assertPred!"=="(SysTime(DateTime(2010, 11, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 734_077);
+ assertPred!"=="(SysTime(DateTime(2010, 11, 30, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 734_106);
+ assertPred!"=="(SysTime(DateTime(2010, 12, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 734_107);
+ assertPred!"=="(SysTime(DateTime(2010, 12, 31, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, 734_137);
+
+ assertPred!"=="(SysTime(DateTime(2012, 2, 1, 0, 0, 0), FracSec.from!"msecs"(0)).dayOfGregorianCal, 734_534);
+ assertPred!"=="(SysTime(DateTime(2012, 2, 28, 0, 0, 0), FracSec.from!"msecs"(0)).dayOfGregorianCal, 734_561);
+ assertPred!"=="(SysTime(DateTime(2012, 2, 29, 0, 0, 0), FracSec.from!"msecs"(0)).dayOfGregorianCal, 734_562);
+ assertPred!"=="(SysTime(DateTime(2012, 3, 1, 0, 0, 0), FracSec.from!"msecs"(0)).dayOfGregorianCal, 734_563);
+
+ //Test B.C.
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal, 0);
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_998)).dayOfGregorianCal, 0);
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(0)).dayOfGregorianCal, 0);
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 0, 0, 0), FracSec.from!"hnsecs"(1)).dayOfGregorianCal, 0);
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 0, 0, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal, 0);
+
+ assertPred!"=="(SysTime(DateTime(-1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal, -366);
+ assertPred!"=="(SysTime(DateTime(-1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_998)).dayOfGregorianCal, -366);
+ assertPred!"=="(SysTime(DateTime(-1, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(0)).dayOfGregorianCal, -366);
+ assertPred!"=="(SysTime(DateTime(-1, 12, 31, 0, 0, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal, -366);
+
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, 0);
+ assertPred!"=="(SysTime(DateTime(0, 12, 30, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -1);
+ assertPred!"=="(SysTime(DateTime(0, 12, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -30);
+ assertPred!"=="(SysTime(DateTime(0, 11, 30, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -31);
+
+ assertPred!"=="(SysTime(DateTime(-1, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -366);
+ assertPred!"=="(SysTime(DateTime(-1, 12, 30, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -367);
+ assertPred!"=="(SysTime(DateTime(-1, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -730);
+ assertPred!"=="(SysTime(DateTime(-2, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -731);
+ assertPred!"=="(SysTime(DateTime(-2, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -1095);
+ assertPred!"=="(SysTime(DateTime(-3, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -1096);
+ assertPred!"=="(SysTime(DateTime(-3, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -1460);
+ assertPred!"=="(SysTime(DateTime(-4, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -1461);
+ assertPred!"=="(SysTime(DateTime(-4, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -1826);
+ assertPred!"=="(SysTime(DateTime(-5, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -1827);
+ assertPred!"=="(SysTime(DateTime(-5, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -2191);
+ assertPred!"=="(SysTime(DateTime(-9, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -3652);
+
+ assertPred!"=="(SysTime(DateTime(-49, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -18_262);
+ assertPred!"=="(SysTime(DateTime(-50, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -18_627);
+ assertPred!"=="(SysTime(DateTime(-97, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -35_794);
+ assertPred!"=="(SysTime(DateTime(-99, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -36_160);
+ assertPred!"=="(SysTime(DateTime(-99, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -36_524);
+ assertPred!"=="(SysTime(DateTime(-100, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -36_889);
+ assertPred!"=="(SysTime(DateTime(-101, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -37_254);
+ assertPred!"=="(SysTime(DateTime(-105, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -38_715);
+ assertPred!"=="(SysTime(DateTime(-200, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -73_413);
+ assertPred!"=="(SysTime(DateTime(-201, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -73_778);
+ assertPred!"=="(SysTime(DateTime(-300, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -109_937);
+ assertPred!"=="(SysTime(DateTime(-301, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -110_302);
+ assertPred!"=="(SysTime(DateTime(-400, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -146_097);
+ assertPred!"=="(SysTime(DateTime(-400, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -146_462);
+ assertPred!"=="(SysTime(DateTime(-401, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -146_827);
+ assertPred!"=="(SysTime(DateTime(-499, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -182_621);
+ assertPred!"=="(SysTime(DateTime(-500, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -182_986);
+ assertPred!"=="(SysTime(DateTime(-501, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -183_351);
+ assertPred!"=="(SysTime(DateTime(-1000, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -365_607);
+ assertPred!"=="(SysTime(DateTime(-1001, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -365_972);
+ assertPred!"=="(SysTime(DateTime(-1599, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -584_387);
+ assertPred!"=="(SysTime(DateTime(-1600, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -584_388);
+ assertPred!"=="(SysTime(DateTime(-1600, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -584_753);
+ assertPred!"=="(SysTime(DateTime(-1601, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -585_118);
+ assertPred!"=="(SysTime(DateTime(-1900, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -694_325);
+ assertPred!"=="(SysTime(DateTime(-1901, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -694_690);
+ assertPred!"=="(SysTime(DateTime(-1999, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -730_484);
+ assertPred!"=="(SysTime(DateTime(-2000, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -730_485);
+ assertPred!"=="(SysTime(DateTime(-2000, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -730_850);
+ assertPred!"=="(SysTime(DateTime(-2001, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)).dayOfGregorianCal, -731_215);
+
+ assertPred!"=="(SysTime(DateTime(-2010, 1, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_502);
+ assertPred!"=="(SysTime(DateTime(-2010, 1, 31, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_472);
+ assertPred!"=="(SysTime(DateTime(-2010, 2, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_471);
+ assertPred!"=="(SysTime(DateTime(-2010, 2, 28, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_444);
+ assertPred!"=="(SysTime(DateTime(-2010, 3, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_443);
+ assertPred!"=="(SysTime(DateTime(-2010, 3, 31, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_413);
+ assertPred!"=="(SysTime(DateTime(-2010, 4, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_412);
+ assertPred!"=="(SysTime(DateTime(-2010, 4, 30, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_383);
+ assertPred!"=="(SysTime(DateTime(-2010, 5, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_382);
+ assertPred!"=="(SysTime(DateTime(-2010, 5, 31, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_352);
+ assertPred!"=="(SysTime(DateTime(-2010, 6, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_351);
+ assertPred!"=="(SysTime(DateTime(-2010, 6, 30, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_322);
+ assertPred!"=="(SysTime(DateTime(-2010, 7, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_321);
+ assertPred!"=="(SysTime(DateTime(-2010, 7, 31, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_291);
+ assertPred!"=="(SysTime(DateTime(-2010, 8, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_290);
+ assertPred!"=="(SysTime(DateTime(-2010, 8, 31, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_260);
+ assertPred!"=="(SysTime(DateTime(-2010, 9, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_259);
+ assertPred!"=="(SysTime(DateTime(-2010, 9, 30, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_230);
+ assertPred!"=="(SysTime(DateTime(-2010, 10, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_229);
+ assertPred!"=="(SysTime(DateTime(-2010, 10, 31, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_199);
+ assertPred!"=="(SysTime(DateTime(-2010, 11, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_198);
+ assertPred!"=="(SysTime(DateTime(-2010, 11, 30, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_169);
+ assertPred!"=="(SysTime(DateTime(-2010, 12, 1, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_168);
+ assertPred!"=="(SysTime(DateTime(-2010, 12, 31, 23, 59, 59), FracSec.from!"msecs"(999)).dayOfGregorianCal, -734_138);
+
+ assertPred!"=="(SysTime(DateTime(-2012, 2, 1, 0, 0, 0), FracSec.from!"msecs"(0)).dayOfGregorianCal, -735_202);
+ assertPred!"=="(SysTime(DateTime(-2012, 2, 28, 0, 0, 0), FracSec.from!"msecs"(0)).dayOfGregorianCal, -735_175);
+ assertPred!"=="(SysTime(DateTime(-2012, 2, 29, 0, 0, 0), FracSec.from!"msecs"(0)).dayOfGregorianCal, -735_174);
+ assertPred!"=="(SysTime(DateTime(-2012, 3, 1, 0, 0, 0), FracSec.from!"msecs"(0)).dayOfGregorianCal, -735_173);
+
+ assertPred!"=="(SysTime(DateTime(-3760, 9, 7, 0, 0, 0), FracSec.from!"msecs"(0)).dayOfGregorianCal, -1_373_427); //Start of Hebrew Calendar
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cst.dayOfGregorianCal));
+ //static assert(__traits(compiles, ist.dayOfGregorianCal));
+
+ //Verify Examples.
+ assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1);
+ assert(SysTime(DateTime(1, 12, 31, 23, 59, 59)).dayOfGregorianCal == 365);
+ assert(SysTime(DateTime(2, 1, 1, 2, 2, 2)).dayOfGregorianCal == 366);
+
+ assert(SysTime(DateTime(0, 12, 31, 7, 7, 7)).dayOfGregorianCal == 0);
+ assert(SysTime(DateTime(0, 1, 1, 19, 30, 0)).dayOfGregorianCal == -365);
+ assert(SysTime(DateTime(-1, 12, 31, 4, 7, 0)).dayOfGregorianCal == -366);
+
+ assert(SysTime(DateTime(2000, 1, 1, 9, 30, 20)).dayOfGregorianCal == 730_120);
+ assert(SysTime(DateTime(2010, 12, 31, 15, 45, 50)).dayOfGregorianCal == 734_137);
+ }
+
+
+ //Test that the logic for the day of the Gregorian Calendar is consistent
+ //between Date and SysTime.
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(Date(1, 1, 1).dayOfGregorianCal, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(1, 1, 2).dayOfGregorianCal, SysTime(DateTime(1, 1, 2, 0, 0, 0), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(1, 2, 1).dayOfGregorianCal, SysTime(DateTime(1, 2, 1, 0, 0, 0), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(2, 1, 1).dayOfGregorianCal, SysTime(DateTime(2, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(3, 1, 1).dayOfGregorianCal, SysTime(DateTime(3, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(4, 1, 1).dayOfGregorianCal, SysTime(DateTime(4, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(5, 1, 1).dayOfGregorianCal, SysTime(DateTime(5, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(50, 1, 1).dayOfGregorianCal, SysTime(DateTime(50, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(97, 1, 1).dayOfGregorianCal, SysTime(DateTime(97, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(100, 1, 1).dayOfGregorianCal, SysTime(DateTime(100, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(101, 1, 1).dayOfGregorianCal, SysTime(DateTime(101, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(105, 1, 1).dayOfGregorianCal, SysTime(DateTime(105, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(200, 1, 1).dayOfGregorianCal, SysTime(DateTime(200, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(201, 1, 1).dayOfGregorianCal, SysTime(DateTime(201, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(300, 1, 1).dayOfGregorianCal, SysTime(DateTime(300, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(301, 1, 1).dayOfGregorianCal, SysTime(DateTime(301, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(400, 1, 1).dayOfGregorianCal, SysTime(DateTime(400, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(401, 1, 1).dayOfGregorianCal, SysTime(DateTime(401, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(500, 1, 1).dayOfGregorianCal, SysTime(DateTime(500, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(501, 1, 1).dayOfGregorianCal, SysTime(DateTime(501, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(1000, 1, 1).dayOfGregorianCal, SysTime(DateTime(1000, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(1001, 1, 1).dayOfGregorianCal, SysTime(DateTime(1001, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(1600, 1, 1).dayOfGregorianCal, SysTime(DateTime(1600, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(1601, 1, 1).dayOfGregorianCal, SysTime(DateTime(1601, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(1900, 1, 1).dayOfGregorianCal, SysTime(DateTime(1900, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(1901, 1, 1).dayOfGregorianCal, SysTime(DateTime(1901, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(1945, 11, 12).dayOfGregorianCal, SysTime(DateTime(1945, 11, 12, 0, 0, 0), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(1999, 1, 1).dayOfGregorianCal, SysTime(DateTime(1999, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(1999, 7, 6).dayOfGregorianCal, SysTime(DateTime(1999, 7, 6, 12, 13, 14), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(2000, 1, 1).dayOfGregorianCal, SysTime(DateTime(2000, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(2001, 1, 1).dayOfGregorianCal, SysTime(DateTime(2001, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+
+ assertPred!"=="(Date(2010, 1, 1).dayOfGregorianCal, SysTime(DateTime(2010, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 1, 31).dayOfGregorianCal, SysTime(DateTime(2010, 1, 31, 23, 0, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 2, 1).dayOfGregorianCal, SysTime(DateTime(2010, 2, 1, 23, 59, 59), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 2, 28).dayOfGregorianCal, SysTime(DateTime(2010, 2, 28, 23, 59, 59), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 3, 1).dayOfGregorianCal, SysTime(DateTime(2010, 3, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 3, 31).dayOfGregorianCal, SysTime(DateTime(2010, 3, 31, 0, 0, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 4, 1).dayOfGregorianCal, SysTime(DateTime(2010, 4, 1, 0, 0, 0), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 4, 30).dayOfGregorianCal, SysTime(DateTime(2010, 4, 30, 0, 0, 0), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 5, 1).dayOfGregorianCal, SysTime(DateTime(2010, 5, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 5, 31).dayOfGregorianCal, SysTime(DateTime(2010, 5, 31, 12, 13, 14), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 6, 1).dayOfGregorianCal, SysTime(DateTime(2010, 6, 1, 12, 13, 14), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 6, 30).dayOfGregorianCal, SysTime(DateTime(2010, 6, 30, 12, 13, 14), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 7, 1).dayOfGregorianCal, SysTime(DateTime(2010, 7, 1, 12, 13, 14), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 7, 31).dayOfGregorianCal, SysTime(DateTime(2010, 7, 31, 23, 59, 59), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 8, 1).dayOfGregorianCal, SysTime(DateTime(2010, 8, 1, 23, 59, 59), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 8, 31).dayOfGregorianCal, SysTime(DateTime(2010, 8, 31, 23, 59, 59), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 9, 1).dayOfGregorianCal, SysTime(DateTime(2010, 9, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 9, 30).dayOfGregorianCal, SysTime(DateTime(2010, 9, 30, 12, 0, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 10, 1).dayOfGregorianCal, SysTime(DateTime(2010, 10, 1, 0, 12, 0), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 10, 31).dayOfGregorianCal, SysTime(DateTime(2010, 10, 31, 0, 0, 12), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 11, 1).dayOfGregorianCal, SysTime(DateTime(2010, 11, 1, 23, 0, 0), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 11, 30).dayOfGregorianCal, SysTime(DateTime(2010, 11, 30, 0, 59, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 12, 1).dayOfGregorianCal, SysTime(DateTime(2010, 12, 1, 0, 0, 59), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(2010, 12, 31).dayOfGregorianCal, SysTime(DateTime(2010, 12, 31, 0, 59, 59), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+
+ assertPred!"=="(Date(2012, 2, 1).dayOfGregorianCal, SysTime(DateTime(2012, 2, 1, 23, 0, 59), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(2012, 2, 28).dayOfGregorianCal, SysTime(DateTime(2012, 2, 28, 23, 59, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(2012, 2, 29).dayOfGregorianCal, SysTime(DateTime(2012, 2, 29, 7, 7, 7), FracSec.from!"hnsecs"(7)).dayOfGregorianCal);
+ assertPred!"=="(Date(2012, 3, 1).dayOfGregorianCal, SysTime(DateTime(2012, 3, 1, 7, 7, 7), FracSec.from!"hnsecs"(7)).dayOfGregorianCal);
+
+ //Test B.C.
+ assertPred!"=="(Date(0, 12, 31).dayOfGregorianCal, SysTime(DateTime(0, 12, 31, 0, 0, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(0, 12, 30).dayOfGregorianCal, SysTime(DateTime(0, 12, 30, 0, 0, 0), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(0, 12, 1).dayOfGregorianCal, SysTime(DateTime(0, 12, 1, 0, 0, 0), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(0, 11, 30).dayOfGregorianCal, SysTime(DateTime(0, 11, 30, 0, 0, 0), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+
+ assertPred!"=="(Date(-1, 12, 31).dayOfGregorianCal, SysTime(DateTime(-1, 12, 31, 12, 13, 14), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(-1, 12, 30).dayOfGregorianCal, SysTime(DateTime(-1, 12, 30, 12, 13, 14), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(-1, 1, 1).dayOfGregorianCal, SysTime(DateTime(-1, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2, 12, 31).dayOfGregorianCal, SysTime(DateTime(-2, 12, 31, 12, 13, 14), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2, 1, 1).dayOfGregorianCal, SysTime(DateTime(-2, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(-3, 12, 31).dayOfGregorianCal, SysTime(DateTime(-3, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(-3, 1, 1).dayOfGregorianCal, SysTime(DateTime(-3, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(-4, 12, 31).dayOfGregorianCal, SysTime(DateTime(-4, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(-4, 1, 1).dayOfGregorianCal, SysTime(DateTime(-4, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(-5, 12, 31).dayOfGregorianCal, SysTime(DateTime(-5, 12, 31, 0, 0, 0), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(-5, 1, 1).dayOfGregorianCal, SysTime(DateTime(-5, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(-9, 1, 1).dayOfGregorianCal, SysTime(DateTime(-9, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+
+ assertPred!"=="(Date(-49, 1, 1).dayOfGregorianCal, SysTime(DateTime(-49, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(-50, 1, 1).dayOfGregorianCal, SysTime(DateTime(-50, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(-97, 1, 1).dayOfGregorianCal, SysTime(DateTime(-97, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(-99, 12, 31).dayOfGregorianCal, SysTime(DateTime(-99, 12, 31, 12, 13, 14), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(-99, 1, 1).dayOfGregorianCal, SysTime(DateTime(-99, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(-100, 1, 1).dayOfGregorianCal, SysTime(DateTime(-100, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(-101, 1, 1).dayOfGregorianCal, SysTime(DateTime(-101, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(-105, 1, 1).dayOfGregorianCal, SysTime(DateTime(-105, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(-200, 1, 1).dayOfGregorianCal, SysTime(DateTime(-200, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(-201, 1, 1).dayOfGregorianCal, SysTime(DateTime(-201, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(-300, 1, 1).dayOfGregorianCal, SysTime(DateTime(-300, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(-301, 1, 1).dayOfGregorianCal, SysTime(DateTime(-301, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(-400, 12, 31).dayOfGregorianCal, SysTime(DateTime(-400, 12, 31, 12, 13, 14), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(-400, 1, 1).dayOfGregorianCal, SysTime(DateTime(-400, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(-401, 1, 1).dayOfGregorianCal, SysTime(DateTime(-401, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(-499, 1, 1).dayOfGregorianCal, SysTime(DateTime(-499, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(-500, 1, 1).dayOfGregorianCal, SysTime(DateTime(-500, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(-501, 1, 1).dayOfGregorianCal, SysTime(DateTime(-501, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(-1000, 1, 1).dayOfGregorianCal, SysTime(DateTime(-1000, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(-1001, 1, 1).dayOfGregorianCal, SysTime(DateTime(-1001, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(-1599, 1, 1).dayOfGregorianCal, SysTime(DateTime(-1599, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(-1600, 12, 31).dayOfGregorianCal, SysTime(DateTime(-1600, 12, 31, 0, 0, 0), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(-1600, 1, 1).dayOfGregorianCal, SysTime(DateTime(-1600, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(-1601, 1, 1).dayOfGregorianCal, SysTime(DateTime(-1601, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(-1900, 1, 1).dayOfGregorianCal, SysTime(DateTime(-1900, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(-1901, 1, 1).dayOfGregorianCal, SysTime(DateTime(-1901, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(-1999, 1, 1).dayOfGregorianCal, SysTime(DateTime(-1999, 1, 1, 12, 13, 14), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(-1999, 7, 6).dayOfGregorianCal, SysTime(DateTime(-1999, 7, 6, 12, 13, 14), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2000, 12, 31).dayOfGregorianCal, SysTime(DateTime(-2000, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2000, 1, 1).dayOfGregorianCal, SysTime(DateTime(-2000, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2001, 1, 1).dayOfGregorianCal, SysTime(DateTime(-2001, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+
+ assertPred!"=="(Date(-2010, 1, 1).dayOfGregorianCal, SysTime(DateTime(-2010, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 1, 31).dayOfGregorianCal, SysTime(DateTime(-2010, 1, 31, 0, 0, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 2, 1).dayOfGregorianCal, SysTime(DateTime(-2010, 2, 1, 0, 0, 0), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 2, 28).dayOfGregorianCal, SysTime(DateTime(-2010, 2, 28, 0, 0, 0), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 3, 1).dayOfGregorianCal, SysTime(DateTime(-2010, 3, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 3, 31).dayOfGregorianCal, SysTime(DateTime(-2010, 3, 31, 12, 13, 14), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 4, 1).dayOfGregorianCal, SysTime(DateTime(-2010, 4, 1, 12, 13, 14), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 4, 30).dayOfGregorianCal, SysTime(DateTime(-2010, 4, 30, 12, 13, 14), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 5, 1).dayOfGregorianCal, SysTime(DateTime(-2010, 5, 1, 12, 13, 14), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 5, 31).dayOfGregorianCal, SysTime(DateTime(-2010, 5, 31, 23, 59, 59), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 6, 1).dayOfGregorianCal, SysTime(DateTime(-2010, 6, 1, 23, 59, 59), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 6, 30).dayOfGregorianCal, SysTime(DateTime(-2010, 6, 30, 23, 59, 59), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 7, 1).dayOfGregorianCal, SysTime(DateTime(-2010, 7, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 7, 31).dayOfGregorianCal, SysTime(DateTime(-2010, 7, 31, 0, 0, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 8, 1).dayOfGregorianCal, SysTime(DateTime(-2010, 8, 1, 0, 0, 0), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 8, 31).dayOfGregorianCal, SysTime(DateTime(-2010, 8, 31, 0, 0, 0), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 9, 1).dayOfGregorianCal, SysTime(DateTime(-2010, 9, 1, 0, 0, 0), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 9, 30).dayOfGregorianCal, SysTime(DateTime(-2010, 9, 30, 12, 0, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 10, 1).dayOfGregorianCal, SysTime(DateTime(-2010, 10, 1, 0, 12, 0), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 10, 31).dayOfGregorianCal, SysTime(DateTime(-2010, 10, 31, 0, 0, 12), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 11, 1).dayOfGregorianCal, SysTime(DateTime(-2010, 11, 1, 23, 0, 0), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 11, 30).dayOfGregorianCal, SysTime(DateTime(-2010, 11, 30, 0, 59, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 12, 1).dayOfGregorianCal, SysTime(DateTime(-2010, 12, 1, 0, 0, 59), FracSec.from!"hnsecs"(500)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2010, 12, 31).dayOfGregorianCal, SysTime(DateTime(-2010, 12, 31, 0, 59, 59), FracSec.from!"hnsecs"(50_000)).dayOfGregorianCal);
+
+ assertPred!"=="(Date(-2012, 2, 1).dayOfGregorianCal, SysTime(DateTime(-2012, 2, 1, 23, 0, 59), FracSec.from!"hnsecs"(9_999_999)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2012, 2, 28).dayOfGregorianCal, SysTime(DateTime(-2012, 2, 28, 23, 59, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2012, 2, 29).dayOfGregorianCal, SysTime(DateTime(-2012, 2, 29, 7, 7, 7), FracSec.from!"hnsecs"(7)).dayOfGregorianCal);
+ assertPred!"=="(Date(-2012, 3, 1).dayOfGregorianCal, SysTime(DateTime(-2012, 3, 1, 7, 7, 7), FracSec.from!"hnsecs"(7)).dayOfGregorianCal);
+
+ assertPred!"=="(Date(-3760, 9, 7).dayOfGregorianCal, SysTime(DateTime(-3760, 9, 7, 0, 0, 0), FracSec.from!"hnsecs"(0)).dayOfGregorianCal);
+ }
+
+
+ /++
+ The Xth day of the Gregorian Calendar that this SysTime is on. Setting
+ this property does not affect the time portion of SysTime.
+
+ Params:
+ days = The day of the Gregorian Calendar to set this Date to.
+
+ Examples:
+--------------------
+auto st = SysTime(DateTime(0, 0, 0, 12, 0, 0));
+st.dayOfGregorianCal = 1;
+assert(st == SysTime(DateTime(1, 1, 1, 12, 0, 0)));
+
+st.dayOfGregorianCal = 365;
+assert(st == SysTime(DateTime(1, 12, 31, 12, 0, 0)));
+
+st.dayOfGregorianCal = 366;
+assert(st == SysTime(DateTime(2, 1, 1, 12, 0, 0)));
+
+st.dayOfGregorianCal = 0;
+assert(st == SysTime(DateTime(0, 12, 31, 12, 0, 0)));
+
+st.dayOfGregorianCal = -365;
+assert(st == SysTime(DateTime(-0, 1, 1, 12, 0, 0)));
+
+st.dayOfGregorianCal = -366;
+assert(st == SysTime(DateTime(-1, 12, 31, 12, 0, 0)));
+
+st.dayOfGregorianCal = 730_120;
+assert(st == SysTime(DateTime(2000, 1, 1, 12, 0, 0)));
+
+st.dayOfGregorianCal = 734_137;
+assert(st == SysTime(DateTime(2010, 12, 31, 12, 0, 0)));
+--------------------
+ +/
+ @property void dayOfGregorianCal(int days) nothrow
+ {
+ auto hnsecs = adjTime;
+ hnsecs = removeUnitsFromHNSecs!"days"(hnsecs);
+
+ if(hnsecs < 0)
+ hnsecs += convert!("hours", "hnsecs")(24);
+
+ if(--days < 0)
+ {
+ hnsecs -= convert!("hours", "hnsecs")(24);
+ ++days;
+ }
+
+ immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
+
+ adjTime = newDaysHNSecs + hnsecs;
+ }
+
+ unittest
+ {
+ void testST(SysTime orig, int day, in SysTime expected, size_t line = __LINE__)
+ {
+ orig.dayOfGregorianCal = day;
+ assertPred!"=="(orig, expected, "", __FILE__, line);
+ }
+
+ //Test A.D.
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 1, SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+
+ //Test B.C.
+ testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(1)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(0)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(0)));
+
+ //Test Both.
+ testST(SysTime(DateTime(-512, 7, 20, 0, 0, 0), FracSec.from!"hnsecs"(0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(DateTime(-513, 6, 6, 0, 0, 0), FracSec.from!"hnsecs"(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(-511, 5, 7, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 1, SysTime(DateTime(1, 1, 1, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+
+ testST(SysTime(DateTime(1607, 4, 8, 0, 0, 0), FracSec.from!"hnsecs"(0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0), FracSec.from!"hnsecs"(0)));
+ testST(SysTime(DateTime(1500, 3, 9, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ testST(SysTime(DateTime(999, 2, 10, 23, 59, 59), FracSec.from!"hnsecs"(1)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1)));
+ testST(SysTime(DateTime(2007, 12, 11, 23, 59, 59), FracSec.from!"hnsecs"(0)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(0)));
+
+
+ auto sysTime = SysTime(DateTime(1, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212));
+
+ void testST2(int day, in SysTime expected, size_t line = __LINE__)
+ {
+ sysTime.dayOfGregorianCal = day;
+ assertPred!"=="(sysTime, expected, "", __FILE__, line);
+ }
+
+ //Test A.D.
+ testST2(1, SysTime(DateTime(1, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(2, SysTime(DateTime(1, 1, 2, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(32, SysTime(DateTime(1, 2, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(366, SysTime(DateTime(2, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(731, SysTime(DateTime(3, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(1096, SysTime(DateTime(4, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(1462, SysTime(DateTime(5, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(17_898, SysTime(DateTime(50, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(35_065, SysTime(DateTime(97, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(36_160, SysTime(DateTime(100, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(36_525, SysTime(DateTime(101, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(37_986, SysTime(DateTime(105, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(72_684, SysTime(DateTime(200, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(73_049, SysTime(DateTime(201, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(109_208, SysTime(DateTime(300, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(109_573, SysTime(DateTime(301, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(145_732, SysTime(DateTime(400, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(146_098, SysTime(DateTime(401, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(182_257, SysTime(DateTime(500, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(182_622, SysTime(DateTime(501, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(364_878, SysTime(DateTime(1000, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(365_243, SysTime(DateTime(1001, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(584_023, SysTime(DateTime(1600, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(584_389, SysTime(DateTime(1601, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(693_596, SysTime(DateTime(1900, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(693_961, SysTime(DateTime(1901, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(729_755, SysTime(DateTime(1999, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(730_120, SysTime(DateTime(2000, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(730_486, SysTime(DateTime(2001, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+
+ testST2(733_773, SysTime(DateTime(2010, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(733_803, SysTime(DateTime(2010, 1, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(733_804, SysTime(DateTime(2010, 2, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(733_831, SysTime(DateTime(2010, 2, 28, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(733_832, SysTime(DateTime(2010, 3, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(733_862, SysTime(DateTime(2010, 3, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(733_863, SysTime(DateTime(2010, 4, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(733_892, SysTime(DateTime(2010, 4, 30, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(733_893, SysTime(DateTime(2010, 5, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(733_923, SysTime(DateTime(2010, 5, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(733_924, SysTime(DateTime(2010, 6, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(733_953, SysTime(DateTime(2010, 6, 30, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(733_954, SysTime(DateTime(2010, 7, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(733_984, SysTime(DateTime(2010, 7, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(733_985, SysTime(DateTime(2010, 8, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(734_015, SysTime(DateTime(2010, 8, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(734_016, SysTime(DateTime(2010, 9, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(734_045, SysTime(DateTime(2010, 9, 30, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(734_046, SysTime(DateTime(2010, 10, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(734_076, SysTime(DateTime(2010, 10, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(734_077, SysTime(DateTime(2010, 11, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(734_106, SysTime(DateTime(2010, 11, 30, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(734_107, SysTime(DateTime(2010, 12, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(734_137, SysTime(DateTime(2010, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+
+ testST2(734_534, SysTime(DateTime(2012, 2, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+
+ testST2(734_534, SysTime(DateTime(2012, 2, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+
+ testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+
+ //Test B.C.
+ testST2(0, SysTime(DateTime(0, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-1, SysTime(DateTime(0, 12, 30, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-30, SysTime(DateTime(0, 12, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-31, SysTime(DateTime(0, 11, 30, 12, 2, 9), FracSec.from!"msecs"(212)));
+
+ testST2(-366, SysTime(DateTime(-1, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-367, SysTime(DateTime(-1, 12, 30, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-730, SysTime(DateTime(-1, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-731, SysTime(DateTime(-2, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-1095, SysTime(DateTime(-2, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-1096, SysTime(DateTime(-3, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-1460, SysTime(DateTime(-3, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-1461, SysTime(DateTime(-4, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-1826, SysTime(DateTime(-4, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-1827, SysTime(DateTime(-5, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-2191, SysTime(DateTime(-5, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-3652, SysTime(DateTime(-9, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+
+ testST2(-18_262, SysTime(DateTime(-49, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-18_627, SysTime(DateTime(-50, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-35_794, SysTime(DateTime(-97, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-36_160, SysTime(DateTime(-99, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-36_524, SysTime(DateTime(-99, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-36_889, SysTime(DateTime(-100, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-37_254, SysTime(DateTime(-101, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-38_715, SysTime(DateTime(-105, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-73_413, SysTime(DateTime(-200, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-73_778, SysTime(DateTime(-201, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-109_937, SysTime(DateTime(-300, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-110_302, SysTime(DateTime(-301, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-146_097, SysTime(DateTime(-400, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-146_462, SysTime(DateTime(-400, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-146_827, SysTime(DateTime(-401, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-182_621, SysTime(DateTime(-499, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-182_986, SysTime(DateTime(-500, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-183_351, SysTime(DateTime(-501, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-365_607, SysTime(DateTime(-1000, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-365_972, SysTime(DateTime(-1001, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-584_387, SysTime(DateTime(-1599, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-584_388, SysTime(DateTime(-1600, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-584_753, SysTime(DateTime(-1600, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-585_118, SysTime(DateTime(-1601, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-694_325, SysTime(DateTime(-1900, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-694_690, SysTime(DateTime(-1901, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-730_484, SysTime(DateTime(-1999, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-730_485, SysTime(DateTime(-2000, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-730_850, SysTime(DateTime(-2000, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-731_215, SysTime(DateTime(-2001, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+
+ testST2(-734_502, SysTime(DateTime(-2010, 1, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_472, SysTime(DateTime(-2010, 1, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_471, SysTime(DateTime(-2010, 2, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_444, SysTime(DateTime(-2010, 2, 28, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_443, SysTime(DateTime(-2010, 3, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_413, SysTime(DateTime(-2010, 3, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_412, SysTime(DateTime(-2010, 4, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_383, SysTime(DateTime(-2010, 4, 30, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_382, SysTime(DateTime(-2010, 5, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_352, SysTime(DateTime(-2010, 5, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_351, SysTime(DateTime(-2010, 6, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_322, SysTime(DateTime(-2010, 6, 30, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_321, SysTime(DateTime(-2010, 7, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_291, SysTime(DateTime(-2010, 7, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_290, SysTime(DateTime(-2010, 8, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_260, SysTime(DateTime(-2010, 8, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_259, SysTime(DateTime(-2010, 9, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_230, SysTime(DateTime(-2010, 9, 30, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_229, SysTime(DateTime(-2010, 10, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_199, SysTime(DateTime(-2010, 10, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_198, SysTime(DateTime(-2010, 11, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_169, SysTime(DateTime(-2010, 11, 30, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_168, SysTime(DateTime(-2010, 12, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-734_138, SysTime(DateTime(-2010, 12, 31, 12, 2, 9), FracSec.from!"msecs"(212)));
+
+ testST2(-735_202, SysTime(DateTime(-2012, 2, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-735_175, SysTime(DateTime(-2012, 2, 28, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-735_174, SysTime(DateTime(-2012, 2, 29, 12, 2, 9), FracSec.from!"msecs"(212)));
+ testST2(-735_173, SysTime(DateTime(-2012, 3, 1, 12, 2, 9), FracSec.from!"msecs"(212)));
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(!__traits(compiles, cst.dayOfGregorianCal = 7));
+ //static assert(!__traits(compiles, ist.dayOfGregorianCal = 7));
+
+ //Verify Examples.
+ auto st = SysTime(DateTime(0, 1, 1, 12, 0, 0));
+ st.dayOfGregorianCal = 1;
+ assert(st == SysTime(DateTime(1, 1, 1, 12, 0, 0)));
+
+ st.dayOfGregorianCal = 365;
+ assert(st == SysTime(DateTime(1, 12, 31, 12, 0, 0)));
+
+ st.dayOfGregorianCal = 366;
+ assert(st == SysTime(DateTime(2, 1, 1, 12, 0, 0)));
+
+ st.dayOfGregorianCal = 0;
+ assert(st == SysTime(DateTime(0, 12, 31, 12, 0, 0)));
+
+ st.dayOfGregorianCal = -365;
+ assert(st == SysTime(DateTime(-0, 1, 1, 12, 0, 0)));
+
+ st.dayOfGregorianCal = -366;
+ assert(st == SysTime(DateTime(-1, 12, 31, 12, 0, 0)));
+
+ st.dayOfGregorianCal = 730_120;
+ assert(st == SysTime(DateTime(2000, 1, 1, 12, 0, 0)));
+
+ st.dayOfGregorianCal = 734_137;
+ assert(st == SysTime(DateTime(2010, 12, 31, 12, 0, 0)));
+ }
+
+
+ /++
+ The ISO 8601 week of the year that this SysTime is in.
+
+ See_Also:
+ ISO Week Date
+ +/
+ @property ubyte isoWeek() const nothrow
+ {
+ return (cast(Date)this).isoWeek;
+ }
+
+ unittest
+ {
+ auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, st.isoWeek));
+ static assert(__traits(compiles, cst.isoWeek));
+ //static assert(__traits(compiles, ist.isoWeek));
+ }
+
+
+ /++
+ SysTime for the last day in the month that this Date is in.
+ The time portion of endOfMonth is always 23:59:59.9999999.
+
+ Examples:
+--------------------
+assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).endOfMonth == SysTime(DateTime(1999, 1, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0), FracSec.from!"msecs"(24)).endOfMonth == SysTime(DateTime(1999, 2, 28, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27), FracSec.from!"usecs"(5203)).endOfMonth == SysTime(DateTime(2000, 2, 29, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9), FracSec.from!"hnsecs"(12345)).endOfMonth == SysTime(DateTime(2000, 6, 30, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+--------------------
+ +/
+ @property SysTime endOfMonth() const nothrow
+ {
+ immutable hnsecs = adjTime;
+ immutable days = getUnitsFromHNSecs!"days"(hnsecs);
+
+ auto date = Date(cast(int)days + 1).endOfMonth;
+ auto newDays = date.dayOfGregorianCal - 1;
+ long theTimeHNSecs;
+
+ if(newDays < 0)
+ {
+ theTimeHNSecs = -1;
+ ++newDays;
+ }
+ else
+ theTimeHNSecs = convert!("days", "hnsecs")(1) - 1;
+
+ immutable newDaysHNSecs = convert!("days", "hnsecs")(newDays);
+
+ auto retval = SysTime(this._stdTime, this._timezone.get);
+ retval.adjTime = newDaysHNSecs + theTimeHNSecs;
+
+ return retval;
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(SysTime(Date(1999, 1, 1)).endOfMonth, SysTime(DateTime(1999, 1, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(1999, 2, 1)).endOfMonth, SysTime(DateTime(1999, 2, 28, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(2000, 2, 1)).endOfMonth, SysTime(DateTime(2000, 2, 29, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(1999, 3, 1)).endOfMonth, SysTime(DateTime(1999, 3, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(1999, 4, 1)).endOfMonth, SysTime(DateTime(1999, 4, 30, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(1999, 5, 1)).endOfMonth, SysTime(DateTime(1999, 5, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(1999, 6, 1)).endOfMonth, SysTime(DateTime(1999, 6, 30, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(1999, 7, 1)).endOfMonth, SysTime(DateTime(1999, 7, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(1999, 8, 1)).endOfMonth, SysTime(DateTime(1999, 8, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(1999, 9, 1)).endOfMonth, SysTime(DateTime(1999, 9, 30, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(1999, 10, 1)).endOfMonth, SysTime(DateTime(1999, 10, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(1999, 11, 1)).endOfMonth, SysTime(DateTime(1999, 11, 30, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(1999, 12, 1)).endOfMonth, SysTime(DateTime(1999, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+
+ //Test B.C.
+ assertPred!"=="(SysTime(Date(-1999, 1, 1)).endOfMonth, SysTime(DateTime(-1999, 1, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(-1999, 2, 1)).endOfMonth, SysTime(DateTime(-1999, 2, 28, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(-2000, 2, 1)).endOfMonth, SysTime(DateTime(-2000, 2, 29, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(-1999, 3, 1)).endOfMonth, SysTime(DateTime(-1999, 3, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(-1999, 4, 1)).endOfMonth, SysTime(DateTime(-1999, 4, 30, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(-1999, 5, 1)).endOfMonth, SysTime(DateTime(-1999, 5, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(-1999, 6, 1)).endOfMonth, SysTime(DateTime(-1999, 6, 30, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(-1999, 7, 1)).endOfMonth, SysTime(DateTime(-1999, 7, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(-1999, 8, 1)).endOfMonth, SysTime(DateTime(-1999, 8, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(-1999, 9, 1)).endOfMonth, SysTime(DateTime(-1999, 9, 30, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(-1999, 10, 1)).endOfMonth, SysTime(DateTime(-1999, 10, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(-1999, 11, 1)).endOfMonth, SysTime(DateTime(-1999, 11, 30, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assertPred!"=="(SysTime(Date(-1999, 12, 1)).endOfMonth, SysTime(DateTime(-1999, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cst.endOfMonth));
+ //static assert(__traits(compiles, ist.endOfMonth));
+
+ //Verify Examples.
+ assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).endOfMonth == SysTime(DateTime(1999, 1, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0), FracSec.from!"msecs"(24)).endOfMonth == SysTime(DateTime(1999, 2, 28, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27), FracSec.from!"usecs"(5203)).endOfMonth == SysTime(DateTime(2000, 2, 29, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9), FracSec.from!"hnsecs"(12345)).endOfMonth == SysTime(DateTime(2000, 6, 30, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999)));
+ }
+
+
+ /++
+ The last day in the month that this SysTime is in.
+
+ Examples:
+--------------------
+assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).endOfMonthDay == 31);
+assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0)).endOfMonthDay == 28);
+assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27)).endOfMonthDay == 29);
+assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9)).endOfMonthDay == 30);
+--------------------
+ +/
+ @property ubyte endOfMonthDay() const nothrow
+ {
+ return Date(dayOfGregorianCal).endOfMonthDay;
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(SysTime(DateTime(1999, 1, 1, 12, 1, 13)).endOfMonthDay, 31);
+ assertPred!"=="(SysTime(DateTime(1999, 2, 1, 17, 13, 12)).endOfMonthDay, 28);
+ assertPred!"=="(SysTime(DateTime(2000, 2, 1, 13, 2, 12)).endOfMonthDay, 29);
+ assertPred!"=="(SysTime(DateTime(1999, 3, 1, 12, 13, 12)).endOfMonthDay, 31);
+ assertPred!"=="(SysTime(DateTime(1999, 4, 1, 12, 6, 13)).endOfMonthDay, 30);
+ assertPred!"=="(SysTime(DateTime(1999, 5, 1, 15, 13, 12)).endOfMonthDay, 31);
+ assertPred!"=="(SysTime(DateTime(1999, 6, 1, 13, 7, 12)).endOfMonthDay, 30);
+ assertPred!"=="(SysTime(DateTime(1999, 7, 1, 12, 13, 17)).endOfMonthDay, 31);
+ assertPred!"=="(SysTime(DateTime(1999, 8, 1, 12, 3, 13)).endOfMonthDay, 31);
+ assertPred!"=="(SysTime(DateTime(1999, 9, 1, 12, 13, 12)).endOfMonthDay, 30);
+ assertPred!"=="(SysTime(DateTime(1999, 10, 1, 13, 19, 12)).endOfMonthDay, 31);
+ assertPred!"=="(SysTime(DateTime(1999, 11, 1, 12, 13, 17)).endOfMonthDay, 30);
+ assertPred!"=="(SysTime(DateTime(1999, 12, 1, 12, 52, 13)).endOfMonthDay, 31);
+
+ //Test B.C.
+ assertPred!"=="(SysTime(DateTime(-1999, 1, 1, 12, 1, 13)).endOfMonthDay, 31);
+ assertPred!"=="(SysTime(DateTime(-1999, 2, 1, 7, 13, 12)).endOfMonthDay, 28);
+ assertPred!"=="(SysTime(DateTime(-2000, 2, 1, 13, 2, 12)).endOfMonthDay, 29);
+ assertPred!"=="(SysTime(DateTime(-1999, 3, 1, 12, 13, 12)).endOfMonthDay, 31);
+ assertPred!"=="(SysTime(DateTime(-1999, 4, 1, 12, 6, 13)).endOfMonthDay, 30);
+ assertPred!"=="(SysTime(DateTime(-1999, 5, 1, 5, 13, 12)).endOfMonthDay, 31);
+ assertPred!"=="(SysTime(DateTime(-1999, 6, 1, 13, 7, 12)).endOfMonthDay, 30);
+ assertPred!"=="(SysTime(DateTime(-1999, 7, 1, 12, 13, 17)).endOfMonthDay, 31);
+ assertPred!"=="(SysTime(DateTime(-1999, 8, 1, 12, 3, 13)).endOfMonthDay, 31);
+ assertPred!"=="(SysTime(DateTime(-1999, 9, 1, 12, 13, 12)).endOfMonthDay, 30);
+ assertPred!"=="(SysTime(DateTime(-1999, 10, 1, 13, 19, 12)).endOfMonthDay, 31);
+ assertPred!"=="(SysTime(DateTime(-1999, 11, 1, 12, 13, 17)).endOfMonthDay, 30);
+ assertPred!"=="(SysTime(DateTime(-1999, 12, 1, 12, 52, 13)).endOfMonthDay, 31);
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cst.endOfMonthDay));
+ //static assert(__traits(compiles, ist.endOfMonthDay));
+
+ //Verify Examples.
+ assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).endOfMonthDay == 31);
+ assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0)).endOfMonthDay == 28);
+ assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27)).endOfMonthDay == 29);
+ assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9)).endOfMonthDay == 30);
+ }
+
+
+ /++
+ Whether the current year is a date in A.D.
+
+ Examples:
+--------------------
+assert(SysTime(DateTime(1, 1, 1, 12, 7, 0)).isAD);
+assert(SysTime(DateTime(2010, 12, 31, 0, 0, 0)).isAD);
+assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD);
+assert(!SysTime(DateTime(-2010, 1, 1, 2, 2, 2)).isAD);
+--------------------
+ +/
+ @property bool isAD() const nothrow
+ {
+ return adjTime >= 0;
+ }
+
+ unittest
+ {
+ assert(SysTime(DateTime(2010, 7, 4, 12, 0, 9)).isAD);
+ assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).isAD);
+ assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD);
+ assert(!SysTime(DateTime(0, 1, 1, 23, 59, 59)).isAD);
+ assert(!SysTime(DateTime(-1, 1, 1, 23 ,59 ,59)).isAD);
+ assert(!SysTime(DateTime(-2010, 7, 4, 12, 2, 2)).isAD);
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cst.isAD));
+ //static assert(__traits(compiles, ist.isAD));
+
+ //Verify Examples.
+ assert(SysTime(DateTime(1, 1, 1, 12, 7, 0)).isAD);
+ assert(SysTime(DateTime(2010, 12, 31, 0, 0, 0)).isAD);
+ assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD);
+ assert(!SysTime(DateTime(-2010, 1, 1, 2, 2, 2)).isAD);
+ }
+
+
+ /++
+ The julian day for this SysTime at the given time. For example, prior
+ to noon, 1996-03-31 would be the julian day number 2_450_173, so this
+ function returns 2_450_173, while from noon onward, it the julian day
+ number would be 2_450_174, so this function returns 2_450_174.
+ +/
+ @property long julianDay() const nothrow
+ {
+ immutable jd = dayOfGregorianCal + 1_721_425;
+
+ return hour < 12 ? jd - 1 : jd;
+ }
+
+ unittest
+ {
+ assertPred!"=="(SysTime(DateTime(-4713, 11, 24, 0, 0, 0)).julianDay, -1);
+ assertPred!"=="(SysTime(DateTime(-4713, 11, 24, 12, 0, 0)).julianDay, 0);
+
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 0, 0, 0)).julianDay, 1_721_424);
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 12, 0, 0)).julianDay, 1_721_425);
+
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 0, 0, 0)).julianDay, 1_721_425);
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 12, 0, 0)).julianDay, 1_721_426);
+
+ assertPred!"=="(SysTime(DateTime(1582, 10, 15, 0, 0, 0)).julianDay, 2_299_160);
+ assertPred!"=="(SysTime(DateTime(1582, 10, 15, 12, 0, 0)).julianDay, 2_299_161);
+
+ assertPred!"=="(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).julianDay, 2_400_000);
+ assertPred!"=="(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).julianDay, 2_400_001);
+
+ assertPred!"=="(SysTime(DateTime(1982, 1, 4, 0, 0, 0)).julianDay, 2_444_973);
+ assertPred!"=="(SysTime(DateTime(1982, 1, 4, 12, 0, 0)).julianDay, 2_444_974);
+
+ assertPred!"=="(SysTime(DateTime(1996, 3, 31, 0, 0, 0)).julianDay, 2_450_173);
+ assertPred!"=="(SysTime(DateTime(1996, 3, 31, 12, 0, 0)).julianDay, 2_450_174);
+
+ assertPred!"=="(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).julianDay, 2_455_432);
+ assertPred!"=="(SysTime(DateTime(2010, 8, 24, 12, 0, 0)).julianDay, 2_455_433);
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cst.julianDay));
+ //static assert(__traits(compiles, ist.julianDay));
+ }
+
+
+ /++
+ The modified julian day for any time on this Date (since, the modified
+ julian day changes at midnight).
+ +/
+ @property long modJulianDay() const nothrow
+ {
+ return (dayOfGregorianCal + 1_721_425) - 2_400_001;
+ }
+
+ unittest
+ {
+ assertPred!"=="(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).modJulianDay, 0);
+ assertPred!"=="(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).modJulianDay, 0);
+
+ assertPred!"=="(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).modJulianDay, 55_432);
+ assertPred!"=="(SysTime(DateTime(2010, 8, 24, 12, 0, 0)).modJulianDay, 55_432);
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cst.modJulianDay));
+ //static assert(__traits(compiles, ist.modJulianDay));
+ }
+
+
+ /++
+ Returns a Date equivalent to this SysTime.
+ +/
+ Date opCast(T)() const nothrow
+ if(is(Unqual!T == Date))
+ {
+ return Date(dayOfGregorianCal);
+ }
+
+ unittest
+ {
+ assertPred!"=="(cast(Date)SysTime(Date(1999, 7, 6)), Date(1999, 7, 6));
+ assertPred!"=="(cast(Date)SysTime(Date(2000, 12, 31)), Date(2000, 12, 31));
+ assertPred!"=="(cast(Date)SysTime(Date(2001, 1, 1)), Date(2001, 1, 1));
+
+ assertPred!"=="(cast(Date)SysTime(DateTime(1999, 7, 6, 12, 10, 9)), Date(1999, 7, 6));
+ assertPred!"=="(cast(Date)SysTime(DateTime(2000, 12, 31, 13, 11, 10)), Date(2000, 12, 31));
+ assertPred!"=="(cast(Date)SysTime(DateTime(2001, 1, 1, 14, 12, 11)), Date(2001, 1, 1));
+
+ assertPred!"=="(cast(Date)SysTime(Date(-1999, 7, 6)), Date(-1999, 7, 6));
+ assertPred!"=="(cast(Date)SysTime(Date(-2000, 12, 31)), Date(-2000, 12, 31));
+ assertPred!"=="(cast(Date)SysTime(Date(-2001, 1, 1)), Date(-2001, 1, 1));
+
+ assertPred!"=="(cast(Date)SysTime(DateTime(-1999, 7, 6, 12, 10, 9)), Date(-1999, 7, 6));
+ assertPred!"=="(cast(Date)SysTime(DateTime(-2000, 12, 31, 13, 11, 10)), Date(-2000, 12, 31));
+ assertPred!"=="(cast(Date)SysTime(DateTime(-2001, 1, 1, 14, 12, 11)), Date(-2001, 1, 1));
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cast(Date)cst));
+ //static assert(__traits(compiles, cast(Date)ist));
+ }
+
+
+ /++
+ Returns a DateTime equivalent to this SysTime.
+ +/
+ DateTime opCast(T)() const nothrow
+ if(is(Unqual!T == DateTime))
+ {
+ try
+ {
+ auto hnsecs = adjTime;
+ auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
+
+ if(hnsecs < 0)
+ {
+ hnsecs += convert!("hours", "hnsecs")(24);
+ --days;
+ }
+
+ immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
+ immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
+ immutable second = getUnitsFromHNSecs!"seconds"(hnsecs);
+
+ return DateTime(Date(cast(int)days), TimeOfDay(cast(int)hour, cast(int)minute, cast(int)second));
+ }
+ catch(Exception e)
+ assert(0, "Either DateTime's constructor or TimeOfDay's constructor threw.");
+ }
+
+ unittest
+ {
+ assertPred!"=="(cast(DateTime)SysTime(DateTime(1, 1, 6, 7, 12, 22)), DateTime(1, 1, 6, 7, 12, 22));
+ assertPred!"=="(cast(DateTime)SysTime(DateTime(1, 1, 6, 7, 12, 22), FracSec.from!"msecs"(22)), DateTime(1, 1, 6, 7, 12, 22));
+ assertPred!"=="(cast(DateTime)SysTime(Date(1999, 7, 6)), DateTime(1999, 7, 6, 0, 0, 0));
+ assertPred!"=="(cast(DateTime)SysTime(Date(2000, 12, 31)), DateTime(2000, 12, 31, 0, 0, 0));
+ assertPred!"=="(cast(DateTime)SysTime(Date(2001, 1, 1)), DateTime(2001, 1, 1, 0, 0, 0));
+
+ assertPred!"=="(cast(DateTime)SysTime(DateTime(1999, 7, 6, 12, 10, 9)), DateTime(1999, 7, 6, 12, 10, 9));
+ assertPred!"=="(cast(DateTime)SysTime(DateTime(2000, 12, 31, 13, 11, 10)), DateTime(2000, 12, 31, 13, 11, 10));
+ assertPred!"=="(cast(DateTime)SysTime(DateTime(2001, 1, 1, 14, 12, 11)), DateTime(2001, 1, 1, 14, 12, 11));
+
+ assertPred!"=="(cast(DateTime)SysTime(DateTime(-1, 1, 6, 7, 12, 22)), DateTime(-1, 1, 6, 7, 12, 22));
+ assertPred!"=="(cast(DateTime)SysTime(DateTime(-1, 1, 6, 7, 12, 22), FracSec.from!"msecs"(22)), DateTime(-1, 1, 6, 7, 12, 22));
+ assertPred!"=="(cast(DateTime)SysTime(Date(-1999, 7, 6)), DateTime(-1999, 7, 6, 0, 0, 0));
+ assertPred!"=="(cast(DateTime)SysTime(Date(-2000, 12, 31)), DateTime(-2000, 12, 31, 0, 0, 0));
+ assertPred!"=="(cast(DateTime)SysTime(Date(-2001, 1, 1)), DateTime(-2001, 1, 1, 0, 0, 0));
+
+ assertPred!"=="(cast(DateTime)SysTime(DateTime(-1999, 7, 6, 12, 10, 9)), DateTime(-1999, 7, 6, 12, 10, 9));
+ assertPred!"=="(cast(DateTime)SysTime(DateTime(-2000, 12, 31, 13, 11, 10)), DateTime(-2000, 12, 31, 13, 11, 10));
+ assertPred!"=="(cast(DateTime)SysTime(DateTime(-2001, 1, 1, 14, 12, 11)), DateTime(-2001, 1, 1, 14, 12, 11));
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cast(DateTime)cst));
+ //static assert(__traits(compiles, cast(DateTime)ist));
+ }
+
+
+ /++
+ Returns a TimeOfDay equivalent to this SysTime.
+ +/
+ TimeOfDay opCast(T)() const nothrow
+ if(is(Unqual!T == TimeOfDay))
+ {
+ try
+ {
+ auto hnsecs = adjTime;
+ hnsecs = removeUnitsFromHNSecs!"days"(hnsecs);
+
+ if(hnsecs < 0)
+ hnsecs += convert!("hours", "hnsecs")(24);
+
+ immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
+ immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
+ immutable second = getUnitsFromHNSecs!"seconds"(hnsecs);
+
+ return TimeOfDay(cast(int)hour, cast(int)minute, cast(int)second);
+ }
+ catch(Exception e)
+ assert(0, "TimeOfDay's constructor threw.");
+ }
+
+ unittest
+ {
+ assertPred!"=="(cast(TimeOfDay)SysTime(Date(1999, 7, 6)), TimeOfDay(0, 0, 0));
+ assertPred!"=="(cast(TimeOfDay)SysTime(Date(2000, 12, 31)), TimeOfDay(0, 0, 0));
+ assertPred!"=="(cast(TimeOfDay)SysTime(Date(2001, 1, 1)), TimeOfDay(0, 0, 0));
+
+ assertPred!"=="(cast(TimeOfDay)SysTime(DateTime(1999, 7, 6, 12, 10, 9)), TimeOfDay(12, 10, 9));
+ assertPred!"=="(cast(TimeOfDay)SysTime(DateTime(2000, 12, 31, 13, 11, 10)), TimeOfDay(13, 11, 10));
+ assertPred!"=="(cast(TimeOfDay)SysTime(DateTime(2001, 1, 1, 14, 12, 11)), TimeOfDay(14, 12, 11));
+
+ assertPred!"=="(cast(TimeOfDay)SysTime(Date(-1999, 7, 6)), TimeOfDay(0, 0, 0));
+ assertPred!"=="(cast(TimeOfDay)SysTime(Date(-2000, 12, 31)), TimeOfDay(0, 0, 0));
+ assertPred!"=="(cast(TimeOfDay)SysTime(Date(-2001, 1, 1)), TimeOfDay(0, 0, 0));
+
+ assertPred!"=="(cast(TimeOfDay)SysTime(DateTime(-1999, 7, 6, 12, 10, 9)), TimeOfDay(12, 10, 9));
+ assertPred!"=="(cast(TimeOfDay)SysTime(DateTime(-2000, 12, 31, 13, 11, 10)), TimeOfDay(13, 11, 10));
+ assertPred!"=="(cast(TimeOfDay)SysTime(DateTime(-2001, 1, 1, 14, 12, 11)), TimeOfDay(14, 12, 11));
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cast(TimeOfDay)cst));
+ //static assert(__traits(compiles, cast(TimeOfDay)ist));
+ }
+
+
+ //Temporary hack until bug http://d.puremagic.com/issues/show_bug.cgi?id=4867 is fixed.
+ //This allows assignment from const(SysTime) to SysTime.
+ //It may be a good idea to keep it though, since casting from a type to itself
+ //should be allowed, and it doesn't work without this opCast() since opCast()
+ //has already been defined for other types.
+ SysTime opCast(T)() const pure nothrow
+ if(is(Unqual!T == SysTime))
+ {
+ return SysTime(_stdTime, _timezone.get);
+ }
+
+
+ /++
+ Converts this SysTime to a string with the format YYYYMMDDTHHMMSS.FFFFFFFTZ
+ (where F is fractional seconds and TZ is time zone).
+
+ Note that the number of digits in the fractional seconds varies with the
+ number of fractional seconds. It's a maximum of 7 (which would be hnsecs),
+ but only has as many as are necessary to hold the correct value (so no
+ trailing zeroes), and if there are no fractional seconds, then there is
+ no decimal point.
+
+ If this SysTime's time zone is LocalTime, then TZ is empty. If the time zone
+ is UTC, then it is "Z". Otherwise, it is the offset from UTC (e.g. +1:00 or -7:00).
+ Note that the offset from UTC is $(I not) enough to uniquely identify the time zone.
+
+ Time zone offsets will be in the form +HH:MM or -HH:MM.
+
+ Examples:
+--------------------
+assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOString() ==
+ "20100704T070612");
+assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), FracSec.from!"msecs"(24)).toISOString() ==
+ "19981225T021500.024");
+assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOString() ==
+ "00000105T230959");
+assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), FracSec.from!"hnsecs"(520920)).toISOString() ==
+ "-00040105T000002.052092");
+--------------------
+ +/
+ string toISOString() const nothrow
+ {
+ try
+ {
+ immutable adjustedTime = adjTime;
+ long hnsecs = adjustedTime;
+
+ auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
+
+ if(hnsecs < 0)
+ {
+ hnsecs += convert!("hours", "hnsecs")(24);
+ --days;
+ }
+
+ auto hour = splitUnitsFromHNSecs!"hours"(hnsecs);
+ auto minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
+ auto second = splitUnitsFromHNSecs!"seconds"(hnsecs);
+
+ auto dateTime = DateTime(Date(cast(int)days), TimeOfDay(cast(int)hour, cast(int)minute, cast(int)second));
+ auto fracSecStr = fracSecToISOString(cast(int)hnsecs);
+
+ if(_timezone.get is LocalTime())
+ return dateTime.toISOString() ~ fracSecToISOString(cast(int)hnsecs);
+
+ if(_timezone.get is UTC())
+ return dateTime.toISOString() ~ fracSecToISOString(cast(int)hnsecs) ~ "Z";
+
+ immutable utcOffset = cast(int)convert!("hnsecs", "minutes")(stdTime - adjustedTime);
+
+ return dateTime.toISOString() ~ fracSecToISOString(cast(int)hnsecs) ~ SimpleTimeZone.toISOString(utcOffset);
+ }
+ catch(Exception e)
+ assert(0, "format() threw.");
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(SysTime(DateTime.init, UTC()).toISOString(), "00010101T000000Z");
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1), UTC()).toISOString(), "00010101T000000.0000001Z");
+
+ assertPred!"=="(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOString(), "00091204T000000");
+ assertPred!"=="(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOString(), "00991204T050612");
+ assertPred!"=="(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOString(), "09991204T134459");
+ assertPred!"=="(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOString(), "99990704T235959");
+ assertPred!"=="(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOString(), "+100001020T010101");
+
+ assertPred!"=="(SysTime(DateTime(9, 12, 4, 0, 0, 0), FracSec.from!"msecs"(42)).toISOString(), "00091204T000000.042");
+ assertPred!"=="(SysTime(DateTime(99, 12, 4, 5, 6, 12), FracSec.from!"msecs"(100)).toISOString(), "00991204T050612.1");
+ assertPred!"=="(SysTime(DateTime(999, 12, 4, 13, 44, 59), FracSec.from!"usecs"(45020)).toISOString(), "09991204T134459.04502");
+ assertPred!"=="(SysTime(DateTime(9999, 7, 4, 23, 59, 59), FracSec.from!"hnsecs"(12)).toISOString(), "99990704T235959.0000012");
+ assertPred!"=="(SysTime(DateTime(10000, 10, 20, 1, 1, 1), FracSec.from!"hnsecs"(507890)).toISOString(), "+100001020T010101.050789");
+
+ //Test B.C.
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999), UTC()).toISOString(), "00001231T235959.9999999Z");
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1), UTC()).toISOString(), "00001231T235959.0000001Z");
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOString(), "00001231T235959Z");
+
+ assertPred!"=="(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOString(), "00001204T001204");
+ assertPred!"=="(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOString(), "-00091204T000000");
+ assertPred!"=="(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOString(), "-00991204T050612");
+ assertPred!"=="(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOString(), "-09991204T134459");
+ assertPred!"=="(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOString(), "-99990704T235959");
+ assertPred!"=="(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOString(), "-100001020T010101");
+
+ assertPred!"=="(SysTime(DateTime(0, 12, 4, 0, 0, 0), FracSec.from!"msecs"(7)).toISOString(), "00001204T000000.007");
+ assertPred!"=="(SysTime(DateTime(-9, 12, 4, 0, 0, 0), FracSec.from!"msecs"(42)).toISOString(), "-00091204T000000.042");
+ assertPred!"=="(SysTime(DateTime(-99, 12, 4, 5, 6, 12), FracSec.from!"msecs"(100)).toISOString(), "-00991204T050612.1");
+ assertPred!"=="(SysTime(DateTime(-999, 12, 4, 13, 44, 59), FracSec.from!"usecs"(45020)).toISOString(), "-09991204T134459.04502");
+ assertPred!"=="(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), FracSec.from!"hnsecs"(12)).toISOString(), "-99990704T235959.0000012");
+ assertPred!"=="(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), FracSec.from!"hnsecs"(507890)).toISOString(), "-100001020T010101.050789");
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cast(TimeOfDay)cst));
+ //static assert(__traits(compiles, cast(TimeOfDay)ist));
+
+ //Verify Examples.
+ assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOString() == "20100704T070612");
+ assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), FracSec.from!"msecs"(24)).toISOString() == "19981225T021500.024");
+ assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOString() == "00000105T230959");
+ assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), FracSec.from!"hnsecs"(520920)).toISOString() == "-00040105T000002.052092");
+ }
+
+
+
+ /++
+ Converts this SysTime to a string with the format YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ
+ (where F is fractional seconds and TZ is time zone).
+
+ Note that the number of digits in the fractional seconds varies with the
+ number of fractional seconds. It's a maximum of 7 (which would be hnsecs),
+ but only has as many as are necessary to hold the correct value (so no
+ trailing zeroes), and if there are no fractional seconds, then there is
+ no decimal point.
+
+ If this SysTime's time zone is LocalTime, then TZ is empty. If the time
+ zone is UTC, then it is "Z". Otherwise, it is the offset from UTC
+ (e.g. +1:00 or -7:00). Note that the offset from UTC is $(I not) enough
+ to uniquely identify the time zone.
+
+ Time zone offsets will be in the form +HH:MM or -HH:MM.
+
+ Examples:
+--------------------
+assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOExtendedString() ==
+ "2010-07-04T07:06:12");
+assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), FracSec.from!"msecs"(24)).toISOExtendedString() ==
+ "1998-12-25T02:15:00.024");
+assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOExtendedString() ==
+ "0000-01-05T23:09:59");
+assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), FracSec.from!"hnsecs"(520920)).toISOExtendedString() ==
+ "-0004-01-05T00:00:02.052092");
+--------------------
+ +/
+ string toISOExtendedString() const nothrow
+ {
+ try
+ {
+ immutable adjustedTime = adjTime;
+ long hnsecs = adjustedTime;
+
+ auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
+
+ if(hnsecs < 0)
+ {
+ hnsecs += convert!("hours", "hnsecs")(24);
+ --days;
+ }
+
+ auto hour = splitUnitsFromHNSecs!"hours"(hnsecs);
+ auto minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
+ auto second = splitUnitsFromHNSecs!"seconds"(hnsecs);
+
+ auto dateTime = DateTime(Date(cast(int)days), TimeOfDay(cast(int)hour, cast(int)minute, cast(int)second));
+ auto fracSecStr = fracSecToISOString(cast(int)hnsecs);
+
+ if(_timezone.get is LocalTime())
+ return dateTime.toISOExtendedString() ~ fracSecToISOString(cast(int)hnsecs);
+
+ if(_timezone.get is UTC())
+ return dateTime.toISOExtendedString() ~ fracSecToISOString(cast(int)hnsecs) ~ "Z";
+
+ immutable utcOffset = cast(int)convert!("hnsecs", "minutes")(stdTime - adjustedTime);
+
+ return dateTime.toISOExtendedString() ~ fracSecToISOString(cast(int)hnsecs) ~ SimpleTimeZone.toISOString(utcOffset);
+ }
+ catch(Exception e)
+ assert(0, "format() threw.");
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(SysTime(DateTime.init, UTC()).toISOExtendedString(), "0001-01-01T00:00:00Z");
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1), UTC()).toISOExtendedString(), "0001-01-01T00:00:00.0000001Z");
+
+ assertPred!"=="(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOExtendedString(), "0009-12-04T00:00:00");
+ assertPred!"=="(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOExtendedString(), "0099-12-04T05:06:12");
+ assertPred!"=="(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOExtendedString(), "0999-12-04T13:44:59");
+ assertPred!"=="(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOExtendedString(), "9999-07-04T23:59:59");
+ assertPred!"=="(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOExtendedString(), "+10000-10-20T01:01:01");
+
+ assertPred!"=="(SysTime(DateTime(9, 12, 4, 0, 0, 0), FracSec.from!"msecs"(42)).toISOExtendedString(), "0009-12-04T00:00:00.042");
+ assertPred!"=="(SysTime(DateTime(99, 12, 4, 5, 6, 12), FracSec.from!"msecs"(100)).toISOExtendedString(), "0099-12-04T05:06:12.1");
+ assertPred!"=="(SysTime(DateTime(999, 12, 4, 13, 44, 59), FracSec.from!"usecs"(45020)).toISOExtendedString(), "0999-12-04T13:44:59.04502");
+ assertPred!"=="(SysTime(DateTime(9999, 7, 4, 23, 59, 59), FracSec.from!"hnsecs"(12)).toISOExtendedString(), "9999-07-04T23:59:59.0000012");
+ assertPred!"=="(SysTime(DateTime(10000, 10, 20, 1, 1, 1), FracSec.from!"hnsecs"(507890)).toISOExtendedString(), "+10000-10-20T01:01:01.050789");
+
+ //Test B.C.
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999), UTC()).toISOExtendedString(), "0000-12-31T23:59:59.9999999Z");
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1), UTC()).toISOExtendedString(), "0000-12-31T23:59:59.0000001Z");
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOExtendedString(), "0000-12-31T23:59:59Z");
+
+ assertPred!"=="(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOExtendedString(), "0000-12-04T00:12:04");
+ assertPred!"=="(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOExtendedString(), "-0009-12-04T00:00:00");
+ assertPred!"=="(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOExtendedString(), "-0099-12-04T05:06:12");
+ assertPred!"=="(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOExtendedString(), "-0999-12-04T13:44:59");
+ assertPred!"=="(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOExtendedString(), "-9999-07-04T23:59:59");
+ assertPred!"=="(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOExtendedString(), "-10000-10-20T01:01:01");
+
+ assertPred!"=="(SysTime(DateTime(0, 12, 4, 0, 0, 0), FracSec.from!"msecs"(7)).toISOExtendedString(), "0000-12-04T00:00:00.007");
+ assertPred!"=="(SysTime(DateTime(-9, 12, 4, 0, 0, 0), FracSec.from!"msecs"(42)).toISOExtendedString(), "-0009-12-04T00:00:00.042");
+ assertPred!"=="(SysTime(DateTime(-99, 12, 4, 5, 6, 12), FracSec.from!"msecs"(100)).toISOExtendedString(), "-0099-12-04T05:06:12.1");
+ assertPred!"=="(SysTime(DateTime(-999, 12, 4, 13, 44, 59), FracSec.from!"usecs"(45020)).toISOExtendedString(), "-0999-12-04T13:44:59.04502");
+ assertPred!"=="(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), FracSec.from!"hnsecs"(12)).toISOExtendedString(), "-9999-07-04T23:59:59.0000012");
+ assertPred!"=="(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), FracSec.from!"hnsecs"(507890)).toISOExtendedString(), "-10000-10-20T01:01:01.050789");
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cast(TimeOfDay)cst));
+ //static assert(__traits(compiles, cast(TimeOfDay)ist));
+
+ //Verify Examples.
+ assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOExtendedString() == "2010-07-04T07:06:12");
+ assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), FracSec.from!"msecs"(24)).toISOExtendedString() == "1998-12-25T02:15:00.024");
+ assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOExtendedString() == "0000-01-05T23:09:59");
+ assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), FracSec.from!"hnsecs"(520920)).toISOExtendedString() == "-0004-01-05T00:00:02.052092");
+ }
+
+ /++
+ Converts this SysTime to a string with the format YYYY-Mon-DD HH:MM:SS.FFFFFFFTZ
+ (where F is fractional seconds and TZ is time zone).
+
+ Note that the number of digits in the fractional seconds varies with the
+ number of fractional seconds. It's a maximum of 7 (which would be hnsecs),
+ but only has as many as are necessary to hold the correct value (so no
+ trailing zeroes), and if there are no fractional seconds, then there is
+ no decimal point.
+
+ If this SysTime's time zone is LocalTime, then TZ is empty. If the time
+ zone is UTC, then it is "Z". Otherwise, it is the offset from UTC
+ (e.g. +1:00 or -7:00). Note that the offset from UTC is $(I not) enough
+ to uniquely identify the time zone.
+
+ Time zone offsets will be in the form +HH:MM or -HH:MM.
+
+ Examples:
+--------------------
+assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toSimpleString() ==
+ "2010-Jul-04 07:06:12");
+assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), FracSec.from!"msecs"(24)).toSimpleString() ==
+ "1998-Dec-25 02:15:00.024");
+assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toSimpleString() ==
+ "0000-Jan-05 23:09:59");
+assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), FracSec.from!"hnsecs"(520920)).toSimpleString() ==
+ "-0004-Jan-05 00:00:02.052092");
+--------------------
+ +/
+ string toSimpleString() const nothrow
+ {
+ try
+ {
+ immutable adjustedTime = adjTime;
+ long hnsecs = adjustedTime;
+
+ auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
+
+ if(hnsecs < 0)
+ {
+ hnsecs += convert!("hours", "hnsecs")(24);
+ --days;
+ }
+
+ auto hour = splitUnitsFromHNSecs!"hours"(hnsecs);
+ auto minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
+ auto second = splitUnitsFromHNSecs!"seconds"(hnsecs);
+
+ auto dateTime = DateTime(Date(cast(int)days), TimeOfDay(cast(int)hour, cast(int)minute, cast(int)second));
+ auto fracSecStr = fracSecToISOString(cast(int)hnsecs);
+
+ if(_timezone.get is LocalTime())
+ return dateTime.toSimpleString() ~ fracSecToISOString(cast(int)hnsecs);
+
+ if(_timezone.get is UTC())
+ return dateTime.toSimpleString() ~ fracSecToISOString(cast(int)hnsecs) ~ "Z";
+
+ immutable utcOffset = cast(int)convert!("hnsecs", "minutes")(stdTime - adjustedTime);
+
+ return dateTime.toSimpleString() ~ fracSecToISOString(cast(int)hnsecs) ~ SimpleTimeZone.toISOString(utcOffset);
+ }
+ catch(Exception e)
+ assert(0, "format() threw.");
+ }
+
+ unittest
+ {
+ //Test A.D.
+ assertPred!"=="(SysTime(DateTime.init, UTC()).toString(), "0001-Jan-01 00:00:00Z");
+ assertPred!"=="(SysTime(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"hnsecs"(1), UTC()).toString(), "0001-Jan-01 00:00:00.0000001Z");
+
+ assertPred!"=="(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toSimpleString(), "0009-Dec-04 00:00:00");
+ assertPred!"=="(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toSimpleString(), "0099-Dec-04 05:06:12");
+ assertPred!"=="(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toSimpleString(), "0999-Dec-04 13:44:59");
+ assertPred!"=="(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toSimpleString(), "9999-Jul-04 23:59:59");
+ assertPred!"=="(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toSimpleString(), "+10000-Oct-20 01:01:01");
+
+ assertPred!"=="(SysTime(DateTime(9, 12, 4, 0, 0, 0), FracSec.from!"msecs"(42)).toSimpleString(), "0009-Dec-04 00:00:00.042");
+ assertPred!"=="(SysTime(DateTime(99, 12, 4, 5, 6, 12), FracSec.from!"msecs"(100)).toSimpleString(), "0099-Dec-04 05:06:12.1");
+ assertPred!"=="(SysTime(DateTime(999, 12, 4, 13, 44, 59), FracSec.from!"usecs"(45020)).toSimpleString(), "0999-Dec-04 13:44:59.04502");
+ assertPred!"=="(SysTime(DateTime(9999, 7, 4, 23, 59, 59), FracSec.from!"hnsecs"(12)).toSimpleString(), "9999-Jul-04 23:59:59.0000012");
+ assertPred!"=="(SysTime(DateTime(10000, 10, 20, 1, 1, 1), FracSec.from!"hnsecs"(507890)).toSimpleString(), "+10000-Oct-20 01:01:01.050789");
+
+ //Test B.C.
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999), UTC()).toSimpleString(), "0000-Dec-31 23:59:59.9999999Z");
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1), UTC()).toSimpleString(), "0000-Dec-31 23:59:59.0000001Z");
+ assertPred!"=="(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toSimpleString(), "0000-Dec-31 23:59:59Z");
+
+ assertPred!"=="(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toSimpleString(), "0000-Dec-04 00:12:04");
+ assertPred!"=="(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toSimpleString(), "-0009-Dec-04 00:00:00");
+ assertPred!"=="(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toSimpleString(), "-0099-Dec-04 05:06:12");
+ assertPred!"=="(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toSimpleString(), "-0999-Dec-04 13:44:59");
+ assertPred!"=="(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toSimpleString(), "-9999-Jul-04 23:59:59");
+ assertPred!"=="(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toSimpleString(), "-10000-Oct-20 01:01:01");
+
+ assertPred!"=="(SysTime(DateTime(0, 12, 4, 0, 0, 0), FracSec.from!"msecs"(7)).toSimpleString(), "0000-Dec-04 00:00:00.007");
+ assertPred!"=="(SysTime(DateTime(-9, 12, 4, 0, 0, 0), FracSec.from!"msecs"(42)).toSimpleString(), "-0009-Dec-04 00:00:00.042");
+ assertPred!"=="(SysTime(DateTime(-99, 12, 4, 5, 6, 12), FracSec.from!"msecs"(100)).toSimpleString(), "-0099-Dec-04 05:06:12.1");
+ assertPred!"=="(SysTime(DateTime(-999, 12, 4, 13, 44, 59), FracSec.from!"usecs"(45020)).toSimpleString(), "-0999-Dec-04 13:44:59.04502");
+ assertPred!"=="(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), FracSec.from!"hnsecs"(12)).toSimpleString(), "-9999-Jul-04 23:59:59.0000012");
+ assertPred!"=="(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), FracSec.from!"hnsecs"(507890)).toSimpleString(), "-10000-Oct-20 01:01:01.050789");
+
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, cast(TimeOfDay)cst));
+ //static assert(__traits(compiles, cast(TimeOfDay)ist));
+
+ //Verify Examples.
+ assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toSimpleString() == "2010-Jul-04 07:06:12");
+ assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), FracSec.from!"msecs"(24)).toSimpleString() == "1998-Dec-25 02:15:00.024");
+ assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toSimpleString() == "0000-Jan-05 23:09:59");
+ assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), FracSec.from!"hnsecs"(520920)).toSimpleString() == "-0004-Jan-05 00:00:02.052092");
+ }
+
+
+ /+
+ Converts this SysTime to a string.
+ +/
+ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't
+ //have versions of toString() with extra modifiers, so we define one version
+ //with modifiers and one without.
+ string toString()
+ {
+ return toSimpleString();
+ }
+
+ /++
+ Converts this SysTime to a string.
+ +/
+ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't
+ //have versions of toString() with extra modifiers, so we define one version
+ //with modifiers and one without.
+ string toString() const nothrow
+ {
+ return toSimpleString();
+ }
+
+ unittest
+ {
+ auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
+ static assert(__traits(compiles, st.toString()));
+ static assert(__traits(compiles, cst.toString()));
+ //static assert(__traits(compiles, ist.toString()));
+ }
+
+
+ /++
+ Creates a SysTime from a string with the format YYYYMMDDTHHMMSS.FFFFFFFTZ
+ (where F is fractional seconds is time zone). Whitespace is stripped from
+ the given string.
+
+ The exact format is exactly as described in toISOString() except that
+ trailing zeroes are permitted - including having fractional seconds with
+ all zeroes. However, a decimal point with nothing following it is invalid.
+
+ If there is no time zone in the string, then LocalTime is used. If the
+ time zone is "Z", then UTC is used. Otherwise, a SimpleTimeZone which
+ corresponds to the given offset from UTC is used. If you wish the
+ returned SysTime to be a particular time zone, then pass in that time
+ zone and the SysTime to be returned will be converted to that time zone
+ (though it will still be read in as whatever time zone is in its string).
+
+ The accepted formats for time zone offsets are +H, -H, +HH, -HH, +H:MM,
+ -H:MM, +HH:MM, and -HH:MM.
+
+ Params:
+ isoString = A string formatted in the ISO format for dates and times.
+ tz = The time zone to convert the given time to (no conversion
+ occurs if null).
+
+ Throws:
+ DateTimeException if the given string is not in the ISO format or if
+ the resulting SysTime would not be valid.
+
+ Examples:
+--------------------
+assert(SysTime.fromISOString("20100704T070612") ==
+ SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
+assert(SysTime.fromISOString("19981225T021500.007") ==
+ SysTime(DateTime(1998, 12, 25, 2, 15, 0), FracSec.from!"msecs"(7)));
+assert(SysTime.fromISOString("00000105T230959.00002") ==
+ SysTime(DateTime(0, 1, 5, 23, 9, 59), FracSec.from!"usecs"(20)));
+assert(SysTime.fromISOString("-00040105T000002") ==
+ SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
+assert(SysTime.fromISOString(" 20100704T070612 ") ==
+ SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
+
+assert(SysTime.fromISOString("20100704T070612Z") ==
+ SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
+assert(SysTime.fromISOString("20100704T070612-8:00") ==
+ SysTime(DateTime(2010, 7, 4, 7, 6, 12), new SimpleTimeZone(-480)));
+assert(SysTime.fromISOString("20100704T070612+8:00") ==
+ SysTime(DateTime(2010, 7, 3, 7, 6, 12), new SimpleTimeZone(480)));
+--------------------
+ +/
+ static SysTime fromISOString(S)(in S isoString, immutable TimeZone tz = null)
+ if(isSomeString!S)
+ {
+ auto dstr = to!dstring(strip(isoString));
+ immutable skipFirst = dstr.startsWith("+", "-") != 0;
+
+ auto found = (skipFirst ? dstr[1..$] : dstr).find(".", "Z", "+", "-");
+ auto dateTimeStr = dstr[0 .. $ - found[0].length];
+
+ dstring fracSecStr;
+ dstring zoneStr;
+
+ if(found[1] != 0)
+ {
+ if(found[1] == 1)
+ {
+ auto foundTZ = found[0].find("Z", "+", "-");
+
+ if(foundTZ[1] != 0)
+ {
+ fracSecStr = found[0][0 .. $ - foundTZ[0].length];
+ zoneStr = foundTZ[0];
+ }
+ else
+ fracSecStr = found[0];
+ }
+ else
+ zoneStr = found[0];
+ }
+
+ try
+ {
+ auto dateTime = DateTime.fromISOString(dateTimeStr);
+ auto fracSec = fracSecFromISOString(fracSecStr);
+ DTRebindable!(immutable TimeZone) parsedZone;
+
+ if(zoneStr.empty)
+ parsedZone = LocalTime();
+ else if(zoneStr == "Z")
+ parsedZone = UTC();
+ else
+ parsedZone = SimpleTimeZone.fromISOString(zoneStr);
+
+ auto retval = SysTime(dateTime, fracSec, parsedZone.get);
+
+ if(tz !is null)
+ retval.timezone = tz;
+
+ return retval;
+ }
+ catch(DateTimeException dte)
+ throw new DateTimeException(format("Invalid ISO String: %s", isoString));
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException(SysTime.fromISOString(""));
+ assertThrown!DateTimeException(SysTime.fromISOString("20100704000000"));
+ assertThrown!DateTimeException(SysTime.fromISOString("20100704 000000"));
+ assertThrown!DateTimeException(SysTime.fromISOString("20100704t000000"));
+ assertThrown!DateTimeException(SysTime.fromISOString("20100704T000000."));
+ assertThrown!DateTimeException(SysTime.fromISOString("20100704T000000.A"));
+ assertThrown!DateTimeException(SysTime.fromISOString("20100704T000000.Z"));
+ assertThrown!DateTimeException(SysTime.fromISOString("20100704T000000.00000000"));
+ assertThrown!DateTimeException(SysTime.fromISOString("20100704T000000.00000000"));
+ assertThrown!DateTimeException(SysTime.fromISOString("20100704T000000+"));
+ assertThrown!DateTimeException(SysTime.fromISOString("20100704T000000-"));
+ assertThrown!DateTimeException(SysTime.fromISOString("20100704T000000:"));
+ assertThrown!DateTimeException(SysTime.fromISOString("20100704T000000-:"));
+ assertThrown!DateTimeException(SysTime.fromISOString("20100704T000000+:"));
+ assertThrown!DateTimeException(SysTime.fromISOString("20100704T000000-1:"));
+ assertThrown!DateTimeException(SysTime.fromISOString("20100704T000000+1:"));
+ assertThrown!DateTimeException(SysTime.fromISOString("20100704T000000+1:0"));
+ assertThrown!DateTimeException(SysTime.fromISOString("20100704T000000-24.00"));
+ assertThrown!DateTimeException(SysTime.fromISOString("20100704T000000+24.00"));
+
+ assertThrown!DateTimeException(SysTime.fromISOString("2010-07-0400:00:00"));
+ assertThrown!DateTimeException(SysTime.fromISOString("2010-07-04 00:00:00"));
+ assertThrown!DateTimeException(SysTime.fromISOString("2010-07-04t00:00:00"));
+ assertThrown!DateTimeException(SysTime.fromISOString("2010-07-04T00:00:00."));
+
+ assertThrown!DateTimeException(SysTime.fromISOString("2010-Jul-0400:00:00"));
+ assertThrown!DateTimeException(SysTime.fromISOString("2010-Jul-04 00:00:00"));
+ assertThrown!DateTimeException(SysTime.fromISOString("2010-Jul-04t00:00:00"));
+ assertThrown!DateTimeException(SysTime.fromISOString("2010-Jul-04T00:00:00"));
+ assertThrown!DateTimeException(SysTime.fromISOString("2010-Jul-04 00:00:00."));
+
+ assertThrown!DateTimeException(SysTime.fromISOString("2010-12-22T172201"));
+ assertThrown!DateTimeException(SysTime.fromISOString("2010-Dec-22 17:22:01"));
+
+ assertPred!"=="(SysTime.fromISOString("20101222T172201"), SysTime(DateTime(2010, 12, 22, 17, 22, 01)));
+ assertPred!"=="(SysTime.fromISOString("19990706T123033"), SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
+ assertPred!"=="(SysTime.fromISOString("-19990706T123033"), SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
+ assertPred!"=="(SysTime.fromISOString("+019990706T123033"), SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
+ assertPred!"=="(SysTime.fromISOString("19990706T123033 "), SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
+ assertPred!"=="(SysTime.fromISOString(" 19990706T123033"), SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
+ assertPred!"=="(SysTime.fromISOString(" 19990706T123033 "), SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
+
+ assertPred!"=="(SysTime.fromISOString("19070707T121212.0"), SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
+ assertPred!"=="(SysTime.fromISOString("19070707T121212.0000000"), SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
+ assertPred!"=="(SysTime.fromISOString("19070707T121212.0000001"), SysTime(DateTime(1907, 07, 07, 12, 12, 12), FracSec.from!"hnsecs"(1)));
+ assertPred!"=="(SysTime.fromISOString("19070707T121212.000001"), SysTime(DateTime(1907, 07, 07, 12, 12, 12), FracSec.from!"usecs"(1)));
+ assertPred!"=="(SysTime.fromISOString("19070707T121212.0000010"), SysTime(DateTime(1907, 07, 07, 12, 12, 12), FracSec.from!"usecs"(1)));
+ assertPred!"=="(SysTime.fromISOString("19070707T121212.001"), SysTime(DateTime(1907, 07, 07, 12, 12, 12), FracSec.from!"msecs"(1)));
+ assertPred!"=="(SysTime.fromISOString("19070707T121212.0010000"), SysTime(DateTime(1907, 07, 07, 12, 12, 12), FracSec.from!"msecs"(1)));
+
+ assertPred!"=="(SysTime.fromISOString("20101222T172201Z"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC()));
+ assertPred!"=="(SysTime.fromISOString("20101222T172201-1:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(-60)));
+ assertPred!"=="(SysTime.fromISOString("20101222T172201-1"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(-60)));
+ assertPred!"=="(SysTime.fromISOString("20101222T172201-1:30"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(-90)));
+ assertPred!"=="(SysTime.fromISOString("20101222T172201-8:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(-480)));
+ assertPred!"=="(SysTime.fromISOString("20101222T172201+1:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(60)));
+ assertPred!"=="(SysTime.fromISOString("20101222T172201+1"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(60)));
+ assertPred!"=="(SysTime.fromISOString("20101222T172201+1:30"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(90)));
+ assertPred!"=="(SysTime.fromISOString("20101222T172201+8:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(480)));
+
+ assertPred!"=="(SysTime.fromISOString("20101103T065106.57159Z"), SysTime(DateTime(2010, 11, 3, 6, 51, 6), FracSec.from!"hnsecs"(5715900), UTC()));
+
+ assertPred!"=="(SysTime.fromISOString("20101222T172201.23412Z"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(2_341_200), UTC()));
+ assertPred!"=="(SysTime.fromISOString("20101222T172201.23112-1:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(2_311_200), new SimpleTimeZone(-60)));
+ assertPred!"=="(SysTime.fromISOString("20101222T172201.45-1"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(4_500_000), new SimpleTimeZone(-60)));
+ assertPred!"=="(SysTime.fromISOString("20101222T172201.1-1:30"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(1_000_000), new SimpleTimeZone(-90)));
+ assertPred!"=="(SysTime.fromISOString("20101222T172201.55-8:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(5_500_000), new SimpleTimeZone(-480)));
+ assertPred!"=="(SysTime.fromISOString("20101222T172201.1234567+1:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(1_234_567), new SimpleTimeZone(60)));
+ assertPred!"=="(SysTime.fromISOString("20101222T172201.0+1"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(0), new SimpleTimeZone(60)));
+ assertPred!"=="(SysTime.fromISOString("20101222T172201.0000000+1:30"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(0), new SimpleTimeZone(90)));
+ assertPred!"=="(SysTime.fromISOString("20101222T172201.45+8:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(4_500_000), new SimpleTimeZone(480)));
+
+ //Verify Examples.
+ assert(SysTime.fromISOString("20100704T070612") == SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
+ assert(SysTime.fromISOString("19981225T021500.007") == SysTime(DateTime(1998, 12, 25, 2, 15, 0), FracSec.from!"msecs"(7)));
+ assert(SysTime.fromISOString("00000105T230959.00002") == SysTime(DateTime(0, 1, 5, 23, 9, 59), FracSec.from!"usecs"(20)));
+ assert(SysTime.fromISOString("-00040105T000002") == SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
+ assert(SysTime.fromISOString(" 20100704T070612 ") == SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
+
+ assert(SysTime.fromISOString("20100704T070612Z") == SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
+ assert(SysTime.fromISOString("20100704T070612-8:00") == SysTime(DateTime(2010, 7, 4, 7, 6, 12), new SimpleTimeZone(-480)));
+ assert(SysTime.fromISOString("20100704T070612+8:00") == SysTime(DateTime(2010, 7, 4, 7, 6, 12), new SimpleTimeZone(480)));
+ }
+
+
+ /++
+ Creates a SysTime from a string with the format YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ
+ (where F is fractional seconds is time zone). Whitespace is stripped from the
+ given string.
+
+ The exact format is exactly as described in toISOExtendedString() except
+ that trailing zeroes are permitted - including having fractional seconds
+ with all zeroes. However, a decimal point with nothing following it is
+ invalid.
+
+ If there is no time zone in the string, then LocalTime is used. If the
+ time zone is "Z", then UTC is used. Otherwise, a SimpleTimeZone which
+ corresponds to the given offset from UTC is used. If you wish the
+ returned SysTime to be a particular time zone, then pass in that time
+ zone and the SysTime to be returned will be converted to that time zone
+ (though it will still be read in as whatever time zone is in its string).
+
+ The accepted formats for time zone offsets are +H, -H, +HH, -HH, +H:MM,
+ -H:MM, +HH:MM, and -HH:MM.
+
+ Params:
+ isoString = A string formatted in the ISO Extended format for dates
+ and times.
+ tz = The time zone to convert the given time to (no conversion
+ occurs if null).
+
+ Throws:
+ DateTimeException if the given string is not in the ISO format or if
+ the resulting SysTime would not be valid.
+
+ Examples:
+--------------------
+assert(SysTime.fromISOExtendedString("2010-07-04T07:06:12") ==
+ SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
+assert(SysTime.fromISOExtendedString("1998-12-25T02:15:00.007") ==
+ SysTime(DateTime(1998, 12, 25, 2, 15, 0), FracSec.from!"msecs"(7)));
+assert(SysTime.fromISOExtendedString("0000-01-05T23:09:59.00002") ==
+ SysTime(DateTime(0, 1, 5, 23, 9, 59), FracSec.from!"usecs"(20)));
+assert(SysTime.fromISOExtendedString("-0004-01-05T00:00:02") ==
+ SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
+assert(SysTime.fromISOExtendedString(" 2010-07-04T07:06:12 ") ==
+ SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
+
+assert(SysTime.fromISOExtendedString("2010-07-04T07:06:12Z") ==
+ SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
+assert(SysTime.fromISOExtendedString("2010-07-04T07:06:12-8:00") ==
+ SysTime(DateTime(2010, 7, 4, 7, 6, 12), new SimpleTimeZone(-480)));
+assert(SysTime.fromISOExtendedString("2010-07-04T07:06:12+8:00") ==
+ SysTime(DateTime(2010, 7, 4, 7, 6, 12), new SimpleTimeZone(480)));
+--------------------
+ +/
+ static SysTime fromISOExtendedString(S)(in S isoExtString, immutable TimeZone tz = null)
+ if(isSomeString!(S))
+ {
+ auto dstr = to!dstring(strip(isoExtString));
+
+ auto tIndex = dstr.indexOf("T");
+ enforce(tIndex != -1, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
+
+ auto found = dstr[tIndex + 1 .. $].find(".", "Z", "+", "-");
+ auto dateTimeStr = dstr[0 .. $ - found[0].length];
+
+ dstring fracSecStr;
+ dstring zoneStr;
+
+ if(found[1] != 0)
+ {
+ if(found[1] == 1)
+ {
+ auto foundTZ = found[0].find("Z", "+", "-");
+
+ if(foundTZ[1] != 0)
+ {
+ fracSecStr = found[0][0 .. $ - foundTZ[0].length];
+ zoneStr = foundTZ[0];
+ }
+ else
+ fracSecStr = found[0];
+ }
+ else
+ zoneStr = found[0];
+ }
+
+ try
+ {
+ auto dateTime = DateTime.fromISOExtendedString(dateTimeStr);
+ auto fracSec = fracSecFromISOString(fracSecStr);
+ DTRebindable!(immutable TimeZone) parsedZone;
+
+ if(zoneStr.empty)
+ parsedZone = LocalTime();
+ else if(zoneStr == "Z")
+ parsedZone = UTC();
+ else
+ parsedZone = SimpleTimeZone.fromISOString(zoneStr);
+
+ auto retval = SysTime(dateTime, fracSec, parsedZone.get);
+
+ if(tz !is null)
+ retval.timezone = tz;
+
+ return retval;
+ }
+ catch(DateTimeException dte)
+ throw new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString));
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString(""));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("20100704000000"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("20100704 000000"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("20100704t000000"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("20100704T000000."));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("20100704T000000.0"));
+
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-07:0400:00:00"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-07-04 00:00:00"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-07-04 00:00:00"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-07-04t00:00:00"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-07-04T00:00:00."));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-07-04T00:00:00.A"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-07-04T00:00:00.Z"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-07-04T00:00:00.00000000"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-07-04T00:00:00.00000000"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-07-04T00:00:00+"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-07-04T00:00:00-"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-07-04T00:00:00:"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-07-04T00:00:00-:"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-07-04T00:00:00+:"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-07-04T00:00:00-1:"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-07-04T00:00:00+1:"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-07-04T00:00:00+1:0"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-07-04T00:00:00-24.00"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-07-04T00:00:00+24.00"));
+
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-Jul-0400:00:00"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-Jul-04t00:00:00"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-Jul-04 00:00:00."));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-Jul-04 00:00:00.0"));
+
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("20101222T172201"));
+ assertThrown!DateTimeException(SysTime.fromISOExtendedString("2010-Dec-22 17:22:01"));
+
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-12-22T17:22:01"), SysTime(DateTime(2010, 12, 22, 17, 22, 01)));
+ assertPred!"=="(SysTime.fromISOExtendedString("1999-07-06T12:30:33"), SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
+ assertPred!"=="(SysTime.fromISOExtendedString("-1999-07-06T12:30:33"), SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
+ assertPred!"=="(SysTime.fromISOExtendedString("+01999-07-06T12:30:33"), SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
+ assertPred!"=="(SysTime.fromISOExtendedString("1999-07-06T12:30:33 "), SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
+ assertPred!"=="(SysTime.fromISOExtendedString(" 1999-07-06T12:30:33"), SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
+ assertPred!"=="(SysTime.fromISOExtendedString(" 1999-07-06T12:30:33 "), SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
+
+ assertPred!"=="(SysTime.fromISOExtendedString("1907-07-07T12:12:12.0"), SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
+ assertPred!"=="(SysTime.fromISOExtendedString("1907-07-07T12:12:12.0000000"), SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
+ assertPred!"=="(SysTime.fromISOExtendedString("1907-07-07T12:12:12.0000001"), SysTime(DateTime(1907, 07, 07, 12, 12, 12), FracSec.from!"hnsecs"(1)));
+ assertPred!"=="(SysTime.fromISOExtendedString("1907-07-07T12:12:12.000001"), SysTime(DateTime(1907, 07, 07, 12, 12, 12), FracSec.from!"usecs"(1)));
+ assertPred!"=="(SysTime.fromISOExtendedString("1907-07-07T12:12:12.0000010"), SysTime(DateTime(1907, 07, 07, 12, 12, 12), FracSec.from!"usecs"(1)));
+ assertPred!"=="(SysTime.fromISOExtendedString("1907-07-07T12:12:12.001"), SysTime(DateTime(1907, 07, 07, 12, 12, 12), FracSec.from!"msecs"(1)));
+ assertPred!"=="(SysTime.fromISOExtendedString("1907-07-07T12:12:12.0010000"), SysTime(DateTime(1907, 07, 07, 12, 12, 12), FracSec.from!"msecs"(1)));
+
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-12-22T17:22:01Z"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC()));
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-12-22T17:22:01-1:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(-60)));
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-12-22T17:22:01-1"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(-60)));
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-12-22T17:22:01-1:30"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(-90)));
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-12-22T17:22:01-8:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(-480)));
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-12-22T17:22:01+1:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(60)));
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-12-22T17:22:01+1"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(60)));
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-12-22T17:22:01+1:30"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(90)));
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-12-22T17:22:01+8:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(480)));
+
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-11-03T06:51:06.57159Z"), SysTime(DateTime(2010, 11, 3, 6, 51, 6), FracSec.from!"hnsecs"(5715900), UTC()));
+
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-12-22T17:22:01.23412Z"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(2_341_200), UTC()));
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-12-22T17:22:01.23112-1:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(2_311_200), new SimpleTimeZone(-60)));
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-12-22T17:22:01.45-1"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(4_500_000), new SimpleTimeZone(-60)));
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-12-22T17:22:01.1-1:30"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(1_000_000), new SimpleTimeZone(-90)));
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-12-22T17:22:01.55-8:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(5_500_000), new SimpleTimeZone(-480)));
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-12-22T17:22:01.1234567+1:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(1_234_567), new SimpleTimeZone(60)));
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-12-22T17:22:01.0+1"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(0), new SimpleTimeZone(60)));
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-12-22T17:22:01.0000000+1:30"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(0), new SimpleTimeZone(90)));
+ assertPred!"=="(SysTime.fromISOExtendedString("2010-12-22T17:22:01.45+8:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(4_500_000), new SimpleTimeZone(480)));
+
+ //Verify Examples.
+ assert(SysTime.fromISOExtendedString("2010-07-04T07:06:12") == SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
+ assert(SysTime.fromISOExtendedString("1998-12-25T02:15:00.007") == SysTime(DateTime(1998, 12, 25, 2, 15, 0), FracSec.from!"msecs"(7)));
+ assert(SysTime.fromISOExtendedString("0000-01-05T23:09:59.00002") == SysTime(DateTime(0, 1, 5, 23, 9, 59), FracSec.from!"usecs"(20)));
+ assert(SysTime.fromISOExtendedString("-0004-01-05T00:00:02") == SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
+ assert(SysTime.fromISOExtendedString(" 2010-07-04T07:06:12 ") == SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
+
+ assert(SysTime.fromISOExtendedString("2010-07-04T07:06:12Z") == SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
+ assert(SysTime.fromISOExtendedString("2010-07-04T07:06:12-8:00") == SysTime(DateTime(2010, 7, 4, 7, 6, 12), new SimpleTimeZone(-480)));
+ assert(SysTime.fromISOExtendedString("2010-07-04T07:06:12+8:00") == SysTime(DateTime(2010, 7, 4, 7, 6, 12), new SimpleTimeZone(480)));
+ }
+
+
+ /++
+ Creates a SysTime from a string with the format YYYY-MM-DD HH:MM:SS.FFFFFFFTZ
+ (where F is fractional seconds is time zone). Whitespace is stripped from the
+ given string.
+
+ The exact format is exactly as described in toSimpleString() except that
+ trailing zeroes are permitted - including having fractional seconds with
+ all zeroes. However, a decimal point with nothing following it is invalid.
+
+ If there is no time zone in the string, then LocalTime is used. If the
+ time zone is "Z", then UTC is used. Otherwise, a SimpleTimeZone which
+ corresponds to the given offset from UTC is used. If you wish the
+ returned SysTime to be a particular time zone, then pass in that time
+ zone and the SysTime to be returned will be converted to that time zone
+ (though it will still be read in as whatever time zone is in its string).
+
+ The accepted formats for time zone offsets are +H, -H, +HH, -HH, +H:MM,
+ -H:MM, +HH:MM, and -HH:MM.
+
+
+ Params:
+ simpleString = A string formatted in the way that toSimpleString()
+ formats dates and times.
+ tz = The time zone to convert the given time to (no
+ conversion occurs if null).
+
+ Throws:
+ DateTimeException if the given string is not in the ISO format or if
+ the resulting SysTime would not be valid.
+
+ Examples:
+--------------------
+assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12") ==
+ SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
+assert(SysTime.fromSimpleString("1998-Dec-25 02:15:00.007") ==
+ SysTime(DateTime(1998, 12, 25, 2, 15, 0), FracSec.from!"msecs"(7)));
+assert(SysTime.fromSimpleString("0000-Jan-05 23:09:59.00002") ==
+ SysTime(DateTime(0, 1, 5, 23, 9, 59), FracSec.from!"usecs"(20)));
+assert(SysTime.fromSimpleString("-0004-Jan-05 00:00:02") ==
+ SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
+assert(SysTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") ==
+ SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
+
+assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12Z") ==
+ SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
+assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12-8:00") ==
+ SysTime(DateTime(2010, 7, 4, 7, 6, 12), new SimpleTimeZone(-480)));
+assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12+8:00") ==
+ SysTime(DateTime(2010, 7, 4, 7, 6, 12), new SimpleTimeZone(480)));
+--------------------
+ +/
+ static SysTime fromSimpleString(S)(in S simpleString, immutable TimeZone tz = null)
+ if(isSomeString!(S))
+ {
+ auto dstr = to!dstring(strip(simpleString));
+
+ auto spaceIndex = dstr.indexOf(" ");
+ enforce(spaceIndex != -1, new DateTimeException(format("Invalid Simple String: %s", simpleString)));
+
+ auto found = dstr[spaceIndex + 1 .. $].find(".", "Z", "+", "-");
+ auto dateTimeStr = dstr[0 .. $ - found[0].length];
+
+ dstring fracSecStr;
+ dstring zoneStr;
+
+ if(found[1] != 0)
+ {
+ if(found[1] == 1)
+ {
+ auto foundTZ = found[0].find("Z", "+", "-");
+
+ if(foundTZ[1] != 0)
+ {
+ fracSecStr = found[0][0 .. $ - foundTZ[0].length];
+ zoneStr = foundTZ[0];
+ }
+ else
+ fracSecStr = found[0];
+ }
+ else
+ zoneStr = found[0];
+ }
+
+ try
+ {
+ auto dateTime = DateTime.fromSimpleString(dateTimeStr);
+ auto fracSec = fracSecFromISOString(fracSecStr);
+ DTRebindable!(immutable TimeZone) parsedZone;
+
+ if(zoneStr.empty)
+ parsedZone = LocalTime();
+ else if(zoneStr == "Z")
+ parsedZone = UTC();
+ else
+ parsedZone = SimpleTimeZone.fromISOString(zoneStr);
+
+ auto retval = SysTime(dateTime, fracSec, parsedZone.get);
+
+ if(tz !is null)
+ retval.timezone = tz;
+
+ return retval;
+ }
+ catch(DateTimeException dte)
+ throw new DateTimeException(format("Invalid Simple String: %s", simpleString));
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException(SysTime.fromSimpleString(""));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("20100704000000"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("20100704 000000"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("20100704t000000"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("20100704T000000."));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("20100704T000000.0"));
+
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-07-0400:00:00"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-07-04 00:00:00"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-07-04t00:00:00"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-07-04T00:00:00."));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-07-04T00:00:00.0"));
+
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-Jul-0400:00:00"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-Jul-04t00:00:00"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-Jul-04T00:00:00"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-Jul-04 00:00:00."));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-Jul-04 00:00:00.A"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-Jul-04 00:00:00.Z"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-Jul-04 00:00:00.00000000"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-Jul-04 00:00:00.00000000"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-Jul-04 00:00:00+"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-Jul-04 00:00:00-"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-Jul-04 00:00:00:"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-Jul-04 00:00:00-:"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-Jul-04 00:00:00+:"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-Jul-04 00:00:00-1:"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-Jul-04 00:00:00+1:"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-Jul-04 00:00:00+1:0"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-Jul-04 00:00:00-24.00"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-Jul-04 00:00:00+24.00"));
+
+ assertThrown!DateTimeException(SysTime.fromSimpleString("20101222T172201"));
+ assertThrown!DateTimeException(SysTime.fromSimpleString("2010-12-22T172201"));
+
+ assertPred!"=="(SysTime.fromSimpleString("2010-Dec-22 17:22:01"), SysTime(DateTime(2010, 12, 22, 17, 22, 01)));
+ assertPred!"=="(SysTime.fromSimpleString("1999-Jul-06 12:30:33"), SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
+ assertPred!"=="(SysTime.fromSimpleString("-1999-Jul-06 12:30:33"), SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
+ assertPred!"=="(SysTime.fromSimpleString("+01999-Jul-06 12:30:33"), SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
+ assertPred!"=="(SysTime.fromSimpleString("1999-Jul-06 12:30:33 "), SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
+ assertPred!"=="(SysTime.fromSimpleString(" 1999-Jul-06 12:30:33"), SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
+ assertPred!"=="(SysTime.fromSimpleString(" 1999-Jul-06 12:30:33 "), SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
+
+ assertPred!"=="(SysTime.fromSimpleString("1907-Jul-07 12:12:12.0"), SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
+ assertPred!"=="(SysTime.fromSimpleString("1907-Jul-07 12:12:12.0000000"), SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
+ assertPred!"=="(SysTime.fromSimpleString("1907-Jul-07 12:12:12.0000001"), SysTime(DateTime(1907, 07, 07, 12, 12, 12), FracSec.from!"hnsecs"(1)));
+ assertPred!"=="(SysTime.fromSimpleString("1907-Jul-07 12:12:12.000001"), SysTime(DateTime(1907, 07, 07, 12, 12, 12), FracSec.from!"usecs"(1)));
+ assertPred!"=="(SysTime.fromSimpleString("1907-Jul-07 12:12:12.0000010"), SysTime(DateTime(1907, 07, 07, 12, 12, 12), FracSec.from!"usecs"(1)));
+ assertPred!"=="(SysTime.fromSimpleString("1907-Jul-07 12:12:12.001"), SysTime(DateTime(1907, 07, 07, 12, 12, 12), FracSec.from!"msecs"(1)));
+ assertPred!"=="(SysTime.fromSimpleString("1907-Jul-07 12:12:12.0010000"), SysTime(DateTime(1907, 07, 07, 12, 12, 12), FracSec.from!"msecs"(1)));
+
+ assertPred!"=="(SysTime.fromSimpleString("2010-Dec-22 17:22:01Z"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC()));
+ assertPred!"=="(SysTime.fromSimpleString("2010-Dec-22 17:22:01-1:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(-60)));
+ assertPred!"=="(SysTime.fromSimpleString("2010-Dec-22 17:22:01-1"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(-60)));
+ assertPred!"=="(SysTime.fromSimpleString("2010-Dec-22 17:22:01-1:30"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(-90)));
+ assertPred!"=="(SysTime.fromSimpleString("2010-Dec-22 17:22:01-8:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(-480)));
+ assertPred!"=="(SysTime.fromSimpleString("2010-Dec-22 17:22:01+1:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(60)));
+ assertPred!"=="(SysTime.fromSimpleString("2010-Dec-22 17:22:01+1"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(60)));
+ assertPred!"=="(SysTime.fromSimpleString("2010-Dec-22 17:22:01+1:30"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(90)));
+ assertPred!"=="(SysTime.fromSimpleString("2010-Dec-22 17:22:01+8:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), new SimpleTimeZone(480)));
+
+ assertPred!"=="(SysTime.fromSimpleString("2010-Nov-03 06:51:06.57159Z"), SysTime(DateTime(2010, 11, 3, 6, 51, 6), FracSec.from!"hnsecs"(5715900), UTC()));
+
+ assertPred!"=="(SysTime.fromSimpleString("2010-Dec-22 17:22:01.23412Z"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(2_341_200), UTC()));
+ assertPred!"=="(SysTime.fromSimpleString("2010-Dec-22 17:22:01.23112-1:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(2_311_200), new SimpleTimeZone(-60)));
+ assertPred!"=="(SysTime.fromSimpleString("2010-Dec-22 17:22:01.45-1"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(4_500_000), new SimpleTimeZone(-60)));
+ assertPred!"=="(SysTime.fromSimpleString("2010-Dec-22 17:22:01.1-1:30"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(1_000_000), new SimpleTimeZone(-90)));
+ assertPred!"=="(SysTime.fromSimpleString("2010-Dec-22 17:22:01.55-8:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(5_500_000), new SimpleTimeZone(-480)));
+ assertPred!"=="(SysTime.fromSimpleString("2010-Dec-22 17:22:01.1234567+1:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(1_234_567), new SimpleTimeZone(60)));
+ assertPred!"=="(SysTime.fromSimpleString("2010-Dec-22 17:22:01.0+1"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(0), new SimpleTimeZone(60)));
+ assertPred!"=="(SysTime.fromSimpleString("2010-Dec-22 17:22:01.0000000+1:30"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(0), new SimpleTimeZone(90)));
+ assertPred!"=="(SysTime.fromSimpleString("2010-Dec-22 17:22:01.45+8:00"), SysTime(DateTime(2010, 12, 22, 17, 22, 01), FracSec.from!"hnsecs"(4_500_000), new SimpleTimeZone(480)));
+
+ //Verify Examples.
+ assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12") == SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
+ assert(SysTime.fromSimpleString("1998-Dec-25 02:15:00.007") == SysTime(DateTime(1998, 12, 25, 2, 15, 0), FracSec.from!"msecs"(7)));
+ assert(SysTime.fromSimpleString("0000-Jan-05 23:09:59.00002") == SysTime(DateTime(0, 1, 5, 23, 9, 59), FracSec.from!"usecs"(20)));
+ assert(SysTime.fromSimpleString("-0004-Jan-05 00:00:02") == SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
+ assert(SysTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") == SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
+
+ assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12Z") == SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
+ assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12-8:00") == SysTime(DateTime(2010, 7, 4, 7, 6, 12), new SimpleTimeZone(-480)));
+ assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12+8:00") == SysTime(DateTime(2010, 7, 4, 7, 6, 12), new SimpleTimeZone(480)));
+ }
+
+
+ //TODO Add function which takes a user-specified time format and produces a SysTime
+
+ //TODO Add function which takes pretty much any time-string and produces a SysTime.
+ // Obviously, it will be less efficient, and it probably won't manage _every_
+ // possible date format, but a smart conversion function would be nice.
+
+
+ /++
+ Returns the SysTime farthest in the past which is representable by SysTime.
+
+ The SysTime which is returned is in UTC.
+ +/
+ @property static SysTime min() pure nothrow
+ {
+ return SysTime(long.min, UTC());
+ }
+
+ unittest
+ {
+ assert(SysTime.min.year < 0);
+ assert(SysTime.min < SysTime.max);
+ }
+
+
+ /++
+ Returns the SysTime farthest in the future which is representable by SysTime.
+
+ The SysTime which is returned is in UTC.
+ +/
+ @property static SysTime max() pure nothrow
+ {
+ return SysTime(long.max, UTC());
+ }
+
+ unittest
+ {
+ assert(SysTime.max.year > 0);
+ assert(SysTime.max > SysTime.min);
+ }
+
+
+private:
+
+ /++
+ Returns stdTime converted to SysTime's time zone.
+ +/
+ @property long adjTime() const nothrow
+ {
+ return _timezone.utcToTZ(_stdTime);
+ }
+
+
+ /++
+ Converts the given hnsecs from SysTime's time zone to std time.
+ +/
+ @property void adjTime(long adjTime) nothrow
+ {
+ _stdTime = _timezone.tzToUTC(adjTime);
+ }
+
+
+ //Commented out due to bug http://d.puremagic.com/issues/show_bug.cgi?id=5058
+ /+
+ invariant()
+ {
+ assert(_timezone.get !is null, "Invariant Failure: timezone is null. Were you foolish enough to use SysTime.init? (since timezone for SysTime.init can't be set at compile time).");
+ }
+ +/
+
+
+ long _stdTime;
+ DTRebindable!(immutable TimeZone) _timezone;
+}
+
+
+//==============================================================================
+// Section with intervals.
+//==============================================================================
+
+/++
+ Represents an interval of time.
+
+ An $(D Interval) has a begin point and an end point. The interval of time is
+ therefore the time starting at the begin point up to, but not including, the
+ end point. e.g.
+
+ $(TABLE
+ $(TR $(TD [January 5th, 2010 - March 10th, 2010$(RPAREN)))
+ $(TR $(TD [05:00:30 - 12:00:00$(RPAREN)))
+ $(TR $(TD [1982-01-04T08:59:00 - 2010-07-04T12:00:00$(RPAREN)))
+ )
+
+ A range can be obtained from an $(D Interval), allowing you to iterate over
+ that interval, with the exact time points which are iterated over depending
+ on the function which generates the range.
+ +/
+struct Interval(TP)
+{
+public:
+
+ /++
+ Params:
+ begin = The time point which begins the interval.
+ end = The time point which ends (but is not included in) the interval.
+
+ Throws:
+ DateTimeException if end is before begin.
+
+ Examples:
+--------------------
+Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
+--------------------
+ +/
+ this(U)(in TP begin, in U end) pure
+ if(is(Unqual!TP == Unqual!U))
+ {
+ if(!_valid(begin, end))
+ throw new DateTimeException("Arguments would result in an invalid Interval.");
+
+ _begin = cast(TP)begin;
+ _end = cast(TP)end;
+ }
+
+
+ /++
+ Params:
+ begin = The time point which begins the interval.
+ duration = The duration from the begin point to the end point.
+
+ Throws:
+ DateTimeException if the resulting end is before begin.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Dur.years(3)) == Interval!Date(Date(1996, 1, 2), Date(1999, 1, 2)));
+--------------------
+ +/
+ this(D)(in TP begin, in D duration) pure
+ if(__traits(compiles, begin + duration))
+ {
+ _begin = cast(TP)begin;
+ _end = begin + duration;
+
+ if(!_valid(_begin, _end))
+ throw new DateTimeException("Arguments would result in an invalid Interval.");
+ }
+
+
+ /++
+ Params:
+ rhs = The Interval to assign to this one.
+ +/
+ /+ref+/ Interval opAssign(const ref Interval rhs) pure nothrow
+ {
+ _begin = cast(TP)rhs._begin;
+ _end = cast(TP)rhs._end;
+
+ return this;
+ }
+
+
+ /++
+ Params:
+ rhs = The Interval to assign to this one.
+ +/
+ /+ref+/ Interval opAssign(Interval rhs) pure nothrow
+ {
+ _begin = cast(TP)rhs._begin;
+ _end = cast(TP)rhs._end;
+
+ return this;
+ }
+
+
+ /++
+ The begin point of the interval. It is included in the interval.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).begin == Date(1996, 1, 2));
+--------------------
+ +/
+ @property TP begin() const pure nothrow
+ {
+ return cast(TP)_begin;
+ }
+
+
+ /++
+ The begin point of the interval. It is included in the interval.
+
+ Params:
+ timePoint = The time point to set begin to.
+
+ Throws:
+ DateTimeException if the resulting interval would be invalid.
+ +/
+ @property void begin(TP timePoint) pure
+ {
+ if(!_valid(timePoint, _end))
+ throw new DateTimeException("Arguments would result in an invalid Interval.");
+
+ _begin = timePoint;
+ }
+
+
+ /++
+ The end point of the interval. It is excluded from the interval.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).end == Date(2012, 3, 1));
+--------------------
+ +/
+ @property TP end() const pure nothrow
+ {
+ return cast(TP)_end;
+ }
+
+
+ /++
+ The end point of the interval. It is excluded from the interval.
+
+ Params:
+ timePoint = The time point to set end to.
+
+ Throws:
+ DateTimeException if the resulting interval would be invalid.
+ +/
+ @property void end(TP timePoint) pure
+ {
+ if(!_valid(_begin, timePoint))
+ throw new DateTimeException("Arguments would result in an invalid Interval.");
+
+ _end = timePoint;
+ }
+
+
+ /++
+ Returns the duration between begin and end.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).length == dur!"days"(5903));
+--------------------
+ +/
+ @property typeof(end - begin) length() const pure nothrow
+ {
+ return _end - _begin;
+ }
+
+
+ /++
+ Whether the interval's length is 0, that is, whether begin == end.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Date(1996, 1, 2)).empty);
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).empty);
+--------------------
+ +/
+ @property bool empty() const pure nothrow
+ {
+ return _begin == _end;
+ }
+
+
+ /++
+ Whether the given time point is within this interval.
+
+ Params:
+ timePoint = The time point to check for inclusion in this interval.
+
+ Throws:
+ DateTimeException if empty is true.
+
+ Examples:
+--------------------
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Date(1994, 12, 24)));
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Date(2000, 1, 5)));
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Date(2012, 3, 1)));
+--------------------
+ +/
+ bool contains(in TP timePoint) const pure
+ {
+ _enforceNotEmpty();
+
+ return timePoint >= _begin && timePoint < _end;
+ }
+
+
+ /++
+ Whether the given interval is completely within this interval.
+
+ Params:
+ interval = The interval to check for inclusion in this interval.
+
+ Throws:
+ DateTimeException if either interval is empty.
+
+ Examples:
+--------------------
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Interval!Date(Date(1998, 2, 28), Date(2013, 5, 1))));
+--------------------
+ +/
+ bool contains(in Interval interval) const pure
+ {
+ _enforceNotEmpty();
+ interval._enforceNotEmpty();
+
+ return interval._begin >= _begin &&
+ interval._begin < _end &&
+ interval._end <= _end;
+ }
+
+
+ /++
+ Whether the given interval is completely within this interval.
+
+ Always returns false (unless this interval is empty), because an interval
+ going to positive infinity can never be contained in a finite interval.
+
+ Params:
+ interval = The interval to check for inclusion in this interval.
+
+ Throws:
+ DateTimeException if this interval is empty.
+
+ Examples:
+--------------------
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(PosInfInterval!Date(Date(1999, 5, 4))));
+--------------------
+ +/
+ bool contains(in PosInfInterval!TP interval) const pure
+ {
+ _enforceNotEmpty();
+
+ return false;
+ }
+
+
+ /++
+ Whether the given interval is completely within this interval.
+
+ Always returns false (unless this interval is empty), because an interval
+ begging at negative infinity can never be contained in a finite interval.
+
+ Params:
+ interval = The interval to check for inclusion in this interval.
+
+ Throws:
+ DateTimeException if this interval is empty.
+
+ Examples:
+--------------------
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(NegInfInterval!Date(Date(1996, 5, 4))));
+--------------------
+ +/
+ bool contains(in NegInfInterval!TP interval) const pure
+ {
+ _enforceNotEmpty();
+
+ return false;
+ }
+
+
+ /++
+ Whether this interval is before the given time point.
+
+ Params:
+ timePoint = The time point to check whether this interval is before it.
+
+ Throws:
+ DateTimeException if empty is true.
+
+ Examples:
+--------------------
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Date(1994, 12, 24)));
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Date(2000, 1, 5)));
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Date(2012, 3, 1)));
+--------------------
+ +/
+ bool isBefore(in TP timePoint) const pure
+ {
+ _enforceNotEmpty();
+
+ return _end <= timePoint;
+ }
+
+
+ /++
+ Whether this interval is before the given interval and does not intersect
+ with it.
+
+ Params:
+ interval = The interval to check for against this interval.
+
+ Throws:
+ DateTimeException if either interval is empty.
+
+ Examples:
+--------------------
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Interval!Date(Date(2012, 3, 1), Date(2013, 5, 1))));
+--------------------
+ +/
+ bool isBefore(in Interval interval) const pure
+ {
+ _enforceNotEmpty();
+ interval._enforceNotEmpty();
+
+ return _end <= interval._begin;
+ }
+
+
+ /++
+ Whether this interval is before the given interval and does not intersect
+ with it.
+
+ Params:
+ interval = The interval to check for against this interval.
+
+ Throws:
+ DateTimeException if this interval is empty.
+
+ Examples:
+--------------------
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(PosInfInterval!Date(Date(1999, 5, 4))));
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(PosInfInterval!Date(Date(2013, 3, 7))));
+--------------------
+ +/
+ bool isBefore(in PosInfInterval!TP interval) const pure
+ {
+ _enforceNotEmpty();
+
+ return _end <= interval._begin;
+ }
+
+
+ /++
+ Whether this interval is before the given interval and does not intersect
+ with it.
+
+ Always returns false (unless this interval is empty) because a finite
+ interval can never be before an interval beginning at negative infinity.
+
+ Params:
+ interval = The interval to check for against this interval.
+
+ Throws:
+ DateTimeException if this interval is empty.
+
+ Examples:
+--------------------
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(NegInfInterval!Date(Date(1996, 5, 4))));
+--------------------
+ +/
+ bool isBefore(in NegInfInterval!TP interval) const pure
+ {
+ _enforceNotEmpty();
+
+ return false;
+ }
+
+
+ /++
+ Whether this interval is after the given time point.
+
+ Params:
+ timePoint = The time point to check whether this interval is after it.
+
+ Throws:
+ DateTimeException if empty is true.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Date(1994, 12, 24)));
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Date(2000, 1, 5)));
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Date(2012, 3, 1)));
+--------------------
+ +/
+ bool isAfter(in TP timePoint) const pure
+ {
+ _enforceNotEmpty();
+
+ return timePoint < _begin;
+ }
+
+
+ /++
+ Whether this interval is after the given interval and does not intersect
+ with it.
+
+ Params:
+ interval = The interval to check against this interval.
+
+ Throws:
+ DateTimeException if either interval is empty.
+
+ Examples:
+--------------------
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
+--------------------
+ +/
+ bool isAfter(in Interval interval) const pure
+ {
+ _enforceNotEmpty();
+ interval._enforceNotEmpty();
+
+ return _begin >= interval._end;
+ }
+
+
+ /++
+ Whether this interval is after the given interval and does not intersect
+ with it.
+
+ Always returns false (unless this interval is empty) because a finite
+ interval can never be after an interval going to positive infinity.
+
+ Params:
+ interval = The interval to check against this interval.
+
+ Throws:
+ DateTimeException if this interval is empty.
+
+ Examples:
+--------------------
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(PosInfInterval!Date(Date(1999, 5, 4))));
+--------------------
+ +/
+ bool isAfter(in PosInfInterval!TP interval) const pure
+ {
+ _enforceNotEmpty();
+
+ return false;
+ }
+
+
+ /++
+ Whether this interval is after the given interval and does not intersect
+ with it.
+
+ Params:
+ interval = The interval to check against this interval.
+
+ Throws:
+ DateTimeException if this interval is empty.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(NegInfInterval!Date(Date(1996, 1, 2))));
+--------------------
+ +/
+ bool isAfter(in NegInfInterval!TP interval) const pure
+ {
+ _enforceNotEmpty();
+
+ return _begin >= interval._end;
+ }
+
+
+ /++
+ Whether the given interval overlaps with this interval.
+
+ Params:
+ interval = The interval to check for intersection with this interval.
+
+ Throws:
+ DateTimeException if either interval is empty.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
+--------------------
+ +/
+ bool intersects(in Interval interval) const pure
+ {
+ _enforceNotEmpty();
+ interval._enforceNotEmpty();
+
+ return interval._begin < _end && interval._end > _begin;
+ }
+
+
+ /++
+ Whether the given interval overlaps with this interval.
+
+ Params:
+ interval = The interval to check for intersection with this interval.
+
+ Throws:
+ DateTimeException if this interval is empty.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(PosInfInterval!Date(Date(1999, 5, 4))));
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(PosInfInterval!Date(Date(2012, 3, 1))));
+--------------------
+ +/
+ bool intersects(in PosInfInterval!TP interval) const pure
+ {
+ _enforceNotEmpty();
+
+ return _end > interval._begin;
+ }
+
+
+ /++
+ Whether the given interval overlaps with this interval.
+
+ Params:
+ interval = The interval to check for intersection with this interval.
+
+ Throws:
+ DateTimeException if this interval is empty.
+
+ Examples:
+--------------------
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(NegInfInterval!Date(Date(1996, 1, 2))));
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(NegInfInterval!Date(Date(2000, 1, 2))));
+--------------------
+ +/
+ bool intersects(in NegInfInterval!TP interval) const pure
+ {
+ _enforceNotEmpty();
+
+ return _begin < interval._end;
+ }
+
+
+ /++
+ Returns the intersection of two intervals
+
+ Params:
+ interval = The interval to intersect with this interval.
+
+ Throws:
+ DateTimeException if the two intervals do not intersect or if
+ either interval is empty.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == Interval!Date(Date(1996, 1 , 2), Date(2000, 8, 2)));
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) == Interval!Date(Date(1999, 1 , 12), Date(2011, 9, 17)));
+--------------------
+ +/
+ Interval intersection(in Interval interval) const
+ {
+ enforce(this.intersects(interval), new DateTimeException(format("%s and %s do not intersect.", this, interval)));
+
+ auto begin = _begin > interval._begin ? _begin : interval._begin;
+ auto end = _end < interval._end ? _end : interval._end;
+
+ return Interval(begin, end);
+ }
+
+
+ /++
+ Returns the intersection of two intervals
+
+ Params:
+ interval = The interval to intersect with this interval.
+
+ Throws:
+ DateTimeException if the two intervals do not intersect or if this
+ interval is empty.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(PosInfInterval!Date(Date(1990, 7, 6))) == Interval!Date(Date(1996, 1 , 2), Date(2012, 3, 1)));
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(PosInfInterval!Date(Date(1999, 1, 12))) == Interval!Date(Date(1999, 1 , 12), Date(2012, 3, 1)));
+--------------------
+ +/
+ Interval intersection(in PosInfInterval!TP interval) const
+ {
+ enforce(this.intersects(interval), new DateTimeException(format("%s and %s do not intersect.", this, interval)));
+
+ return Interval(_begin > interval._begin ? _begin : interval._begin, _end);
+ }
+
+
+ /++
+ Returns the intersection of two intervals
+
+ Params:
+ interval = The interval to intersect with this interval.
+
+ Throws:
+ DateTimeException if the two intervals do not intersect or if this
+ interval is empty.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(NegInfInterval!Date(Date(1999, 7, 6))) == Interval!Date(Date(1996, 1 , 2), Date(1999, 7, 6)));
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(NegInfInterval!Date(Date(2013, 1, 12))) == Interval!Date(Date(1996, 1 , 2), Date(2012, 3, 1)));
+--------------------
+ +/
+ Interval intersection(in NegInfInterval!TP interval) const
+ {
+ enforce(this.intersects(interval), new DateTimeException(format("%s and %s do not intersect.", this, interval)));
+
+ return Interval(_begin, _end < interval._end ? _end : interval._end);
+ }
+
+
+ /++
+ Whether the given interval is adjacent to this interval.
+
+ Params:
+ interval = The interval to check whether its adjacent with this
+ interval.
+
+ Throws:
+ DateTimeException if either interval is empty.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(1990, 7, 6), Date(1996, 1, 2))));
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(2012, 3, 1), Date(2013, 9, 17))));
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(1989, 3, 1), Date(2012, 3, 1))));
+--------------------
+ +/
+ bool isAdjacent(in Interval interval) const pure
+ {
+ _enforceNotEmpty();
+ interval._enforceNotEmpty();
+
+ return _begin == interval._end || _end == interval._begin;
+ }
+
+
+ /++
+ Whether the given interval is adjacent to this interval.
+
+ Params:
+ interval = The interval to check whether its adjacent with this
+ interval.
+
+ Throws:
+ DateTimeException if this is empty.
+
+ Examples:
+--------------------
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(PosInfInterval!Date(Date(1999, 5, 4))));
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(PosInfInterval!Date(Date(2012, 3, 1))));
+--------------------
+ +/
+ bool isAdjacent(in PosInfInterval!TP interval) const pure
+ {
+ _enforceNotEmpty();
+
+ return _end == interval._begin;
+ }
+
+
+ /++
+ Whether the given interval is adjacent to this interval.
+
+ Params:
+ interval = The interval to check whether its adjacent with this
+ interval.
+
+ Throws:
+ DateTimeException if this is empty.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(NegInfInterval!Date(Date(1996, 1, 2))));
+assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(NegInfInterval!Date(Date(2000, 1, 2))));
+--------------------
+ +/
+ bool isAdjacent(in NegInfInterval!TP interval) const pure
+ {
+ _enforceNotEmpty();
+
+ return _begin == interval._end;
+ }
+
+
+ /++
+ Returns the union of two intervals
+
+ Params:
+ interval = The interval to merge with this interval.
+
+ Throws:
+ DateTimeException if the two intervals do not intersect and are not
+ adjacent or if either interval is empty.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == Interval!Date(Date(1990, 7 , 6), Date(2012, 3, 1)));
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(Interval!Date(Date(2012, 3, 1), Date(2013, 5, 7))) == Interval!Date(Date(1996, 1 , 2), Date(2013, 5, 7)));
+--------------------
+ +/
+ Interval merge(in Interval interval) const
+ {
+ enforce(this.isAdjacent(interval) || this.intersects(interval),
+ new DateTimeException(format("%s and %s are not adjacent and do not intersect.", this, interval)));
+
+ auto begin = _begin < interval._begin ? _begin : interval._begin;
+ auto end = _end > interval._end ? _end : interval._end;
+
+ return Interval(begin, end);
+ }
+
+
+ /++
+ Returns the union of two intervals
+
+ Params:
+ interval = The interval to merge with this interval.
+
+ Throws:
+ DateTimeException if the two intervals do not intersect and are
+ not adjacent or if this interval is empty.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1990, 7 , 6)));
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(PosInfInterval!Date(Date(2012, 3, 1))) == PosInfInterval!Date(Date(1996, 1 , 2)));
+--------------------
+ +/
+ PosInfInterval!TP merge(in PosInfInterval!TP interval) const
+ {
+ enforce(this.isAdjacent(interval) || this.intersects(interval),
+ new DateTimeException(format("%s and %s are not adjacent and do not intersect.", this, interval)));
+
+ return PosInfInterval!TP(_begin < interval._begin ? _begin : interval._begin);
+ }
+
+
+ /++
+ Returns the union of two intervals
+
+ Params:
+ interval = The interval to merge with this interval.
+
+ Throws:
+ DateTimeException if the two intervals do not intersect and are not
+ adjacent or if this interval is empty.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(NegInfInterval!Date(Date(1996, 1, 2))) == NegInfInterval!Date(Date(2012, 3 , 1)));
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2013, 1 , 12)));
+--------------------
+ +/
+ NegInfInterval!TP merge(in NegInfInterval!TP interval) const
+ {
+ enforce(this.isAdjacent(interval) || this.intersects(interval),
+ new DateTimeException(format("%s and %s are not adjacent and do not intersect.", this, interval)));
+
+ return NegInfInterval!TP(_end > interval._end ? _end : interval._end);
+ }
+
+
+ /++
+ Returns an interval that covers from the earliest time point of two
+ intervals up to (but not including) the latest time point of two intervals.
+
+ Params:
+ interval = The interval to create a span together with this interval.
+
+ Throws:
+ DateTimeException if either interval is empty.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(Interval!Date(Date(1990, 7, 6), Date(1991, 1, 8))) == Interval!Date(Date(1990, 7 , 6), Date(2012, 3, 1)));
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(Interval!Date(Date(2012, 3, 1), Date(2013, 5, 7))) == Interval!Date(Date(1996, 1 , 2), Date(2013, 5, 7)));
+--------------------
+ +/
+ Interval span(in Interval interval) const pure
+ {
+ _enforceNotEmpty();
+ interval._enforceNotEmpty();
+
+ auto begin = _begin < interval._begin ? _begin : interval._begin;
+ auto end = _end > interval._end ? _end : interval._end;
+
+ return Interval(begin, end);
+ }
+
+
+ /++
+ Returns an interval that covers from the earliest time point of two
+ intervals up to (but not including) the latest time point of two intervals.
+
+ Params:
+ interval = The interval to create a span together with this interval.
+
+ Throws:
+ DateTimeException if this interval is empty.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1990, 7 , 6)));
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(PosInfInterval!Date(Date(2050, 1, 1))) == PosInfInterval!Date(Date(1996, 1 , 2)));
+--------------------
+ +/
+ PosInfInterval!TP span(in PosInfInterval!TP interval) const pure
+ {
+ _enforceNotEmpty();
+
+ return PosInfInterval!TP(_begin < interval._begin ? _begin : interval._begin);
+ }
+
+
+ /++
+ Returns an interval that covers from the earliest time point of two
+ intervals up to (but not including) the latest time point of two intervals.
+
+ Params:
+ interval = The interval to create a span together with this interval.
+
+ Throws:
+ DateTimeException if this interval is empty.
+
+ Examples:
+--------------------
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(NegInfInterval!Date(Date(1602, 5, 21))) == NegInfInterval!Date(Date(2012, 3 , 1)));
+assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2013, 1 , 12)));
+--------------------
+ +/
+ NegInfInterval!TP span(in NegInfInterval!TP interval) const pure
+ {
+ _enforceNotEmpty();
+
+ return NegInfInterval!TP(_end > interval._end ? _end : interval._end);
+ }
+
+
+ /++
+ Shifts the interval forward or backwards in time by the given duration
+ (a positive duration shifts the interval forward; a negative duration
+ shifts it backward). Effectively, it does $(D begin += duration) and
+ $(D end += duration).
+
+ Params:
+ duration = The duration to shift the interval by.
+
+ Throws:
+ DateTimeException if empty is true or if the resulting interval
+ would be invalid.
+
+ Examples:
+--------------------
+auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 4, 5));
+auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 4, 5));
+
+interval1.shift(dur!"days"(50));
+assert(interval1 == Interval!Date(Date(1996, 2, 21), Date(2012, 5, 25)));
+
+interval2.shift(dur!"days"(-50));
+assert(interval2 == Interval!Date(Date(1995, 11, 13), Date(2012, 2, 15)));
+--------------------
+ +/
+ void shift(D)(D duration) pure
+ if(__traits(compiles, begin + duration))
+ {
+ _enforceNotEmpty();
+
+ auto begin = _begin + duration;
+ auto end = _end + duration;
+
+ if(!_valid(begin, end))
+ throw new DateTimeException("Argument would result in an invalid Interval.");
+
+ _begin = begin;
+ _end = end;
+ }
+
+
+ static if(__traits(compiles, begin.add!"months"(1)) &&
+ __traits(compiles, begin.add!"years"(1)))
+ {
+ /++
+ Shifts the interval forward or backwards in time by the given number
+ of years and/or months (a positive number of years and months shifts
+ the interval forward; a negative number shifts it backward).
+ It adds the years the given years and months to both begin and end.
+ It effectively calls $(D add!"years"()) and then $(D add!"months"())
+ on begin and end with the given number of years and months.
+
+ Params:
+ years = The number of years to shift the interval by.
+ months = The number of months to shift the interval by.
+ allowOverflow = Whether the days should be allowed to overflow
+ on begin and end, causing their month to increment.
+
+ Throws:
+ DateTimeException if empty is true or if the resulting interval
+ would be invalid.
+
+ Examples:
+--------------------
+auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
+auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
+
+interval1.shift(2);
+assert(interval1 == Interval!Date(Date(1998, 1, 2), Date(2014, 3, 1)));
+
+interval2.shift(-2);
+assert(interval2 == Interval!Date(Date(1994, 1, 2), Date(2010, 3, 1)));
+--------------------
+ +/
+ void shift(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
+ if(isIntegral!T)
+ {
+ _enforceNotEmpty();
+
+ auto begin = _begin;
+ auto end = _end;
+
+ begin.add!"years"(years, allowOverflow);
+ begin.add!"months"(months, allowOverflow);
+ end.add!"years"(years, allowOverflow);
+ end.add!"months"(months, allowOverflow);
+
+ enforce(_valid(begin, end), new DateTimeException("Argument would result in an invalid Interval."));
+
+ _begin = begin;
+ _end = end;
+ }
+ }
+
+
+ /++
+ Expands the interval forwards and/or backwards in time. Effectively,
+ it does $(D begin -= duration) and/or $(D end += duration). Whether
+ it expands forwards and/or backwards in time is determined by the
+ $(D dir) parameter.
+
+ Params:
+ duration = The duration to expand the interval by.
+ dir = The direction in time to expand the interval.
+
+ Throws:
+ DateTimeException if empty is true or if the resulting interval would
+ be invalid.
+
+ Examples:
+--------------------
+auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
+auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
+
+interval1.expand(2);
+assert(interval1 == Interval!Date(Date(1994, 1, 2), Date(2014, 3, 1)));
+
+interval2.expand(-2);
+assert(interval2 == Interval!Date(Date(1998, 1, 2), Date(2010, 3, 1)));
+--------------------
+ +/
+ void expand(D)(D duration, Direction dir = Direction.both) pure
+ if(__traits(compiles, begin + duration))
+ {
+ _enforceNotEmpty();
+
+ switch(dir)
+ {
+ case Direction.both:
+ {
+ auto begin = _begin - duration;
+ auto end = _end + duration;
+
+ if(!_valid(begin, end))
+ throw new DateTimeException("Argument would result in an invalid Interval.");
+
+ _begin = begin;
+ _end = end;
+
+ return;
+ }
+ case Direction.fwd:
+ {
+ auto end = _end + duration;
+
+ if(!_valid(_begin, end))
+ throw new DateTimeException("Argument would result in an invalid Interval.");
+ _end = end;
+
+ return;
+ }
+ case Direction.bwd:
+ {
+ auto begin = _begin - duration;
+
+ if(!_valid(begin, _end))
+ throw new DateTimeException("Argument would result in an invalid Interval.");
+ _begin = begin;
+
+ return;
+ }
+ default:
+ assert(0, "Invalid Direction.");
+ }
+ }
+
+ static if(__traits(compiles, begin.add!"months"(1)) &&
+ __traits(compiles, begin.add!"years"(1)))
+ {
+ /++
+ Expands the interval forwards and/or backwards in time. Effectively,
+ it subtracts the given number of months/years from begin and adds
+ them to end. Whether it expands forwards and/or backwards in time
+ is determined by the dir parameter.
+
+ Params:
+ years = The number of years to expand the interval by.
+ months = The number of months to expand the interval by.
+ allowOverflow = Whether the days should be allowed to overflow
+ on begin and end, causing their month to increment.
+
+ Throws:
+ DateTimeException if empty is true or if the resulting interval
+ would be invalid.
+
+ Examples:
+--------------------
+auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
+auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
+
+interval1.expand(2);
+assert(interval1 == Interval!Date(Date(1994, 1, 2), Date(2014, 3, 1)));
+
+interval2.expand(-2);
+assert(interval2 == Interval!Date(Date(1998, 1, 2), Date(2010, 3, 1)));
+--------------------
+ +/
+ void expand(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes, Direction dir = Direction.both)
+ if(isIntegral!T)
+ {
+ _enforceNotEmpty();
+
+ switch(dir)
+ {
+ case Direction.both:
+ {
+ auto begin = _begin;
+ auto end = _end;
+
+ begin.add!"years"(-years, allowOverflow);
+ begin.add!"months"(-months, allowOverflow);
+ end.add!"years"(years, allowOverflow);
+ end.add!"months"(months, allowOverflow);
+
+ enforce(_valid(begin, end), new DateTimeException("Argument would result in an invalid Interval."));
+ _begin = begin;
+ _end = end;
+
+ return;
+ }
+ case Direction.fwd:
+ {
+ auto end = _end;
+
+ end.add!"years"(years, allowOverflow);
+ end.add!"months"(months, allowOverflow);
+
+ enforce(_valid(_begin, end), new DateTimeException("Argument would result in an invalid Interval."));
+ _end = end;
+
+ return;
+ }
+ case Direction.bwd:
+ {
+ auto begin = _begin;
+
+ begin.add!"years"(-years, allowOverflow);
+ begin.add!"months"(-months, allowOverflow);
+
+ enforce(_valid(begin, _end), new DateTimeException("Argument would result in an invalid Interval."));
+ _begin = begin;
+
+ return;
+ }
+ default:
+ assert(0, "Invalid Direction.");
+ }
+ }
+ }
+
+
+ /++
+ Returns a range which iterates forward over the interval, starting
+ at begin, using $(D func) to generate each successive time point.
+
+ The range's $(D front) is the interval's $(D begin). $(D func) is used
+ to generate the next $(D front) when $(D popFront()) is called. If
+ $(D popFirst) is $(D PopFirst.yes), then $(D popFront()) is called
+ before the range is returned (so that front is a time point which
+ $(D func) would generate).
+
+ If $(D func) ever generates a time point less than or equal to the
+ current front of the range, then a DateTimeException will be thrown.
+ The range will be empty and iteration complete when $(D func) generates
+ a time point equal to or beyond the end of the interval.
+
+ There are helper functions in this module which generate common delegates
+ to pass to $(D fwdRange()). Their documentation starts with
+ "Generates a range-generating function for intervals," so you can easily
+ search for them.
+
+ Params:
+ func = The function used to generate the time points of the
+ range over the interval.
+ popFirst = Whether $(D popFront()) should be called on the range
+ before returning it.
+
+ Throws:
+ DateTimeException if the interval is empty.
+
+ Warning:
+ func must be logically pure. Ideally, $(D func) would be a function
+ pointer to a pure function, but forcing func to be pure is far too
+ restrictive to be useful, and in order to have the ease of use of
+ having functions which generate functions to pass to $(D fwdRange()),
+ $(D func) must be a delegate.
+
+ If $(D func) retains state which changes as it is called, then some
+ algorithms will not work correctly, because the range's $(D save)
+ will have failed to have really saved the range's state. So, if you
+ want to avoid such bugs, don't pass a delegate which is not
+ logically pure to $(D fwdRange()). If $(D func) is given the same
+ time point with two different calls, it must return the same result
+ both times.
+
+ Of course, none of the functions in this module have this problem, so
+ it's only relevant if you're creating your own delegate.
+
+ Examples:
+--------------------
+auto interval = Interval!Date(Date(2010, 9, 1), Date(2010, 9, 9));
+auto func = (in Date date) //For iterating over even-numbered days.
+ {
+ if((date.day & 1) == 0)
+ return date + dur!"days"(2);
+
+ return date + dur!"days"(1);
+ };
+auto range = interval.fwdRange(func);
+
+assert(range.front == Date(2010, 9, 1)); //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 2).
+
+range.popFront();
+assert(range.front == Date(2010, 9, 2));
+
+range.popFront();
+assert(range.front == Date(2010, 9, 4));
+
+range.popFront();
+assert(range.front == Date(2010, 9, 6));
+
+range.popFront();
+assert(range.front == Date(2010, 9, 8));
+
+range.popFront();
+assert(range.empty);
+--------------------
+ +/
+ IntervalRange!(TP, Direction.fwd) fwdRange(TP delegate(in TP) func, PopFirst popFirst = PopFirst.no) const
+ {
+ _enforceNotEmpty();
+
+ auto range = IntervalRange!(TP, Direction.fwd)(this, func);
+
+ if(popFirst == PopFirst.yes)
+ range.popFront();
+
+ return range;
+ }
+
+
+ /++
+ Returns a range which iterates backwards over the interval, starting
+ at end, using $(D func) to generate each successive time point.
+
+ The range's $(D front) is the interval's $(D end). $(D func) is used
+ to generate the next $(D front) when $(D popFront()) is called. If
+ $(D popFirst) is $(D PopFirst.yes), then $(D popFront()) is called
+ before the range is returned (so that $(D front) is a time point which
+ $(D func) would generate).
+
+ If $(D func) ever generates a time point greater than or equal to the
+ current $(D front) of the range, then a DateTimeException will be thrown.
+ The range will be empty and iteration complete when $(D func) generates
+ a time point equal to or less than the $(D begin) of the interval.
+
+ There are helper functions in this module which generate common delegates
+ to pass to $(D bwdRange()). Their documentation starts with
+ "Generates a range-generating function for intervals," so you can easily
+ search for them.
+
+ Params:
+ func = The function used to generate the time points of the range
+ over the interval.
+ popFirst = Whether $(D popFront()) should be called on the range before
+ returning it.
+
+ Throws:
+ DateTimeException if the interval is empty.
+
+ Warning:
+ func must be logically pure. Ideally, $(D func) would be a function
+ pointer to a pure function, but forcing func to be pure is far too
+ restrictive to be useful, and in order to have the ease of use of
+ having functions which generate functions to pass to $(D fwdRange()),
+ $(D func) must be a delegate.
+
+ If $(D func) retains state which changes as it is called, then some
+ algorithms will not work correctly, because the range's $(D save)
+ will have failed to have really saved the range's state. So, if you
+ want to avoid such bugs, don't pass a delegate which is not
+ logically pure to $(D fwdRange()). If $(D func) is given the same
+ time point with two different calls, it must return the same result
+ both times.
+
+ Of course, none of the functions in this module have this problem, so
+ it's only relevant if you're creating your own delegate.
+
+ Examples:
+--------------------
+auto interval = Interval!Date(Date(2010, 9, 1), Date(2010, 9, 9));
+auto func = (in Date date) //For iterating over even-numbered days.
+ {
+ if((date.day & 1) == 0)
+ return date - dur!"days"(2);
+
+ return date - dur!"days"(1);
+ };
+auto range = interval.bwdRange(func);
+
+assert(range.front == Date(2010, 9, 9)); //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 8).
+
+range.popFront();
+assert(range.front == Date(2010, 9, 8));
+
+range.popFront();
+assert(range.front == Date(2010, 9, 6));
+
+range.popFront();
+assert(range.front == Date(2010, 9, 4));
+
+range.popFront();
+assert(range.front == Date(2010, 9, 2));
+
+range.popFront();
+assert(range.empty);
+--------------------
+ +/
+ IntervalRange!(TP, Direction.bwd) bwdRange(TP delegate(in TP) func, PopFirst popFirst = PopFirst.no) const
+ {
+ _enforceNotEmpty();
+
+ auto range = IntervalRange!(TP, Direction.bwd)(this, func);
+
+ if(popFirst == PopFirst.yes)
+ range.popFront();
+
+ return range;
+ }
+
+
+ /+
+ Converts this interval to a string.
+ +/
+ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't
+ //have versions of toString() with extra modifiers, so we define one version
+ //with modifiers and one without.
+ string toString()
+ {
+ return _toStringImpl();
+ }
+
+
+ /++
+ Converts this interval to a string.
+ +/
+ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't
+ //have versions of toString() with extra modifiers, so we define one version
+ //with modifiers and one without.
+ string toString() const nothrow
+ {
+ return _toStringImpl();
+ }
+
+
+private:
+
+ /++
+ Since we have two versions of toString(), we have _toStringImpl()
+ so that they can share implementations.
+ +/
+ string _toStringImpl() const nothrow
+ {
+ try
+ return format("[%s - %s)", _begin, _end);
+ catch(Exception e)
+ assert(0, "format() threw.");
+ }
+
+
+ /++
+ Throws:
+ DateTimeException if empty is true.
+ +/
+ void _enforceNotEmpty(size_t line = __LINE__) const pure
+ {
+ if(empty)
+ throw new DateTimeException("Invalid operation for an empty Interval.", __FILE__, line);
+ }
+
+
+ /++
+ Whether the given values form a valid time interval.
+
+ Params:
+ begin = The begin point of the interval.
+ end = The end point of the interval.
+ +/
+ static bool _valid(in TP begin, in TP end) pure nothrow
+ {
+ return begin <= end;
+ }
+
+
+ pure invariant()
+ {
+ assert(_valid(_begin, _end), "Invariant Failure: begin is not before or equal to end.");
+ }
+
+
+ TP _begin;
+ TP _end;
+}
+
+//Test Interval's constructors.
+unittest
+{
+ assertThrown!DateTimeException(Interval!Date(Date(2010, 1, 1), Date(1, 1, 1)));
+
+ Interval!Date(Date.init, Date.init);
+ Interval!TimeOfDay(TimeOfDay.init, TimeOfDay.init);
+ Interval!DateTime(DateTime.init, DateTime.init);
+ Interval!SysTime(SysTime(0), SysTime(0));
+
+ Interval!DateTime(DateTime.init, dur!"days"(7));
+
+ //Verify Examples.
+ Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
+ assert(Interval!Date(Date(1996, 1, 2), dur!"weeks"(3)) == Interval!Date(Date(1996, 1, 2), Date(1996, 1, 23)));
+ assert(Interval!Date(Date(1996, 1, 2), dur!"days"(3)) == Interval!Date(Date(1996, 1, 2), Date(1996, 1, 5)));
+ assert(Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), dur!"hours"(3)) == Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), DateTime(1996, 1, 2, 15, 0, 0)));
+ assert(Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), dur!"minutes"(3)) == Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), DateTime(1996, 1, 2, 12, 3, 0)));
+ assert(Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), dur!"seconds"(3)) == Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), DateTime(1996, 1, 2, 12, 0, 3)));
+ assert(Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), dur!"msecs"(3000)) == Interval!DateTime(DateTime(1996, 1, 2, 12, 0, 0), DateTime(1996, 1, 2, 12, 0, 3)));
+}
+
+//Test Interval's begin.
+unittest
+{
+ assertPred!"=="(Interval!Date(Date(1, 1, 1), Date(2010, 1, 1)).begin, Date(1, 1, 1));
+ assertPred!"=="(Interval!Date(Date(2010, 1, 1), Date(2010, 1, 1)).begin, Date(2010, 1, 1));
+ assertPred!"=="(Interval!Date(Date(1997, 12, 31), Date(1998, 1, 1)).begin, Date(1997, 12, 31));
+
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ static assert(__traits(compiles, cInterval.begin));
+ static assert(__traits(compiles, iInterval.begin));
+
+ //Verify Examples.
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).begin == Date(1996, 1, 2));
+}
+
+//Test Interval's end.
+unittest
+{
+ assertPred!"=="(Interval!Date(Date(1, 1, 1), Date(2010, 1, 1)).end, Date(2010, 1, 1));
+ assertPred!"=="(Interval!Date(Date(2010, 1, 1), Date(2010, 1, 1)).end, Date(2010, 1, 1));
+ assertPred!"=="(Interval!Date(Date(1997, 12, 31), Date(1998, 1, 1)).end, Date(1998, 1, 1));
+
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ static assert(__traits(compiles, cInterval.end));
+ static assert(__traits(compiles, iInterval.end));
+
+ //Verify Examples.
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).end == Date(2012, 3, 1));
+}
+
+//Test Interval's length.
+unittest
+{
+ assertPred!"=="(Interval!Date(Date(2010, 1, 1), Date(2010, 1, 1)).length, dur!"days"(0));
+ assertPred!"=="(Interval!Date(Date(2010, 1, 1), Date(2010, 4, 1)).length, dur!"days"(90));
+ assertPred!"=="(Interval!TimeOfDay(TimeOfDay(0, 30, 0), TimeOfDay(12, 22, 7)).length, dur!"seconds"(42_727));
+ assertPred!"=="(Interval!DateTime(DateTime(2010, 1, 1, 0, 30, 0), DateTime(2010, 1, 2, 12, 22, 7)).length, dur!"seconds"(129_127));
+ assertPred!"=="(Interval!SysTime(SysTime(DateTime(2010, 1, 1, 0, 30, 0)), SysTime(DateTime(2010, 1, 2, 12, 22, 7))).length, dur!"seconds"(129_127));
+
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ static assert(__traits(compiles, cInterval.length));
+ static assert(__traits(compiles, iInterval.length));
+
+ //Verify Examples.
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).length == dur!"days"(5903));
+}
+
+//Test Interval's empty.
+unittest
+{
+ assert(Interval!Date(Date(2010, 1, 1), Date(2010, 1, 1)).empty);
+ assert(!Interval!Date(Date(2010, 1, 1), Date(2010, 4, 1)).empty);
+ assert(!Interval!TimeOfDay(TimeOfDay(0, 30, 0), TimeOfDay(12, 22, 7)).empty);
+ assert(!Interval!DateTime(DateTime(2010, 1, 1, 0, 30, 0), DateTime(2010, 1, 2, 12, 22, 7)).empty);
+ assert(!Interval!SysTime(SysTime(DateTime(2010, 1, 1, 0, 30, 0)), SysTime(DateTime(2010, 1, 2, 12, 22, 7))).empty);
+
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ static assert(__traits(compiles, cInterval.empty));
+ static assert(__traits(compiles, iInterval.empty));
+
+ //Verify Examples.
+ assert(Interval!Date(Date(1996, 1, 2), Date(1996, 1, 2)).empty);
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).empty);
+}
+
+//Test Interval's contains(time point).
+unittest
+{
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+
+ assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).contains(Date(2010, 7, 4)));
+
+ assert(!interval.contains(Date(2009, 7, 4)));
+ assert(!interval.contains(Date(2010, 7, 3)));
+ assert(interval.contains(Date(2010, 7, 4)));
+ assert(interval.contains(Date(2010, 7, 5)));
+ assert(interval.contains(Date(2011, 7, 1)));
+ assert(interval.contains(Date(2012, 1, 6)));
+ assert(!interval.contains(Date(2012, 1, 7)));
+ assert(!interval.contains(Date(2012, 1, 8)));
+ assert(!interval.contains(Date(2013, 1, 7)));
+
+ const cdate = Date(2010, 7, 6);
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ static assert(__traits(compiles, interval.contains(cdate)));
+ static assert(__traits(compiles, cInterval.contains(cdate)));
+ static assert(__traits(compiles, iInterval.contains(cdate)));
+
+ //Verify Examples.
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Date(1994, 12, 24)));
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Date(2000, 1, 5)));
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Date(2012, 3, 1)));
+}
+
+//Test Interval's contains(Interval).
+unittest
+{
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+
+ assertThrown!DateTimeException(interval.contains(Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+ assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).contains(interval));
+ assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).contains(Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assert(interval.contains(interval));
+ assert(!interval.contains(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
+ assert(!interval.contains(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
+ assert(!interval.contains(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
+ assert(!interval.contains(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
+ assert(!interval.contains(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
+ assert(!interval.contains(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
+ assert(interval.contains(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
+ assert(interval.contains(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
+ assert(interval.contains(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
+ assert(!interval.contains(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
+ assert(!interval.contains(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
+ assert(!interval.contains(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
+
+ assert(!Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).contains(interval));
+ assert(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).contains(interval));
+ assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).contains(interval));
+ assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).contains(interval));
+ assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).contains(interval));
+ assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).contains(interval));
+ assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).contains(interval));
+ assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).contains(interval));
+ assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).contains(interval));
+ assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).contains(interval));
+ assert(!Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).contains(interval));
+ assert(!Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).contains(interval));
+
+ assert(!interval.contains(PosInfInterval!Date(Date(2010, 7, 3))));
+ assert(!interval.contains(PosInfInterval!Date(Date(2010, 7, 4))));
+ assert(!interval.contains(PosInfInterval!Date(Date(2010, 7, 5))));
+ assert(!interval.contains(PosInfInterval!Date(Date(2012, 1, 6))));
+ assert(!interval.contains(PosInfInterval!Date(Date(2012, 1, 7))));
+ assert(!interval.contains(PosInfInterval!Date(Date(2012, 1, 8))));
+
+ assert(!interval.contains(NegInfInterval!Date(Date(2010, 7, 3))));
+ assert(!interval.contains(NegInfInterval!Date(Date(2010, 7, 4))));
+ assert(!interval.contains(NegInfInterval!Date(Date(2010, 7, 5))));
+ assert(!interval.contains(NegInfInterval!Date(Date(2012, 1, 6))));
+ assert(!interval.contains(NegInfInterval!Date(Date(2012, 1, 7))));
+ assert(!interval.contains(NegInfInterval!Date(Date(2012, 1, 8))));
+
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, interval.contains(interval)));
+ static assert(__traits(compiles, interval.contains(cInterval)));
+ static assert(__traits(compiles, interval.contains(iInterval)));
+ static assert(__traits(compiles, interval.contains(posInfInterval)));
+ static assert(__traits(compiles, interval.contains(cPosInfInterval)));
+ static assert(__traits(compiles, interval.contains(iPosInfInterval)));
+ static assert(__traits(compiles, interval.contains(negInfInterval)));
+ static assert(__traits(compiles, interval.contains(cNegInfInterval)));
+ static assert(__traits(compiles, interval.contains(iNegInfInterval)));
+ static assert(__traits(compiles, cInterval.contains(interval)));
+ static assert(__traits(compiles, cInterval.contains(cInterval)));
+ static assert(__traits(compiles, cInterval.contains(iInterval)));
+ static assert(__traits(compiles, cInterval.contains(posInfInterval)));
+ static assert(__traits(compiles, cInterval.contains(cPosInfInterval)));
+ static assert(__traits(compiles, cInterval.contains(iPosInfInterval)));
+ static assert(__traits(compiles, cInterval.contains(negInfInterval)));
+ static assert(__traits(compiles, cInterval.contains(cNegInfInterval)));
+ static assert(__traits(compiles, cInterval.contains(iNegInfInterval)));
+ static assert(__traits(compiles, iInterval.contains(interval)));
+ static assert(__traits(compiles, iInterval.contains(cInterval)));
+ static assert(__traits(compiles, iInterval.contains(iInterval)));
+ static assert(__traits(compiles, iInterval.contains(posInfInterval)));
+ static assert(__traits(compiles, iInterval.contains(cPosInfInterval)));
+ static assert(__traits(compiles, iInterval.contains(iPosInfInterval)));
+ static assert(__traits(compiles, iInterval.contains(negInfInterval)));
+ static assert(__traits(compiles, iInterval.contains(cNegInfInterval)));
+ static assert(__traits(compiles, iInterval.contains(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(Interval!Date(Date(1998, 2, 28), Date(2013, 5, 1))));
+
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(PosInfInterval!Date(Date(1999, 5, 4))));
+
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).contains(NegInfInterval!Date(Date(1996, 5, 4))));
+}
+
+//Test Interval's isBefore(time point).
+unittest
+{
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+
+ assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).isBefore(Date(2010, 7, 4)));
+
+ assert(!interval.isBefore(Date(2009, 7, 3)));
+ assert(!interval.isBefore(Date(2010, 7, 3)));
+ assert(!interval.isBefore(Date(2010, 7, 4)));
+ assert(!interval.isBefore(Date(2010, 7, 5)));
+ assert(!interval.isBefore(Date(2011, 7, 1)));
+ assert(!interval.isBefore(Date(2012, 1, 6)));
+ assert(interval.isBefore(Date(2012, 1, 7)));
+ assert(interval.isBefore(Date(2012, 1, 8)));
+ assert(interval.isBefore(Date(2013, 1, 7)));
+
+ const cdate = Date(2010, 7, 6);
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ static assert(__traits(compiles, interval.isBefore(cdate)));
+ static assert(__traits(compiles, cInterval.isBefore(cdate)));
+ static assert(__traits(compiles, iInterval.isBefore(cdate)));
+
+ //Verify Examples.
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Date(1994, 12, 24)));
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Date(2000, 1, 5)));
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Date(2012, 3, 1)));
+}
+
+//Test Interval's isBefore(Interval).
+unittest
+{
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+
+ assertThrown!DateTimeException(interval.isBefore(Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+ assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).isBefore(interval));
+ assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).isBefore(Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assert(!interval.isBefore(interval));
+ assert(!interval.isBefore(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
+ assert(!interval.isBefore(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
+ assert(!interval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
+ assert(!interval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
+ assert(!interval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
+ assert(!interval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
+ assert(!interval.isBefore(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
+ assert(!interval.isBefore(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
+ assert(!interval.isBefore(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
+ assert(!interval.isBefore(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
+ assert(interval.isBefore(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
+ assert(interval.isBefore(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
+
+ assert(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).isBefore(interval));
+ assert(!Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).isBefore(interval));
+ assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).isBefore(interval));
+ assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).isBefore(interval));
+ assert(!Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).isBefore(interval));
+ assert(!Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).isBefore(interval));
+ assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).isBefore(interval));
+ assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).isBefore(interval));
+ assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).isBefore(interval));
+ assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).isBefore(interval));
+ assert(!Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).isBefore(interval));
+ assert(!Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).isBefore(interval));
+
+ assert(!interval.isBefore(PosInfInterval!Date(Date(2010, 7, 3))));
+ assert(!interval.isBefore(PosInfInterval!Date(Date(2010, 7, 4))));
+ assert(!interval.isBefore(PosInfInterval!Date(Date(2010, 7, 5))));
+ assert(!interval.isBefore(PosInfInterval!Date(Date(2012, 1, 6))));
+ assert(interval.isBefore(PosInfInterval!Date(Date(2012, 1, 7))));
+ assert(interval.isBefore(PosInfInterval!Date(Date(2012, 1, 8))));
+
+ assert(!interval.isBefore(NegInfInterval!Date(Date(2010, 7, 3))));
+ assert(!interval.isBefore(NegInfInterval!Date(Date(2010, 7, 4))));
+ assert(!interval.isBefore(NegInfInterval!Date(Date(2010, 7, 5))));
+ assert(!interval.isBefore(NegInfInterval!Date(Date(2012, 1, 6))));
+ assert(!interval.isBefore(NegInfInterval!Date(Date(2012, 1, 7))));
+ assert(!interval.isBefore(NegInfInterval!Date(Date(2012, 1, 8))));
+
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, interval.isBefore(interval)));
+ static assert(__traits(compiles, interval.isBefore(cInterval)));
+ static assert(__traits(compiles, interval.isBefore(iInterval)));
+ static assert(__traits(compiles, interval.isBefore(posInfInterval)));
+ static assert(__traits(compiles, interval.isBefore(cPosInfInterval)));
+ static assert(__traits(compiles, interval.isBefore(iPosInfInterval)));
+ static assert(__traits(compiles, interval.isBefore(negInfInterval)));
+ static assert(__traits(compiles, interval.isBefore(cNegInfInterval)));
+ static assert(__traits(compiles, interval.isBefore(iNegInfInterval)));
+ static assert(__traits(compiles, cInterval.isBefore(interval)));
+ static assert(__traits(compiles, cInterval.isBefore(cInterval)));
+ static assert(__traits(compiles, cInterval.isBefore(iInterval)));
+ static assert(__traits(compiles, cInterval.isBefore(posInfInterval)));
+ static assert(__traits(compiles, cInterval.isBefore(cPosInfInterval)));
+ static assert(__traits(compiles, cInterval.isBefore(iPosInfInterval)));
+ static assert(__traits(compiles, cInterval.isBefore(negInfInterval)));
+ static assert(__traits(compiles, cInterval.isBefore(cNegInfInterval)));
+ static assert(__traits(compiles, cInterval.isBefore(iNegInfInterval)));
+ static assert(__traits(compiles, iInterval.isBefore(interval)));
+ static assert(__traits(compiles, iInterval.isBefore(cInterval)));
+ static assert(__traits(compiles, iInterval.isBefore(iInterval)));
+ static assert(__traits(compiles, iInterval.isBefore(posInfInterval)));
+ static assert(__traits(compiles, iInterval.isBefore(cPosInfInterval)));
+ static assert(__traits(compiles, iInterval.isBefore(iPosInfInterval)));
+ static assert(__traits(compiles, iInterval.isBefore(negInfInterval)));
+ static assert(__traits(compiles, iInterval.isBefore(cNegInfInterval)));
+ static assert(__traits(compiles, iInterval.isBefore(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(Interval!Date(Date(2012, 3, 1), Date(2013, 5, 1))));
+
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(PosInfInterval!Date(Date(1999, 5, 4))));
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(PosInfInterval!Date(Date(2013, 3, 7))));
+
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isBefore(NegInfInterval!Date(Date(1996, 5, 4))));
+}
+
+//Test Interval's isAfter(time point).
+unittest
+{
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+
+ assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).isAfter(Date(2010, 7, 4)));
+
+ assert(interval.isAfter(Date(2009, 7, 4)));
+ assert(interval.isAfter(Date(2010, 7, 3)));
+ assert(!interval.isAfter(Date(2010, 7, 4)));
+ assert(!interval.isAfter(Date(2010, 7, 5)));
+ assert(!interval.isAfter(Date(2011, 7, 1)));
+ assert(!interval.isAfter(Date(2012, 1, 6)));
+ assert(!interval.isAfter(Date(2012, 1, 7)));
+ assert(!interval.isAfter(Date(2012, 1, 8)));
+ assert(!interval.isAfter(Date(2013, 1, 7)));
+
+ const cdate = Date(2010, 7, 6);
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ static assert(__traits(compiles, interval.isAfter(cdate)));
+ static assert(__traits(compiles, cInterval.isAfter(cdate)));
+ static assert(__traits(compiles, iInterval.isAfter(cdate)));
+
+ //Verify Examples.
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Date(1994, 12, 24)));
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Date(2000, 1, 5)));
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Date(2012, 3, 1)));
+}
+
+//Test Interval's isAfter(Interval).
+unittest
+{
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+
+ assertThrown!DateTimeException(interval.isAfter(Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+ assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).isAfter(interval));
+ assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).isAfter(Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assert(!interval.isAfter(interval));
+ assert(interval.isAfter(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
+ assert(!interval.isAfter(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
+ assert(interval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
+ assert(!interval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
+ assert(!interval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
+ assert(!interval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
+ assert(!interval.isAfter(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
+ assert(!interval.isAfter(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
+ assert(!interval.isAfter(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
+ assert(!interval.isAfter(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
+ assert(!interval.isAfter(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
+ assert(!interval.isAfter(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
+
+ assert(!Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).isAfter(interval));
+ assert(!Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).isAfter(interval));
+ assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).isAfter(interval));
+ assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).isAfter(interval));
+ assert(!Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).isAfter(interval));
+ assert(!Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).isAfter(interval));
+ assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).isAfter(interval));
+ assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).isAfter(interval));
+ assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).isAfter(interval));
+ assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).isAfter(interval));
+ assert(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).isAfter(interval));
+ assert(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).isAfter(interval));
+
+ assert(!interval.isAfter(PosInfInterval!Date(Date(2010, 7, 3))));
+ assert(!interval.isAfter(PosInfInterval!Date(Date(2010, 7, 4))));
+ assert(!interval.isAfter(PosInfInterval!Date(Date(2010, 7, 5))));
+ assert(!interval.isAfter(PosInfInterval!Date(Date(2012, 1, 6))));
+ assert(!interval.isAfter(PosInfInterval!Date(Date(2012, 1, 7))));
+ assert(!interval.isAfter(PosInfInterval!Date(Date(2012, 1, 8))));
+
+ assert(interval.isAfter(NegInfInterval!Date(Date(2010, 7, 3))));
+ assert(interval.isAfter(NegInfInterval!Date(Date(2010, 7, 4))));
+ assert(!interval.isAfter(NegInfInterval!Date(Date(2010, 7, 5))));
+ assert(!interval.isAfter(NegInfInterval!Date(Date(2012, 1, 6))));
+ assert(!interval.isAfter(NegInfInterval!Date(Date(2012, 1, 7))));
+ assert(!interval.isAfter(NegInfInterval!Date(Date(2012, 1, 8))));
+
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, interval.isAfter(interval)));
+ static assert(__traits(compiles, interval.isAfter(cInterval)));
+ static assert(__traits(compiles, interval.isAfter(iInterval)));
+ static assert(__traits(compiles, interval.isAfter(posInfInterval)));
+ static assert(__traits(compiles, interval.isAfter(cPosInfInterval)));
+ static assert(__traits(compiles, interval.isAfter(iPosInfInterval)));
+ static assert(__traits(compiles, interval.isAfter(negInfInterval)));
+ static assert(__traits(compiles, interval.isAfter(cNegInfInterval)));
+ static assert(__traits(compiles, interval.isAfter(iNegInfInterval)));
+ static assert(__traits(compiles, cInterval.isAfter(interval)));
+ static assert(__traits(compiles, cInterval.isAfter(cInterval)));
+ static assert(__traits(compiles, cInterval.isAfter(iInterval)));
+ static assert(__traits(compiles, cInterval.isAfter(posInfInterval)));
+ static assert(__traits(compiles, cInterval.isAfter(cPosInfInterval)));
+ static assert(__traits(compiles, cInterval.isAfter(iPosInfInterval)));
+ static assert(__traits(compiles, cInterval.isAfter(negInfInterval)));
+ static assert(__traits(compiles, cInterval.isAfter(cNegInfInterval)));
+ static assert(__traits(compiles, cInterval.isAfter(iNegInfInterval)));
+ static assert(__traits(compiles, iInterval.isAfter(interval)));
+ static assert(__traits(compiles, iInterval.isAfter(cInterval)));
+ static assert(__traits(compiles, iInterval.isAfter(iInterval)));
+ static assert(__traits(compiles, iInterval.isAfter(posInfInterval)));
+ static assert(__traits(compiles, iInterval.isAfter(cPosInfInterval)));
+ static assert(__traits(compiles, iInterval.isAfter(iPosInfInterval)));
+ static assert(__traits(compiles, iInterval.isAfter(negInfInterval)));
+ static assert(__traits(compiles, iInterval.isAfter(cNegInfInterval)));
+ static assert(__traits(compiles, iInterval.isAfter(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
+
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(PosInfInterval!Date(Date(1999, 5, 4))));
+
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAfter(NegInfInterval!Date(Date(1996, 1, 2))));
+}
+
+//Test Interval's intersects().
+unittest
+{
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+
+ assertThrown!DateTimeException(interval.intersects(Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+ assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).intersects(interval));
+ assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).intersects(Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assert(interval.intersects(interval));
+ assert(!interval.intersects(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
+ assert(interval.intersects(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
+ assert(!interval.intersects(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
+ assert(interval.intersects(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
+ assert(interval.intersects(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
+ assert(interval.intersects(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
+ assert(interval.intersects(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
+ assert(interval.intersects(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
+ assert(interval.intersects(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
+ assert(interval.intersects(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
+ assert(!interval.intersects(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
+ assert(!interval.intersects(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
+
+ assert(!Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).intersects(interval));
+ assert(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).intersects(interval));
+ assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).intersects(interval));
+ assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).intersects(interval));
+ assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).intersects(interval));
+ assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).intersects(interval));
+ assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).intersects(interval));
+ assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).intersects(interval));
+ assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).intersects(interval));
+ assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).intersects(interval));
+ assert(!Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).intersects(interval));
+ assert(!Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).intersects(interval));
+
+ assert(interval.intersects(PosInfInterval!Date(Date(2010, 7, 3))));
+ assert(interval.intersects(PosInfInterval!Date(Date(2010, 7, 4))));
+ assert(interval.intersects(PosInfInterval!Date(Date(2010, 7, 5))));
+ assert(interval.intersects(PosInfInterval!Date(Date(2012, 1, 6))));
+ assert(!interval.intersects(PosInfInterval!Date(Date(2012, 1, 7))));
+ assert(!interval.intersects(PosInfInterval!Date(Date(2012, 1, 8))));
+
+ assert(!interval.intersects(NegInfInterval!Date(Date(2010, 7, 3))));
+ assert(!interval.intersects(NegInfInterval!Date(Date(2010, 7, 4))));
+ assert(interval.intersects(NegInfInterval!Date(Date(2010, 7, 5))));
+ assert(interval.intersects(NegInfInterval!Date(Date(2012, 1, 6))));
+ assert(interval.intersects(NegInfInterval!Date(Date(2012, 1, 7))));
+ assert(interval.intersects(NegInfInterval!Date(Date(2012, 1, 8))));
+
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, interval.intersects(interval)));
+ static assert(__traits(compiles, interval.intersects(cInterval)));
+ static assert(__traits(compiles, interval.intersects(iInterval)));
+ static assert(__traits(compiles, interval.intersects(posInfInterval)));
+ static assert(__traits(compiles, interval.intersects(cPosInfInterval)));
+ static assert(__traits(compiles, interval.intersects(iPosInfInterval)));
+ static assert(__traits(compiles, interval.intersects(negInfInterval)));
+ static assert(__traits(compiles, interval.intersects(cNegInfInterval)));
+ static assert(__traits(compiles, interval.intersects(iNegInfInterval)));
+ static assert(__traits(compiles, cInterval.intersects(interval)));
+ static assert(__traits(compiles, cInterval.intersects(cInterval)));
+ static assert(__traits(compiles, cInterval.intersects(iInterval)));
+ static assert(__traits(compiles, cInterval.intersects(posInfInterval)));
+ static assert(__traits(compiles, cInterval.intersects(cPosInfInterval)));
+ static assert(__traits(compiles, cInterval.intersects(iPosInfInterval)));
+ static assert(__traits(compiles, cInterval.intersects(negInfInterval)));
+ static assert(__traits(compiles, cInterval.intersects(cNegInfInterval)));
+ static assert(__traits(compiles, cInterval.intersects(iNegInfInterval)));
+ static assert(__traits(compiles, iInterval.intersects(interval)));
+ static assert(__traits(compiles, iInterval.intersects(cInterval)));
+ static assert(__traits(compiles, iInterval.intersects(iInterval)));
+ static assert(__traits(compiles, iInterval.intersects(posInfInterval)));
+ static assert(__traits(compiles, iInterval.intersects(cPosInfInterval)));
+ static assert(__traits(compiles, iInterval.intersects(iPosInfInterval)));
+ static assert(__traits(compiles, iInterval.intersects(negInfInterval)));
+ static assert(__traits(compiles, iInterval.intersects(cNegInfInterval)));
+ static assert(__traits(compiles, iInterval.intersects(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
+
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(PosInfInterval!Date(Date(1999, 5, 4))));
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(PosInfInterval!Date(Date(2012, 3, 1))));
+
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(NegInfInterval!Date(Date(1996, 1, 2))));
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersects(NegInfInterval!Date(Date(2000, 1, 2))));
+}
+
+//Test Interval's intersection().
+unittest
+{
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+
+ assertThrown!DateTimeException(interval.intersection(Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+ assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).intersection(interval));
+ assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 4), dur!"days"(0)).intersection(Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assertThrown!DateTimeException(interval.intersection(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
+ assertThrown!DateTimeException(interval.intersection(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
+ assertThrown!DateTimeException(interval.intersection(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
+ assertThrown!DateTimeException(interval.intersection(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
+
+ assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).intersection(interval));
+ assertThrown!DateTimeException(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).intersection(interval));
+ assertThrown!DateTimeException(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).intersection(interval));
+ assertThrown!DateTimeException(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).intersection(interval));
+
+ assertThrown!DateTimeException(interval.intersection(PosInfInterval!Date(Date(2012, 1, 7))));
+ assertThrown!DateTimeException(interval.intersection(PosInfInterval!Date(Date(2012, 1, 8))));
+
+ assertThrown!DateTimeException(interval.intersection(NegInfInterval!Date(Date(2010, 7, 3))));
+ assertThrown!DateTimeException(interval.intersection(NegInfInterval!Date(Date(2010, 7, 4))));
+
+ assertPred!"=="(interval.intersection(interval), interval);
+ assertPred!"=="(interval.intersection(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(interval.intersection(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))),
+ Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5)));
+ assertPred!"=="(interval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(interval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(interval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))),
+ Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)));
+ assertPred!"=="(interval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))),
+ Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)));
+ assertPred!"=="(interval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))),
+ Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
+ assertPred!"=="(interval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))),
+ Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
+
+ assertPred!"=="(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).intersection(interval),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).intersection(interval),
+ Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5)));
+ assertPred!"=="(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).intersection(interval),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).intersection(interval),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).intersection(interval),
+ Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)));
+ assertPred!"=="(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).intersection(interval),
+ Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)));
+ assertPred!"=="(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).intersection(interval),
+ Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
+ assertPred!"=="(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).intersection(interval),
+ Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
+
+ assertPred!"=="(interval.intersection(PosInfInterval!Date(Date(2010, 7, 3))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(interval.intersection(PosInfInterval!Date(Date(2010, 7, 4))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(interval.intersection(PosInfInterval!Date(Date(2010, 7, 5))),
+ Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)));
+ assertPred!"=="(interval.intersection(PosInfInterval!Date(Date(2012, 1, 6))),
+ Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
+
+ assertPred!"=="(interval.intersection(NegInfInterval!Date(Date(2010, 7, 5))),
+ Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5)));
+ assertPred!"=="(interval.intersection(NegInfInterval!Date(Date(2012, 1, 6))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 6)));
+ assertPred!"=="(interval.intersection(NegInfInterval!Date(Date(2012, 1, 7))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(interval.intersection(NegInfInterval!Date(Date(2012, 1, 8))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, interval.intersection(interval)));
+ static assert(__traits(compiles, interval.intersection(cInterval)));
+ static assert(__traits(compiles, interval.intersection(iInterval)));
+ static assert(__traits(compiles, interval.intersection(posInfInterval)));
+ static assert(__traits(compiles, interval.intersection(cPosInfInterval)));
+ static assert(__traits(compiles, interval.intersection(iPosInfInterval)));
+ static assert(__traits(compiles, interval.intersection(negInfInterval)));
+ static assert(__traits(compiles, interval.intersection(cNegInfInterval)));
+ static assert(__traits(compiles, interval.intersection(iNegInfInterval)));
+ static assert(__traits(compiles, cInterval.intersection(interval)));
+ static assert(__traits(compiles, cInterval.intersection(cInterval)));
+ static assert(__traits(compiles, cInterval.intersection(iInterval)));
+ static assert(__traits(compiles, cInterval.intersection(posInfInterval)));
+ static assert(__traits(compiles, cInterval.intersection(cPosInfInterval)));
+ static assert(__traits(compiles, cInterval.intersection(iPosInfInterval)));
+ static assert(__traits(compiles, cInterval.intersection(negInfInterval)));
+ static assert(__traits(compiles, cInterval.intersection(cNegInfInterval)));
+ static assert(__traits(compiles, cInterval.intersection(iNegInfInterval)));
+ static assert(__traits(compiles, iInterval.intersection(interval)));
+ static assert(__traits(compiles, iInterval.intersection(cInterval)));
+ static assert(__traits(compiles, iInterval.intersection(iInterval)));
+ static assert(__traits(compiles, iInterval.intersection(posInfInterval)));
+ static assert(__traits(compiles, iInterval.intersection(cPosInfInterval)));
+ static assert(__traits(compiles, iInterval.intersection(iPosInfInterval)));
+ static assert(__traits(compiles, iInterval.intersection(negInfInterval)));
+ static assert(__traits(compiles, iInterval.intersection(cNegInfInterval)));
+ static assert(__traits(compiles, iInterval.intersection(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == Interval!Date(Date(1996, 1 , 2), Date(2000, 8, 2)));
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) == Interval!Date(Date(1999, 1 , 12), Date(2011, 9, 17)));
+
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(PosInfInterval!Date(Date(1990, 7, 6))) == Interval!Date(Date(1996, 1 , 2), Date(2012, 3, 1)));
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(PosInfInterval!Date(Date(1999, 1, 12))) == Interval!Date(Date(1999, 1 , 12), Date(2012, 3, 1)));
+
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(NegInfInterval!Date(Date(1999, 7, 6))) == Interval!Date(Date(1996, 1 , 2), Date(1999, 7, 6)));
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).intersection(NegInfInterval!Date(Date(2013, 1, 12))) == Interval!Date(Date(1996, 1 , 2), Date(2012, 3, 1)));
+}
+
+//Test Interval's isAdjacent().
+unittest
+{
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+
+ static void testInterval(in Interval!Date interval1, in Interval!Date interval2)
+ {
+ interval1.isAdjacent(interval2);
+ }
+
+ assertThrown!DateTimeException(testInterval(interval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+ assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), interval));
+ assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assert(!interval.isAdjacent(interval));
+ assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
+ assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
+ assert(interval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
+ assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
+ assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
+ assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
+ assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
+ assert(!interval.isAdjacent(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
+ assert(!interval.isAdjacent(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
+ assert(!interval.isAdjacent(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
+ assert(interval.isAdjacent(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
+ assert(!interval.isAdjacent(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
+
+ assert(!Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).isAdjacent(interval));
+ assert(!Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).isAdjacent(interval));
+ assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).isAdjacent(interval));
+ assert(!Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).isAdjacent(interval));
+ assert(!Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).isAdjacent(interval));
+ assert(!Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).isAdjacent(interval));
+ assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).isAdjacent(interval));
+ assert(!Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).isAdjacent(interval));
+ assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).isAdjacent(interval));
+ assert(!Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).isAdjacent(interval));
+ assert(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).isAdjacent(interval));
+ assert(!Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).isAdjacent(interval));
+
+ assert(!interval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 3))));
+ assert(!interval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 4))));
+ assert(!interval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 5))));
+ assert(!interval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 6))));
+ assert(interval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 7))));
+ assert(!interval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 8))));
+
+ assert(!interval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 3))));
+ assert(interval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 4))));
+ assert(!interval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 5))));
+ assert(!interval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 6))));
+ assert(!interval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 7))));
+ assert(!interval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 8))));
+
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, interval.isAdjacent(interval)));
+ static assert(__traits(compiles, interval.isAdjacent(cInterval)));
+ static assert(__traits(compiles, interval.isAdjacent(iInterval)));
+ static assert(__traits(compiles, interval.isAdjacent(posInfInterval)));
+ static assert(__traits(compiles, interval.isAdjacent(cPosInfInterval)));
+ static assert(__traits(compiles, interval.isAdjacent(iPosInfInterval)));
+ static assert(__traits(compiles, interval.isAdjacent(negInfInterval)));
+ static assert(__traits(compiles, interval.isAdjacent(cNegInfInterval)));
+ static assert(__traits(compiles, interval.isAdjacent(iNegInfInterval)));
+ static assert(__traits(compiles, cInterval.isAdjacent(interval)));
+ static assert(__traits(compiles, cInterval.isAdjacent(cInterval)));
+ static assert(__traits(compiles, cInterval.isAdjacent(iInterval)));
+ static assert(__traits(compiles, cInterval.isAdjacent(posInfInterval)));
+ static assert(__traits(compiles, cInterval.isAdjacent(cPosInfInterval)));
+ static assert(__traits(compiles, cInterval.isAdjacent(iPosInfInterval)));
+ static assert(__traits(compiles, cInterval.isAdjacent(negInfInterval)));
+ static assert(__traits(compiles, cInterval.isAdjacent(cNegInfInterval)));
+ static assert(__traits(compiles, cInterval.isAdjacent(iNegInfInterval)));
+ static assert(__traits(compiles, iInterval.isAdjacent(interval)));
+ static assert(__traits(compiles, iInterval.isAdjacent(cInterval)));
+ static assert(__traits(compiles, iInterval.isAdjacent(iInterval)));
+ static assert(__traits(compiles, iInterval.isAdjacent(posInfInterval)));
+ static assert(__traits(compiles, iInterval.isAdjacent(cPosInfInterval)));
+ static assert(__traits(compiles, iInterval.isAdjacent(iPosInfInterval)));
+ static assert(__traits(compiles, iInterval.isAdjacent(negInfInterval)));
+ static assert(__traits(compiles, iInterval.isAdjacent(cNegInfInterval)));
+ static assert(__traits(compiles, iInterval.isAdjacent(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(1990, 7, 6), Date(1996, 1, 2))));
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(2012, 3, 1), Date(2013, 9, 17))));
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(1989, 3, 1), Date(2012, 3, 1))));
+
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(PosInfInterval!Date(Date(1999, 5, 4))));
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(PosInfInterval!Date(Date(2012, 3, 1))));
+
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(NegInfInterval!Date(Date(1996, 1, 2))));
+ assert(!Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).isAdjacent(NegInfInterval!Date(Date(2000, 1, 2))));
+}
+
+//Test Interval's merge().
+unittest
+{
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+
+ static void testInterval(I)(in Interval!Date interval1, in I interval2)
+ {
+ interval1.merge(interval2);
+ }
+
+ assertThrown!DateTimeException(testInterval(interval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+ assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), interval));
+ assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assertThrown!DateTimeException(testInterval(interval, Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
+ assertThrown!DateTimeException(testInterval(interval, Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
+
+ assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)), interval));
+ assertThrown!DateTimeException(testInterval(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)), interval));
+
+ assertThrown!DateTimeException(testInterval(interval, PosInfInterval!Date(Date(2012, 1, 8))));
+
+ assertThrown!DateTimeException(testInterval(interval, NegInfInterval!Date(Date(2010, 7, 3))));
+
+ assertPred!"=="(interval.merge(interval), interval);
+ assertPred!"=="(interval.merge(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))),
+ Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)));
+ assertPred!"=="(interval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))),
+ Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
+ assertPred!"=="(interval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))),
+ Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
+ assertPred!"=="(interval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))),
+ Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
+ assertPred!"=="(interval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))),
+ Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)));
+ assertPred!"=="(interval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(interval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(interval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(interval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
+ assertPred!"=="(interval.merge(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
+
+ assertPred!"=="(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).merge(interval),
+ Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)));
+ assertPred!"=="(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).merge(interval),
+ Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
+ assertPred!"=="(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).merge(interval),
+ Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
+ assertPred!"=="(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).merge(interval),
+ Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
+ assertPred!"=="(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).merge(interval),
+ Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)));
+ assertPred!"=="(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).merge(interval),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).merge(interval),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).merge(interval),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).merge(interval),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
+ assertPred!"=="(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).merge(interval),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
+
+ assertPred!"=="(interval.merge(PosInfInterval!Date(Date(2010, 7, 3))),
+ PosInfInterval!Date(Date(2010, 7, 3)));
+ assertPred!"=="(interval.merge(PosInfInterval!Date(Date(2010, 7, 4))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(interval.merge(PosInfInterval!Date(Date(2010, 7, 5))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(interval.merge(PosInfInterval!Date(Date(2012, 1, 6))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(interval.merge(PosInfInterval!Date(Date(2012, 1, 7))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+
+ assertPred!"=="(interval.merge(NegInfInterval!Date(Date(2010, 7, 4))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(interval.merge(NegInfInterval!Date(Date(2010, 7, 5))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(interval.merge(NegInfInterval!Date(Date(2012, 1, 6))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(interval.merge(NegInfInterval!Date(Date(2012, 1, 7))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(interval.merge(NegInfInterval!Date(Date(2012, 1, 8))),
+ NegInfInterval!Date(Date(2012, 1, 8)));
+
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, interval.merge(interval)));
+ static assert(__traits(compiles, interval.merge(cInterval)));
+ static assert(__traits(compiles, interval.merge(iInterval)));
+ static assert(__traits(compiles, interval.merge(posInfInterval)));
+ static assert(__traits(compiles, interval.merge(cPosInfInterval)));
+ static assert(__traits(compiles, interval.merge(iPosInfInterval)));
+ static assert(__traits(compiles, interval.merge(negInfInterval)));
+ static assert(__traits(compiles, interval.merge(cNegInfInterval)));
+ static assert(__traits(compiles, interval.merge(iNegInfInterval)));
+ static assert(__traits(compiles, cInterval.merge(interval)));
+ static assert(__traits(compiles, cInterval.merge(cInterval)));
+ static assert(__traits(compiles, cInterval.merge(iInterval)));
+ static assert(__traits(compiles, cInterval.merge(posInfInterval)));
+ static assert(__traits(compiles, cInterval.merge(cPosInfInterval)));
+ static assert(__traits(compiles, cInterval.merge(iPosInfInterval)));
+ static assert(__traits(compiles, cInterval.merge(negInfInterval)));
+ static assert(__traits(compiles, cInterval.merge(cNegInfInterval)));
+ static assert(__traits(compiles, cInterval.merge(iNegInfInterval)));
+ static assert(__traits(compiles, iInterval.merge(interval)));
+ static assert(__traits(compiles, iInterval.merge(cInterval)));
+ static assert(__traits(compiles, iInterval.merge(iInterval)));
+ static assert(__traits(compiles, iInterval.merge(posInfInterval)));
+ static assert(__traits(compiles, iInterval.merge(cPosInfInterval)));
+ static assert(__traits(compiles, iInterval.merge(iPosInfInterval)));
+ static assert(__traits(compiles, iInterval.merge(negInfInterval)));
+ static assert(__traits(compiles, iInterval.merge(cNegInfInterval)));
+ static assert(__traits(compiles, iInterval.merge(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == Interval!Date(Date(1990, 7 , 6), Date(2012, 3, 1)));
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(Interval!Date(Date(2012, 3, 1), Date(2013, 5, 7))) == Interval!Date(Date(1996, 1 , 2), Date(2013, 5, 7)));
+
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1990, 7 , 6)));
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(PosInfInterval!Date(Date(2012, 3, 1))) == PosInfInterval!Date(Date(1996, 1 , 2)));
+
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(NegInfInterval!Date(Date(1996, 1, 2))) == NegInfInterval!Date(Date(2012, 3 , 1)));
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).merge(NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2013, 1 , 12)));
+}
+
+//Test Interval's span().
+unittest
+{
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+
+ static void testInterval(in Interval!Date interval1, in Interval!Date interval2)
+ {
+ interval1.span(interval2);
+ }
+
+ assertThrown!DateTimeException(testInterval(interval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+ assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), interval));
+ assertThrown!DateTimeException(testInterval(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assertPred!"=="(interval.span(interval), interval);
+ assertPred!"=="(interval.span(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))),
+ Interval!Date(Date(2010, 7, 1), Date(2012, 1, 7)));
+ assertPred!"=="(interval.span(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))),
+ Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)));
+ assertPred!"=="(interval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))),
+ Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
+ assertPred!"=="(interval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))),
+ Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
+ assertPred!"=="(interval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))),
+ Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
+ assertPred!"=="(interval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))),
+ Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)));
+ assertPred!"=="(interval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(interval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(interval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(interval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
+ assertPred!"=="(interval.span(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
+ assertPred!"=="(interval.span(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 9)));
+
+ assertPred!"=="(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).span(interval),
+ Interval!Date(Date(2010, 7, 1), Date(2012, 1, 7)));
+ assertPred!"=="(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).span(interval),
+ Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)));
+ assertPred!"=="(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).span(interval),
+ Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
+ assertPred!"=="(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).span(interval),
+ Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
+ assertPred!"=="(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).span(interval),
+ Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
+ assertPred!"=="(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).span(interval),
+ Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)));
+ assertPred!"=="(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).span(interval),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).span(interval),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).span(interval),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).span(interval),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
+ assertPred!"=="(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).span(interval),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
+ assertPred!"=="(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).span(interval),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 9)));
+
+ assertPred!"=="(interval.span(PosInfInterval!Date(Date(2010, 7, 3))),
+ PosInfInterval!Date(Date(2010, 7, 3)));
+ assertPred!"=="(interval.span(PosInfInterval!Date(Date(2010, 7, 4))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(interval.span(PosInfInterval!Date(Date(2010, 7, 5))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(interval.span(PosInfInterval!Date(Date(2012, 1, 6))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(interval.span(PosInfInterval!Date(Date(2012, 1, 7))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(interval.span(PosInfInterval!Date(Date(2012, 1, 8))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+
+ assertPred!"=="(interval.span(NegInfInterval!Date(Date(2010, 7, 3))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(interval.span(NegInfInterval!Date(Date(2010, 7, 4))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(interval.span(NegInfInterval!Date(Date(2010, 7, 5))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(interval.span(NegInfInterval!Date(Date(2012, 1, 6))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(interval.span(NegInfInterval!Date(Date(2012, 1, 7))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(interval.span(NegInfInterval!Date(Date(2012, 1, 8))),
+ NegInfInterval!Date(Date(2012, 1, 8)));
+
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, interval.span(interval)));
+ static assert(__traits(compiles, interval.span(cInterval)));
+ static assert(__traits(compiles, interval.span(iInterval)));
+ static assert(__traits(compiles, interval.span(posInfInterval)));
+ static assert(__traits(compiles, interval.span(cPosInfInterval)));
+ static assert(__traits(compiles, interval.span(iPosInfInterval)));
+ static assert(__traits(compiles, interval.span(negInfInterval)));
+ static assert(__traits(compiles, interval.span(cNegInfInterval)));
+ static assert(__traits(compiles, interval.span(iNegInfInterval)));
+ static assert(__traits(compiles, cInterval.span(interval)));
+ static assert(__traits(compiles, cInterval.span(cInterval)));
+ static assert(__traits(compiles, cInterval.span(iInterval)));
+ static assert(__traits(compiles, cInterval.span(posInfInterval)));
+ static assert(__traits(compiles, cInterval.span(cPosInfInterval)));
+ static assert(__traits(compiles, cInterval.span(iPosInfInterval)));
+ static assert(__traits(compiles, cInterval.span(negInfInterval)));
+ static assert(__traits(compiles, cInterval.span(cNegInfInterval)));
+ static assert(__traits(compiles, cInterval.span(iNegInfInterval)));
+ static assert(__traits(compiles, iInterval.span(interval)));
+ static assert(__traits(compiles, iInterval.span(cInterval)));
+ static assert(__traits(compiles, iInterval.span(iInterval)));
+ static assert(__traits(compiles, iInterval.span(posInfInterval)));
+ static assert(__traits(compiles, iInterval.span(cPosInfInterval)));
+ static assert(__traits(compiles, iInterval.span(iPosInfInterval)));
+ static assert(__traits(compiles, iInterval.span(negInfInterval)));
+ static assert(__traits(compiles, iInterval.span(cNegInfInterval)));
+ static assert(__traits(compiles, iInterval.span(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(Interval!Date(Date(1990, 7, 6), Date(1991, 1, 8))) == Interval!Date(Date(1990, 7 , 6), Date(2012, 3, 1)));
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(Interval!Date(Date(2012, 3, 1), Date(2013, 5, 7))) == Interval!Date(Date(1996, 1 , 2), Date(2013, 5, 7)));
+
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1990, 7 , 6)));
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(PosInfInterval!Date(Date(2050, 1, 1))) == PosInfInterval!Date(Date(1996, 1 , 2)));
+
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(NegInfInterval!Date(Date(1602, 5, 21))) == NegInfInterval!Date(Date(2012, 3 , 1)));
+ assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).span(NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2013, 1 , 12)));
+}
+
+//Test Interval's shift(duration).
+unittest
+{
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+
+ static void testIntervalFail(Interval!Date interval, in Duration duration)
+ {
+ interval.shift(duration);
+ }
+
+ assertThrown!DateTimeException(testIntervalFail(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), dur!"days"(1)));
+
+ static void testInterval(I)(I interval, in Duration duration, in I expected, size_t line = __LINE__)
+ {
+ interval.shift(duration);
+ assertPred!"=="(interval, expected, "", __FILE__, line);
+ }
+
+ testInterval(interval, dur!"days"(22), Interval!Date(Date(2010, 7, 26), Date(2012, 1, 29)));
+ testInterval(interval, dur!"days"(-22), Interval!Date(Date(2010, 6, 12), Date(2011, 12, 16)));
+
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ static assert(!__traits(compiles, cInterval.shift(dur!"days"(5))));
+ static assert(!__traits(compiles, iInterval.shift(dur!"days"(5))));
+
+ //Verify Examples.
+ auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 4, 5));
+ auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 4, 5));
+
+ interval1.shift(dur!"days"(50));
+ assert(interval1 == Interval!Date(Date(1996, 2, 21), Date(2012, 5, 25)));
+
+ interval2.shift(dur!"days"(-50));
+ assert(interval2 == Interval!Date(Date(1995, 11, 13), Date(2012, 2, 15)));
+}
+
+//Test Interval's shift(int, int, AllowDayOverflow).
+unittest
+{
+ {
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+
+ static void testIntervalFail(Interval!Date interval, int years, int months)
+ {
+ interval.shift(years, months);
+ }
+
+ assertThrown!DateTimeException(testIntervalFail(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), 1, 0));
+
+ static void testInterval(I)(I interval, int years, int months, AllowDayOverflow allow, in I expected, size_t line = __LINE__)
+ {
+ interval.shift(years, months, allow);
+ assertPred!"=="(interval, expected, "", __FILE__, line);
+ }
+
+ testInterval(interval, 5, 0, AllowDayOverflow.yes, Interval!Date(Date(2015, 7, 4), Date(2017, 1, 7)));
+ testInterval(interval, -5, 0, AllowDayOverflow.yes, Interval!Date(Date(2005, 7, 4), Date(2007, 1, 7)));
+
+ auto interval2 = Interval!Date(Date(2000, 1, 29), Date(2010, 5, 31));
+
+ testInterval(interval2, 1, 1, AllowDayOverflow.yes, Interval!Date(Date(2001, 3, 1), Date(2011, 7, 1)));
+ testInterval(interval2, 1, -1, AllowDayOverflow.yes, Interval!Date(Date(2000, 12, 29), Date(2011, 5, 1)));
+ testInterval(interval2, -1, -1, AllowDayOverflow.yes, Interval!Date(Date(1998, 12, 29), Date(2009, 5, 1)));
+ testInterval(interval2, -1, 1, AllowDayOverflow.yes, Interval!Date(Date(1999, 3, 1), Date(2009, 7, 1)));
+
+ testInterval(interval2, 1, 1, AllowDayOverflow.no, Interval!Date(Date(2001, 2, 28), Date(2011, 6, 30)));
+ testInterval(interval2, 1, -1, AllowDayOverflow.no, Interval!Date(Date(2000, 12, 29), Date(2011, 4, 30)));
+ testInterval(interval2, -1, -1, AllowDayOverflow.no, Interval!Date(Date(1998, 12, 29), Date(2009, 4, 30)));
+ testInterval(interval2, -1, 1, AllowDayOverflow.no, Interval!Date(Date(1999, 2, 28), Date(2009, 6, 30)));
+ }
+
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ static assert(!__traits(compiles, cInterval.shift(5)));
+ static assert(!__traits(compiles, iInterval.shift(5)));
+
+ //Verify Examples.
+ auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
+ auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
+
+ interval1.shift(2);
+ assert(interval1 == Interval!Date(Date(1998, 1, 2), Date(2014, 3, 1)));
+
+ interval2.shift(-2);
+ assert(interval2 == Interval!Date(Date(1994, 1, 2), Date(2010, 3, 1)));
+}
+
+//Test Interval's expand(Duration).
+unittest
+{
+ auto interval = Interval!Date(Date(2000, 7, 4), Date(2012, 1, 7));
+
+ static void testIntervalFail(I)(I interval, in Duration duration)
+ {
+ interval.expand(duration);
+ }
+
+ assertThrown!DateTimeException(testIntervalFail(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), dur!"days"(1)));
+ assertThrown!DateTimeException(testIntervalFail(Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5)), dur!"days"(-5)));
+
+ static void testInterval(I)(I interval, in Duration duration, in I expected, size_t line = __LINE__)
+ {
+ interval.expand(duration);
+ assertPred!"=="(interval, expected, "", __FILE__, line);
+ }
+
+ testInterval(interval, dur!"days"(22), Interval!Date(Date(2000, 6, 12), Date(2012, 1, 29)));
+ testInterval(interval, dur!"days"(-22), Interval!Date(Date(2000, 7, 26), Date(2011, 12, 16)));
+
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ static assert(!__traits(compiles, cInterval.expand(dur!"days"(5))));
+ static assert(!__traits(compiles, iInterval.expand(dur!"days"(5))));
+
+ //Verify Examples.
+ auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
+ auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
+
+ interval1.expand(dur!"days"(2));
+ assert(interval1 == Interval!Date(Date(1995, 12, 31), Date(2012, 3, 3)));
+
+ interval2.expand(dur!"days"(-2));
+ assert(interval2 == Interval!Date(Date(1996, 1, 4), Date(2012, 2, 28)));
+}
+
+//Test Interval's expand(int, int, AllowDayOverflow, Direction)
+unittest
+{
+ {
+ auto interval = Interval!Date(Date(2000, 7, 4), Date(2012, 1, 7));
+
+ static void testIntervalFail(Interval!Date interval, int years, int months)
+ {
+ interval.expand(years, months);
+ }
+
+ assertThrown!DateTimeException(testIntervalFail(Interval!Date(Date(2010, 7, 4), dur!"days"(0)), 1, 0));
+ assertThrown!DateTimeException(testIntervalFail(Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)), -5, 0));
+
+ static void testInterval(I)(I interval, int years, int months, AllowDayOverflow allow, Direction dir, in I expected, size_t line = __LINE__)
+ {
+ interval.expand(years, months, allow, dir);
+ assertPred!"=="(interval, expected, "", __FILE__, line);
+ }
+
+ testInterval(interval, 5, 0, AllowDayOverflow.yes, Direction.both, Interval!Date(Date(1995, 7, 4), Date(2017, 1, 7)));
+ testInterval(interval, -5, 0, AllowDayOverflow.yes, Direction.both, Interval!Date(Date(2005, 7, 4), Date(2007, 1, 7)));
+
+ testInterval(interval, 5, 0, AllowDayOverflow.yes, Direction.fwd, Interval!Date(Date(2000, 7, 4), Date(2017, 1, 7)));
+ testInterval(interval, -5, 0, AllowDayOverflow.yes, Direction.fwd, Interval!Date(Date(2000, 7, 4), Date(2007, 1, 7)));
+
+ testInterval(interval, 5, 0, AllowDayOverflow.yes, Direction.bwd, Interval!Date(Date(1995, 7, 4), Date(2012, 1, 7)));
+ testInterval(interval, -5, 0, AllowDayOverflow.yes, Direction.bwd, Interval!Date(Date(2005, 7, 4), Date(2012, 1, 7)));
+
+ auto interval2 = Interval!Date(Date(2000, 1, 29), Date(2010, 5, 31));
+
+ testInterval(interval2, 1, 1, AllowDayOverflow.yes, Direction.both, Interval!Date(Date(1998, 12, 29), Date(2011, 7, 1)));
+ testInterval(interval2, 1, -1, AllowDayOverflow.yes, Direction.both, Interval!Date(Date(1999, 3, 1), Date(2011, 5, 1)));
+ testInterval(interval2, -1, -1, AllowDayOverflow.yes, Direction.both, Interval!Date(Date(2001, 3, 1), Date(2009, 5, 1)));
+ testInterval(interval2, -1, 1, AllowDayOverflow.yes, Direction.both, Interval!Date(Date(2000, 12, 29), Date(2009, 7, 1)));
+
+ testInterval(interval2, 1, 1, AllowDayOverflow.no, Direction.both, Interval!Date(Date(1998, 12, 29), Date(2011, 6, 30)));
+ testInterval(interval2, 1, -1, AllowDayOverflow.no, Direction.both, Interval!Date(Date(1999, 2, 28), Date(2011, 4, 30)));
+ testInterval(interval2, -1, -1, AllowDayOverflow.no, Direction.both, Interval!Date(Date(2001, 2, 28), Date(2009, 4, 30)));
+ testInterval(interval2, -1, 1, AllowDayOverflow.no, Direction.both, Interval!Date(Date(2000, 12, 29), Date(2009, 6, 30)));
+
+ testInterval(interval2, 1, 1, AllowDayOverflow.yes, Direction.fwd, Interval!Date(Date(2000, 1, 29), Date(2011, 7, 1)));
+ testInterval(interval2, 1, -1, AllowDayOverflow.yes, Direction.fwd, Interval!Date(Date(2000, 1, 29), Date(2011, 5, 1)));
+ testInterval(interval2, -1, -1, AllowDayOverflow.yes, Direction.fwd, Interval!Date(Date(2000, 1, 29), Date(2009, 5, 1)));
+ testInterval(interval2, -1, 1, AllowDayOverflow.yes, Direction.fwd, Interval!Date(Date(2000, 1, 29), Date(2009, 7, 1)));
+
+ testInterval(interval2, 1, 1, AllowDayOverflow.no, Direction.fwd, Interval!Date(Date(2000, 1, 29), Date(2011, 6, 30)));
+ testInterval(interval2, 1, -1, AllowDayOverflow.no, Direction.fwd, Interval!Date(Date(2000, 1, 29), Date(2011, 4, 30)));
+ testInterval(interval2, -1, -1, AllowDayOverflow.no, Direction.fwd, Interval!Date(Date(2000, 1, 29), Date(2009, 4, 30)));
+ testInterval(interval2, -1, 1, AllowDayOverflow.no, Direction.fwd, Interval!Date(Date(2000, 1, 29), Date(2009, 6, 30)));
+
+ testInterval(interval2, 1, 1, AllowDayOverflow.yes, Direction.bwd, Interval!Date(Date(1998, 12, 29), Date(2010, 5, 31)));
+ testInterval(interval2, 1, -1, AllowDayOverflow.yes, Direction.bwd, Interval!Date(Date(1999, 3, 1), Date(2010, 5, 31)));
+ testInterval(interval2, -1, -1, AllowDayOverflow.yes, Direction.bwd, Interval!Date(Date(2001, 3, 1), Date(2010, 5, 31)));
+ testInterval(interval2, -1, 1, AllowDayOverflow.yes, Direction.bwd, Interval!Date(Date(2000, 12, 29), Date(2010, 5, 31)));
+
+ testInterval(interval2, 1, 1, AllowDayOverflow.no, Direction.bwd, Interval!Date(Date(1998, 12, 29), Date(2010, 5, 31)));
+ testInterval(interval2, 1, -1, AllowDayOverflow.no, Direction.bwd, Interval!Date(Date(1999, 2, 28), Date(2010, 5, 31)));
+ testInterval(interval2, -1, -1, AllowDayOverflow.no, Direction.bwd, Interval!Date(Date(2001, 2, 28), Date(2010, 5, 31)));
+ testInterval(interval2, -1, 1, AllowDayOverflow.no, Direction.bwd, Interval!Date(Date(2000, 12, 29), Date(2010, 5, 31)));
+ }
+
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ static assert(!__traits(compiles, cInterval.expand(5)));
+ static assert(!__traits(compiles, iInterval.expand(5)));
+
+ //Verify Examples.
+ auto interval1 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
+ auto interval2 = Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1));
+
+ interval1.expand(2);
+ assert(interval1 == Interval!Date(Date(1994, 1, 2), Date(2014, 3, 1)));
+
+ interval2.expand(-2);
+ assert(interval2 == Interval!Date(Date(1998, 1, 2), Date(2010, 3, 1)));
+}
+
+//Test Interval's fwdRange.
+unittest
+{
+ {
+ auto interval = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 21));
+
+ static void testInterval1(Interval!Date interval)
+ {
+ interval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri));
+ }
+
+ assertThrown!DateTimeException(testInterval1(Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ static void testInterval2(Interval!Date interval)
+ {
+ interval.fwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).popFront();
+ }
+
+ assertThrown!DateTimeException(testInterval2(interval));
+
+ assert(!interval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).empty);
+ assert(interval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri), PopFirst.yes).empty);
+
+ assertPred!"=="(Interval!Date(Date(2010, 9, 12), Date(2010, 10, 1)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).front,
+ Date(2010, 9, 12));
+
+ assertPred!"=="(Interval!Date(Date(2010, 9, 12), Date(2010, 10, 1)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri), PopFirst.yes).front,
+ Date(2010, 9, 17));
+ }
+
+ //Verify Examples.
+ {
+ auto interval = Interval!Date(Date(2010, 9, 1), Date(2010, 9, 9));
+ auto func = (in Date date)
+ {
+ if((date.day & 1) == 0)
+ return date + dur!"days"(2);
+
+ return date + dur!"days"(1);
+ };
+ auto range = interval.fwdRange(func);
+
+ assert(range.front == Date(2010, 9, 1)); //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 2).
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 2));
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 4));
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 6));
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 8));
+
+ range.popFront();
+ assert(range.empty);
+ }
+
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ static assert(__traits(compiles, cInterval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri))));
+ static assert(__traits(compiles, iInterval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri))));
+}
+
+//Test Interval's bwdRange.
+unittest
+{
+ {
+ auto interval = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 21));
+
+ static void testInterval1(Interval!Date interval)
+ {
+ interval.bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri));
+ }
+
+ assertThrown!DateTimeException(testInterval1(Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ static void testInterval2(Interval!Date interval)
+ {
+ interval.bwdRange(everyDayOfWeek!(Date, Direction.fwd)(DayOfWeek.fri)).popFront();
+ }
+
+ assertThrown!DateTimeException(testInterval2(interval));
+
+ assert(!interval.bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).empty);
+ assert(interval.bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri), PopFirst.yes).empty);
+
+ assertPred!"=="(Interval!Date(Date(2010, 9, 19), Date(2010, 10, 1)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).front,
+ Date(2010, 10, 1));
+
+ assertPred!"=="(Interval!Date(Date(2010, 9, 19), Date(2010, 10, 1)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri), PopFirst.yes).front,
+ Date(2010, 9, 24));
+ }
+
+ //Verify Examples.
+ {
+ auto interval = Interval!Date(Date(2010, 9, 1), Date(2010, 9, 9));
+ auto func = (in Date date)
+ {
+ if((date.day & 1) == 0)
+ return date - dur!"days"(2);
+
+ return date - dur!"days"(1);
+ };
+ auto range = interval.bwdRange(func);
+
+ assert(range.front == Date(2010, 9, 9)); //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 8).
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 8));
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 6));
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 4));
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 2));
+
+ range.popFront();
+ assert(range.empty);
+ }
+
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ static assert(__traits(compiles, cInterval.bwdRange(everyDayOfWeek!Date(DayOfWeek.fri))));
+ static assert(__traits(compiles, iInterval.bwdRange(everyDayOfWeek!Date(DayOfWeek.fri))));
+}
+
+//Test Interval's toString().
+unittest
+{
+ assertPred!"=="(Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).toString(), "[2010-Jul-04 - 2012-Jan-07)");
+
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ static assert(__traits(compiles, cInterval.toString()));
+ static assert(__traits(compiles, iInterval.toString()));
+}
+
+
+/++
+ Represents an interval of time which has positive infinity as its end point.
+
+ Any ranges which iterate over a $(D PosInfInterval) are infinite. So, the
+ main purpose of using $(D PosInfInterval) is to create an infinite range
+ which starts at a fixed point in time and goes to positive infinity.
+ +/
+struct PosInfInterval(TP)
+{
+public:
+
+ /++
+ Params:
+ begin = The time point which begins the interval.
+
+ Examples:
+--------------------
+auto interval = PosInfInterval!Date(Date(1996, 1, 2));
+--------------------
+ +/
+ this(in TP begin) pure nothrow
+ {
+ _begin = cast(TP)begin;
+ }
+
+
+ /++
+ Params:
+ rhs = The PosInfInterval to assign to this one.
+ +/
+ /+ref+/ PosInfInterval opAssign(const ref PosInfInterval rhs) pure nothrow
+ {
+ _begin = cast(TP)rhs._begin;
+
+ return this;
+ }
+
+
+ /++
+ Params:
+ rhs = The PosInfInterval to assign to this one.
+ +/
+ /+ref+/ PosInfInterval opAssign(PosInfInterval rhs) pure nothrow
+ {
+ _begin = cast(TP)rhs._begin;
+
+ return this;
+ }
+
+
+ /++
+ The begin point of the interval. It is included in the interval.
+
+ Examples:
+--------------------
+assert(PosInfInterval!Date(Date(1996, 1, 2)).begin == Date(1996, 1, 2));
+--------------------
+ +/
+ @property TP begin() const pure nothrow
+ {
+ return cast(TP)_begin;
+ }
+
+
+ /++
+ The begin point of the interval. It is included in the interval.
+
+ Params:
+ timePoint = The time point to set begin to.
+ +/
+ @property void begin(TP timePoint) pure nothrow
+ {
+ _begin = timePoint;
+ }
+
+
+ /++
+ Whether the interval's length is 0. Always returns false.
+
+ Examples:
+--------------------
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).empty);
+--------------------
+ +/
+ @property bool empty() const pure nothrow
+ {
+ return false;
+ }
+
+
+ /++
+ Whether the given time point is within this interval.
+
+ Params:
+ timePoint = The time point to check for inclusion in this interval.
+
+ Examples:
+--------------------
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(Date(1994, 12, 24)));
+assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(Date(2000, 1, 5)));
+--------------------
+ +/
+ bool contains(TP timePoint) const pure nothrow
+ {
+ return timePoint >= _begin;
+ }
+
+
+ /++
+ Whether the given interval is completely within this interval.
+
+ Params:
+ interval = The interval to check for inclusion in this interval.
+
+ Throws:
+ DateTimeException if the given interval is empty.
+
+ Examples:
+--------------------
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(Interval!Date(Date(1998, 2, 28), Date(2013, 5, 1))));
+--------------------
+ +/
+ bool contains(in Interval!TP interval) const pure
+ {
+ interval._enforceNotEmpty();
+
+ return interval._begin >= _begin;
+ }
+
+
+ /++
+ Whether the given interval is completely within this interval.
+
+ Params:
+ interval = The interval to check for inclusion in this interval.
+
+ Examples:
+--------------------
+assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(PosInfInterval!Date(Date(1999, 5, 4))));
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(PosInfInterval!Date(Date(1995, 7, 2))));
+--------------------
+ +/
+ bool contains(in PosInfInterval interval) const pure nothrow
+ {
+ return interval._begin >= _begin;
+ }
+
+
+ /++
+ Whether the given interval is completely within this interval.
+
+ Always returns false because an interval going to positive infinity
+ can never contain an interval beginning at negative infinity.
+
+ Params:
+ interval = The interval to check for inclusion in this interval.
+
+ Examples:
+--------------------
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(NegInfInterval!Date(Date(1996, 5, 4))));
+--------------------
+ +/
+ bool contains(in NegInfInterval!TP interval) const pure nothrow
+ {
+ return false;
+ }
+
+
+ /++
+ Whether this interval is before the given time point.
+
+ Always returns false because an interval going to positive infinity
+ can never be before any time point.
+
+ Params:
+ timePoint = The time point to check whether this interval is before it.
+
+ Examples:
+--------------------
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Date(1994, 12, 24)));
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Date(2000, 1, 5)));
+--------------------
+ +/
+ bool isBefore(in TP timePoint) const pure nothrow
+ {
+ return false;
+ }
+
+
+ /++
+ Whether this interval is before the given interval and does not intersect
+ with it.
+
+ Always returns false (unless the given interval is empty) because an
+ interval going to positive infinity can never be before any other interval.
+
+ Params:
+ interval = The interval to check for against this interval.
+
+ Throws:
+ DateTimeException if either Interval is empty.
+
+ Examples:
+--------------------
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+--------------------
+ +/
+ bool isBefore(in Interval!TP interval) const pure
+ {
+ interval._enforceNotEmpty();
+
+ return false;
+ }
+
+
+ /++
+ Whether this interval is before the given interval and does not intersect
+ with it.
+
+ Always returns false because an interval going to positive infinity can
+ never be before any other interval.
+
+ Params:
+ interval = The interval to check for against this interval.
+
+ Examples:
+--------------------
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(PosInfInterval!Date(Date(1992, 5, 4))));
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(PosInfInterval!Date(Date(2013, 3, 7))));
+--------------------
+ +/
+ bool isBefore(in PosInfInterval interval) const pure nothrow
+ {
+ return false;
+ }
+
+
+ /++
+ Whether this interval is before the given interval and does not intersect
+ with it.
+
+ Always returns false because an interval going to positive infinity can
+ never be before any other interval.
+
+ Params:
+ interval = The interval to check for against this interval.
+
+ Examples:
+--------------------
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(NegInfInterval!Date(Date(1996, 5, 4))));
+--------------------
+ +/
+ bool isBefore(in NegInfInterval!TP interval) const pure nothrow
+ {
+ return false;
+ }
+
+
+ /++
+ Whether this interval is after the given time point.
+
+ Params:
+ timePoint = The time point to check whether this Interval is after it.
+
+ Examples:
+--------------------
+assert(PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Date(1994, 12, 24)));
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Date(2000, 1, 5)));
+--------------------
+ +/
+ bool isAfter(in TP timePoint) const pure nothrow
+ {
+ return timePoint < _begin;
+ }
+
+
+ /++
+ Whether this interval is after the given interval and does not intersect
+ with it.
+
+ Params:
+ interval = The interval to check against this interval.
+
+ Throws:
+ DateTimeException if the given interval is empty.
+
+ Examples:
+--------------------
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+assert(PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
+--------------------
+ +/
+ bool isAfter(in Interval!TP interval) const pure
+ {
+ interval._enforceNotEmpty();
+
+ return _begin >= interval._end;
+ }
+
+
+ /++
+ Whether this interval is after the given interval and does not intersect
+ with it.
+
+ Always returns false because an interval going to positive infinity can
+ never be after another interval going to positive infinity.
+
+ Params:
+ interval = The interval to check against this interval.
+
+ Examples:
+--------------------
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(PosInfInterval!Date(Date(1990, 1, 7))));
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(PosInfInterval!Date(Date(1999, 5, 4))));
+--------------------
+ +/
+ bool isAfter(in PosInfInterval interval) const pure nothrow
+ {
+ return false;
+ }
+
+
+ /++
+ Whether this interval is after the given interval and does not intersect
+ with it.
+
+ Params:
+ interval = The interval to check against this interval.
+
+ Examples:
+--------------------
+assert(PosInfInterval!Date(Date(1996, 1, 2)).isAfter(NegInfInterval!Date(Date(1996, 1, 2))));
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(NegInfInterval!Date(Date(2000, 7, 1))));
+--------------------
+ +/
+ bool isAfter(in NegInfInterval!TP interval) const pure nothrow
+ {
+ return _begin >= interval._end;
+ }
+
+
+ /++
+ Whether the given interval overlaps with this interval.
+
+ Params:
+ interval = The interval to check for intersection with this interval.
+
+ Throws:
+ DateTimeException if the given interval is empty.
+
+ Examples:
+--------------------
+assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).intersects(Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
+--------------------
+ +/
+ bool intersects(in Interval!TP interval) const pure
+ {
+ interval._enforceNotEmpty();
+
+ return interval._end > _begin;
+ }
+
+
+ /++
+ Whether the given interval overlaps with this interval.
+
+ Always returns true because two intervals going to positive infinity
+ always overlap.
+
+ Params:
+ interval = The interval to check for intersection with this interval.
+
+ Examples:
+--------------------
+assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(PosInfInterval!Date(Date(1990, 1, 7))));
+assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(PosInfInterval!Date(Date(1999, 5, 4))));
+--------------------
+ +/
+ bool intersects(in PosInfInterval interval) const pure nothrow
+ {
+ return true;
+ }
+
+
+ /++
+ Whether the given interval overlaps with this interval.
+
+ Params:
+ interval = The interval to check for intersection with this interval.
+
+ Examples:
+--------------------
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).intersects(NegInfInterval!Date(Date(1996, 1, 2))));
+assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(NegInfInterval!Date(Date(2000, 7, 1))));
+--------------------
+ +/
+ bool intersects(in NegInfInterval!TP interval) const pure nothrow
+ {
+ return _begin < interval._end;
+ }
+
+
+ /++
+ Returns the intersection of two intervals
+
+ Params:
+ interval = The interval to intersect with this interval.
+
+ Throws:
+ DateTimeException if the two intervals do not intersect or if the
+ given interval is empty.
+
+ Examples:
+--------------------
+assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == Interval!Date(Date(1996, 1 , 2), Date(2000, 8, 2)));
+assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) == Interval!Date(Date(1999, 1 , 12), Date(2011, 9, 17)));
+--------------------
+ +/
+ Interval!TP intersection(in Interval!TP interval) const
+ {
+ enforce(this.intersects(interval), new DateTimeException(format("%s and %s do not intersect.", this, interval)));
+
+ auto begin = _begin > interval._begin ? _begin : interval._begin;
+
+ return Interval!TP(begin, interval._end);
+ }
+
+
+ /++
+ Returns the intersection of two intervals
+
+ Params:
+ interval = The interval to intersect with this interval.
+
+ Examples:
+--------------------
+assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1996, 1 , 2)));
+assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(PosInfInterval!Date(Date(1999, 1, 12))) == PosInfInterval!Date(Date(1999, 1 , 12)));
+--------------------
+ +/
+ PosInfInterval intersection(in PosInfInterval interval) const pure nothrow
+ {
+ return PosInfInterval(_begin < interval._begin ? interval._begin : _begin);
+ }
+
+
+ /++
+ Returns the intersection of two intervals
+
+ Params:
+ interval = The interval to intersect with this interval.
+
+ Throws:
+ DateTimeException if the two intervals do not intersect.
+
+ Examples:
+--------------------
+assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(NegInfInterval!Date(Date(1999, 7, 6))) == Interval!Date(Date(1996, 1 , 2), Date(1999, 7, 6)));
+assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(NegInfInterval!Date(Date(2013, 1, 12))) == Interval!Date(Date(1996, 1 , 2), Date(2013, 1, 12)));
+--------------------
+ +/
+ Interval!TP intersection(in NegInfInterval!TP interval) const
+ {
+ enforce(this.intersects(interval), new DateTimeException(format("%s and %s do not intersect.", this, interval)));
+
+ return Interval!TP(_begin, interval._end);
+ }
+
+
+ /++
+ Whether the given interval is adjacent to this interval.
+
+ Params:
+ interval = The interval to check whether its adjacent with this
+ interval.
+
+ Throws:
+ DateTimeException if the given interval is empty.
+
+ Examples:
+--------------------
+assert(PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
+assert(!PosInfInterval!Date(Date(1999, 1, 12)).isAdjacent(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+--------------------
+ +/
+ bool isAdjacent(in Interval!TP interval) const pure
+ {
+ interval._enforceNotEmpty();
+
+ return _begin == interval._end;
+ }
+
+
+ /++
+ Whether the given interval is adjacent to this interval.
+
+ Always returns false because two intervals going to positive infinity
+ can never be adjacent to one another.
+
+ Params:
+ interval = The interval to check whether its adjacent with this
+ interval.
+
+ Examples:
+--------------------
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(PosInfInterval!Date(Date(1990, 1, 7))));
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(PosInfInterval!Date(Date(1996, 1, 2))));
+--------------------
+ +/
+ bool isAdjacent(in PosInfInterval interval) const pure nothrow
+ {
+ return false;
+ }
+
+
+ /++
+ Whether the given interval is adjacent to this interval.
+
+ Params:
+ interval = The interval to check whether its adjacent with this
+ interval.
+
+ Examples:
+--------------------
+assert(PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(NegInfInterval!Date(Date(1996, 1, 2))));
+assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(NegInfInterval!Date(Date(2000, 7, 1))));
+--------------------
+ +/
+ bool isAdjacent(in NegInfInterval!TP interval) const pure nothrow
+ {
+ return _begin == interval._end;
+ }
+
+
+ /++
+ Returns the union of two intervals
+
+ Params:
+ interval = The interval to merge with this interval.
+
+ Throws:
+ DateTimeException if the two intervals do not intersect and are not
+ adjacent or if the given interval is empty.
+
+ Note:
+ There is no overload for $(D merge()) which takes a NegInfInterval. This
+ is because you can't have an interval which goes from negative
+ infinity to positive infinity.
+
+ Examples:
+--------------------
+assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == PosInfInterval!Date(Date(1990, 7 , 6)));
+assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) == PosInfInterval!Date(Date(1996, 1 , 2)));
+--------------------
+ +/
+ PosInfInterval merge(in Interval!TP interval) const
+ {
+ enforce(this.isAdjacent(interval) || this.intersects(interval),
+ new DateTimeException(format("%s and %s are not adjacent and do not intersect.", this, interval)));
+
+ return PosInfInterval(_begin < interval._begin ? _begin : interval._begin);
+ }
+
+
+ /++
+ Returns the union of two intervals
+
+ Params:
+ interval = The interval to merge with this interval.
+
+ Note:
+ There is no overload for $(D merge()) which takes a NegInfInterval.
+ This is because you can't have an interval which goes from negative
+ infinity to positive infinity.
+
+ Examples:
+--------------------
+assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1990, 7 , 6)));
+assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(PosInfInterval!Date(Date(1999, 1, 12))) == PosInfInterval!Date(Date(1996, 1 , 2)));
+--------------------
+ +/
+ PosInfInterval merge(in PosInfInterval interval) const pure nothrow
+ {
+ return PosInfInterval(_begin < interval._begin ? _begin : interval._begin);
+ }
+
+
+ /++
+ Returns an interval that covers from the earliest time point of two
+ intervals up to (but not including) the latest time point of two
+ intervals.
+
+ Params:
+ interval = The interval to create a span together with this
+ interval.
+
+ Throws:
+ DateTimeException if the given interval is empty.
+
+ Note:
+ There is no overload for $(D span()) which takes a NegInfInterval.
+ This is because you can't have an interval which goes from negative
+ infinity to positive infinity.
+
+ Examples:
+--------------------
+assert(PosInfInterval!Date(Date(1996, 1, 2)).span(Interval!Date(Date(500, 8, 9), Date(1602, 1, 31))) == PosInfInterval!Date(Date(500, 8, 9)));
+assert(PosInfInterval!Date(Date(1996, 1, 2)).span(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == PosInfInterval!Date(Date(1990, 7 , 6)));
+assert(PosInfInterval!Date(Date(1996, 1, 2)).span(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) == PosInfInterval!Date(Date(1996, 1 , 2)));
+--------------------
+ +/
+ PosInfInterval span(in Interval!TP interval) const pure
+ {
+ interval._enforceNotEmpty();
+
+ return PosInfInterval(_begin < interval._begin ? _begin : interval._begin);
+ }
+
+
+ /++
+ Returns an interval that covers from the earliest time point of two
+ intervals up to (but not including) the latest time point of two
+ intervals.
+
+ Params:
+ interval = The interval to create a span together with this interval.
+
+ Note:
+ There is no overload for $(D span()) which takes a NegInfInterval.
+ This is because you can't have an interval which goes from negative
+ infinity to positive infinity.
+
+ Examples:
+--------------------
+assert(PosInfInterval!Date(Date(1996, 1, 2)).span(PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1990, 7 , 6)));
+assert(PosInfInterval!Date(Date(1996, 1, 2)).span(PosInfInterval!Date(Date(1999, 1, 12))) == PosInfInterval!Date(Date(1996, 1 , 2)));
+--------------------
+ +/
+ PosInfInterval span(in PosInfInterval interval) const pure nothrow
+ {
+ return PosInfInterval(_begin < interval._begin ? _begin : interval._begin);
+ }
+
+
+ /++
+ Shifts the begin of this interval forward or backwards in time by the
+ given duration (a positive duration shifts the interval forward; a
+ negative duration shifts it backward). Effectively, it does
+ $(D begin += duration).
+
+ Params:
+ duration = The duration to shift the interval by.
+
+ Examples:
+--------------------
+auto interval1 = PosInfInterval!Date(Date(1996, 1, 2));
+auto interval2 = PosInfInterval!Date(Date(1996, 1, 2));
+
+interval1.shift(dur!"days"(50));
+assert(interval1 == PosInfInterval!Date(Date(1996, 2, 21)));
+
+interval2.shift(dur!"days"(-50));
+assert(interval2 == PosInfInterval!Date(Date(1995, 11, 13)));
+--------------------
+ +/
+ void shift(D)(D duration) pure nothrow
+ if(__traits(compiles, begin + duration))
+ {
+ _begin += duration;
+ }
+
+
+ static if(__traits(compiles, begin.add!"months"(1)) &&
+ __traits(compiles, begin.add!"years"(1)))
+ {
+ /++
+ Shifts the begin of this interval forward or backwards in time by
+ the given number of years and/or months (a positive number of years
+ and months shifts the interval forward; a negative number shifts it
+ backward). It adds the years the given years and months to begin.
+ It effectively calls $(D add!"years"()) and then $(D add!"months"())
+ on begin the given number of years and months.
+
+ Params:
+ years = The number of years to shift the interval by.
+ months = The number of months to shift the interval by.
+ allowOverflow = Whether the days should be allowed to overflow
+ on begin, causing its month to increment.
+
+ Throws:
+ DateTimeException if empty is true or if the resulting interval
+ would be invalid.
+
+ Examples:
+--------------------
+auto interval1 = PosInfInterval!Date(Date(1996, 1, 2));
+auto interval2 = PosInfInterval!Date(Date(1996, 1, 2));
+
+interval1.shift(dur!"days"(50));
+assert(interval1 == PosInfInterval!Date(Date(1996, 2, 21)));
+
+interval2.shift(dur!"days"(-50));
+assert(interval2 == PosInfInterval!Date(Date(1995, 11, 13)));
+--------------------
+ +/
+ void shift(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
+ if(isIntegral!T)
+ {
+ auto begin = _begin;
+
+ begin.add!"years"(years, allowOverflow);
+ begin.add!"months"(months, allowOverflow);
+
+ _begin = begin;
+ }
+ }
+
+
+ /++
+ Expands the interval backwards in time. Effectively, it does
+ $(D begin -= duration).
+
+ Params:
+ duration = The duration to expand the interval by.
+ dir = The direction in time to expand the interval.
+
+ Examples:
+--------------------
+auto interval1 = PosInfInterval!Date(Date(1996, 1, 2));
+auto interval2 = PosInfInterval!Date(Date(1996, 1, 2));
+
+interval1.expand(dur!"days"(2));
+assert(interval1 == PosInfInterval!Date(Date(1995, 12, 31)));
+
+interval2.expand(dur!"days"(-2));
+assert(interval2 == PosInfInterval!Date(Date(1996, 1, 4)));
+--------------------
+ +/
+ void expand(D)(D duration) pure nothrow
+ if(__traits(compiles, begin + duration))
+ {
+ _begin -= duration;
+ }
+
+
+ static if(__traits(compiles, begin.add!"months"(1)) &&
+ __traits(compiles, begin.add!"years"(1)))
+ {
+ /++
+ Expands the interval forwards and/or backwards in time. Effectively,
+ it subtracts the given number of months/years from begin.
+
+ Params:
+ years = The number of years to expand the interval by.
+ months = The number of months to expand the interval by.
+ allowOverflow = Whether the days should be allowed to overflow
+ on begin, causing its month to increment.
+
+ Throws:
+ DateTimeException if empty is true or if the resulting interval
+ would be invalid.
+
+ Examples:
+--------------------
+auto interval1 = PosInfInterval!Date(Date(1996, 1, 2));
+auto interval2 = PosInfInterval!Date(Date(1996, 1, 2));
+
+interval1.expand(2);
+assert(interval1 == PosInfInterval!Date(Date(1994, 1, 2)));
+
+interval2.expand(-2);
+assert(interval2 == PosInfInterval!Date(Date(1998, 1, 2)));
+--------------------
+ +/
+ void expand(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
+ if(isIntegral!T)
+ {
+ auto begin = _begin;
+
+ begin.add!"years"(-years, allowOverflow);
+ begin.add!"months"(-months, allowOverflow);
+
+ _begin = begin;
+
+ return;
+ }
+ }
+
+
+ /++
+ Returns a range which iterates forward over the interval, starting
+ at begin, using $(D func()) to generate each successive time point.
+
+ The range's front is the interval's begin. $(D func()) is used
+ to generate the next front when $(D popFront()) is called. If
+ $(D popFirst) is true, then $(D popFront()) is called before the
+ range is returned (so that front is a time point which $(D func())
+ would generate).
+
+ If $(D func()) ever generates a time point less than or equal to the
+ current front of the range, then a DateTimeException will be thrown.
+
+ There are helper functions in this module which generate common delegates
+ to pass to $(D fwdRange()). Their documentation starts with
+ "Generates a range-generating function for intervals," so you can easily
+ search for them.
+
+ Params:
+ func = The function used to generate the time points of the
+ range over the interval.
+ popFirst = Whether popFront() should be called on the range before
+ returning it.
+
+ Warning:
+ func must be logically pure. Ideally, $(D func) would be a function
+ pointer to a pure function, but forcing func to be pure is far too
+ restrictive to be useful, and in order to have the ease of use of
+ having functions which generate functions to pass to $(D fwdRange()),
+ $(D func) must be a delegate.
+
+ If $(D func) retains state which changes as it is called, then some
+ algorithms will not work correctly, because the range's $(D save)
+ will have failed to have really saved the range's state. So, if you
+ want to avoid such bugs, don't pass a delegate which is not
+ logically pure to $(D fwdRange()). If $(D func) is given the same
+ time point with two different calls, it must return the same result
+ both times.
+
+ Of course, none of the functions in this module have this problem, so
+ it's only relevant if you're creating your own delegate.
+
+ Examples:
+--------------------
+auto interval = PosInfInterval!Date(Date(2010, 9, 1));
+auto func = (in Date date) //For iterating over even-numbered days.
+ {
+ if((date.day & 1) == 0)
+ return date + dur!"days"(2);
+
+ return date + dur!"days"(1);
+ };
+auto range = interval.fwdRange(func);
+
+assert(range.front == Date(2010, 9, 1)); //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 2).
+
+range.popFront();
+assert(range.front == Date(2010, 9, 2));
+
+range.popFront();
+assert(range.front == Date(2010, 9, 4));
+
+range.popFront();
+assert(range.front == Date(2010, 9, 6));
+
+range.popFront();
+assert(range.front == Date(2010, 9, 8));
+
+range.popFront();
+assert(!range.empty);
+--------------------
+ +/
+ PosInfIntervalRange!(TP) fwdRange(TP delegate(in TP) func, PopFirst popFirst = PopFirst.no) const
+ {
+ auto range = PosInfIntervalRange!(TP)(this, func);
+
+ if(popFirst == PopFirst.yes)
+ range.popFront();
+
+ return range;
+ }
+
+
+ /+
+ Converts this interval to a string.
+ +/
+ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't
+ //have versions of toString() with extra modifiers, so we define one version
+ //with modifiers and one without.
+ string toString()
+ {
+ return _toStringImpl();
+ }
+
+
+ /++
+ Converts this interval to a string.
+ +/
+ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't
+ //have versions of toString() with extra modifiers, so we define one version
+ //with modifiers and one without.
+ string toString() const nothrow
+ {
+ return _toStringImpl();
+ }
+
+private:
+
+ /++
+ Since we have two versions of toString(), we have _toStringImpl()
+ so that they can share implementations.
+ +/
+ string _toStringImpl() const nothrow
+ {
+ try
+ return format("[%s - ∞)", _begin);
+ catch(Exception e)
+ assert(0, "format() threw.");
+ }
+
+
+ TP _begin;
+}
+
+//Test PosInfInterval's constructor.
+unittest
+{
+ PosInfInterval!Date(Date.init);
+ PosInfInterval!TimeOfDay(TimeOfDay.init);
+ PosInfInterval!DateTime(DateTime.init);
+ PosInfInterval!SysTime(SysTime(0));
+
+ //Verify Examples.
+ auto interval = PosInfInterval!Date(Date(1996, 1, 2));
+}
+
+//Test PosInfInterval's begin.
+unittest
+{
+ assertPred!"=="(PosInfInterval!Date(Date(1, 1, 1)).begin, Date(1, 1, 1));
+ assertPred!"=="(PosInfInterval!Date(Date(2010, 1, 1)).begin, Date(2010, 1, 1));
+ assertPred!"=="(PosInfInterval!Date(Date(1997, 12, 31)).begin, Date(1997, 12, 31));
+
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ static assert(__traits(compiles, cPosInfInterval.begin));
+ static assert(__traits(compiles, iPosInfInterval.begin));
+
+ //Verify Examples.
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).begin == Date(1996, 1, 2));
+}
+
+//Test PosInfInterval's empty.
+unittest
+{
+ assert(!PosInfInterval!Date(Date(2010, 1, 1)).empty);
+ assert(!PosInfInterval!TimeOfDay(TimeOfDay(0, 30, 0)).empty);
+ assert(!PosInfInterval!DateTime(DateTime(2010, 1, 1, 0, 30, 0)).empty);
+ assert(!PosInfInterval!SysTime(SysTime(DateTime(2010, 1, 1, 0, 30, 0))).empty);
+
+ const cPosInfInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iPosInfInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ static assert(__traits(compiles, cPosInfInterval.empty));
+ static assert(__traits(compiles, iPosInfInterval.empty));
+
+ //Verify Examples.
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).empty);
+}
+
+//Test PosInfInterval's contains(time point).
+unittest
+{
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+
+ assert(!posInfInterval.contains(Date(2009, 7, 4)));
+ assert(!posInfInterval.contains(Date(2010, 7, 3)));
+ assert(posInfInterval.contains(Date(2010, 7, 4)));
+ assert(posInfInterval.contains(Date(2010, 7, 5)));
+ assert(posInfInterval.contains(Date(2011, 7, 1)));
+ assert(posInfInterval.contains(Date(2012, 1, 6)));
+ assert(posInfInterval.contains(Date(2012, 1, 7)));
+ assert(posInfInterval.contains(Date(2012, 1, 8)));
+ assert(posInfInterval.contains(Date(2013, 1, 7)));
+
+ const cdate = Date(2010, 7, 6);
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ static assert(__traits(compiles, posInfInterval.contains(cdate)));
+ static assert(__traits(compiles, cPosInfInterval.contains(cdate)));
+ static assert(__traits(compiles, iPosInfInterval.contains(cdate)));
+
+ //Verify Examples.
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(Date(1994, 12, 24)));
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(Date(2000, 1, 5)));
+}
+
+//Test PosInfInterval's contains(Interval).
+unittest
+{
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+
+ static void testInterval(in PosInfInterval!Date posInfInterval, in Interval!Date interval)
+ {
+ posInfInterval.contains(interval);
+ }
+
+ assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assert(posInfInterval.contains(posInfInterval));
+ assert(!posInfInterval.contains(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
+ assert(!posInfInterval.contains(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
+ assert(!posInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
+ assert(!posInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
+ assert(!posInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
+ assert(!posInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
+ assert(posInfInterval.contains(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
+ assert(posInfInterval.contains(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
+ assert(posInfInterval.contains(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
+ assert(posInfInterval.contains(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
+ assert(posInfInterval.contains(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
+ assert(posInfInterval.contains(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
+
+ assert(!posInfInterval.contains(PosInfInterval!Date(Date(2010, 7, 3))));
+ assert(posInfInterval.contains(PosInfInterval!Date(Date(2010, 7, 4))));
+ assert(posInfInterval.contains(PosInfInterval!Date(Date(2010, 7, 5))));
+ assert(posInfInterval.contains(PosInfInterval!Date(Date(2012, 1, 6))));
+ assert(posInfInterval.contains(PosInfInterval!Date(Date(2012, 1, 7))));
+ assert(posInfInterval.contains(PosInfInterval!Date(Date(2012, 1, 8))));
+
+ assert(PosInfInterval!Date(Date(2010, 7, 3)).contains(posInfInterval));
+ assert(PosInfInterval!Date(Date(2010, 7, 4)).contains(posInfInterval));
+ assert(!PosInfInterval!Date(Date(2010, 7, 5)).contains(posInfInterval));
+ assert(!PosInfInterval!Date(Date(2012, 1, 6)).contains(posInfInterval));
+ assert(!PosInfInterval!Date(Date(2012, 1, 7)).contains(posInfInterval));
+ assert(!PosInfInterval!Date(Date(2012, 1, 8)).contains(posInfInterval));
+
+ assert(!posInfInterval.contains(NegInfInterval!Date(Date(2010, 7, 3))));
+ assert(!posInfInterval.contains(NegInfInterval!Date(Date(2010, 7, 4))));
+ assert(!posInfInterval.contains(NegInfInterval!Date(Date(2010, 7, 5))));
+ assert(!posInfInterval.contains(NegInfInterval!Date(Date(2012, 1, 6))));
+ assert(!posInfInterval.contains(NegInfInterval!Date(Date(2012, 1, 7))));
+ assert(!posInfInterval.contains(NegInfInterval!Date(Date(2012, 1, 8))));
+
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, posInfInterval.contains(interval)));
+ static assert(__traits(compiles, posInfInterval.contains(cInterval)));
+ static assert(__traits(compiles, posInfInterval.contains(iInterval)));
+ static assert(__traits(compiles, posInfInterval.contains(posInfInterval)));
+ static assert(__traits(compiles, posInfInterval.contains(cPosInfInterval)));
+ static assert(__traits(compiles, posInfInterval.contains(iPosInfInterval)));
+ static assert(__traits(compiles, posInfInterval.contains(negInfInterval)));
+ static assert(__traits(compiles, posInfInterval.contains(cNegInfInterval)));
+ static assert(__traits(compiles, posInfInterval.contains(iNegInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.contains(interval)));
+ static assert(__traits(compiles, cPosInfInterval.contains(cInterval)));
+ static assert(__traits(compiles, cPosInfInterval.contains(iInterval)));
+ static assert(__traits(compiles, cPosInfInterval.contains(posInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.contains(cPosInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.contains(iPosInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.contains(negInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.contains(cNegInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.contains(iNegInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.contains(interval)));
+ static assert(__traits(compiles, iPosInfInterval.contains(cInterval)));
+ static assert(__traits(compiles, iPosInfInterval.contains(iInterval)));
+ static assert(__traits(compiles, iPosInfInterval.contains(posInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.contains(cPosInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.contains(iPosInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.contains(negInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.contains(cNegInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.contains(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(Interval!Date(Date(1998, 2, 28), Date(2013, 5, 1))));
+
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).contains(PosInfInterval!Date(Date(1999, 5, 4))));
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(PosInfInterval!Date(Date(1995, 7, 2))));
+
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).contains(NegInfInterval!Date(Date(1996, 5, 4))));
+}
+
+//Test PosInfInterval's isBefore(time point).
+unittest
+{
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+
+ assert(!posInfInterval.isBefore(Date(2009, 7, 3)));
+ assert(!posInfInterval.isBefore(Date(2010, 7, 3)));
+ assert(!posInfInterval.isBefore(Date(2010, 7, 4)));
+ assert(!posInfInterval.isBefore(Date(2010, 7, 5)));
+ assert(!posInfInterval.isBefore(Date(2011, 7, 1)));
+ assert(!posInfInterval.isBefore(Date(2012, 1, 6)));
+ assert(!posInfInterval.isBefore(Date(2012, 1, 7)));
+ assert(!posInfInterval.isBefore(Date(2012, 1, 8)));
+ assert(!posInfInterval.isBefore(Date(2013, 1, 7)));
+
+ const cdate = Date(2010, 7, 6);
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ static assert(__traits(compiles, posInfInterval.isBefore(cdate)));
+ static assert(__traits(compiles, cPosInfInterval.isBefore(cdate)));
+ static assert(__traits(compiles, iPosInfInterval.isBefore(cdate)));
+
+ //Verify Examples.
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Date(1994, 12, 24)));
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Date(2000, 1, 5)));
+}
+
+//Test PosInfInterval's isBefore(Interval).
+unittest
+{
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+
+ static void testInterval(in PosInfInterval!Date posInfInterval, in Interval!Date interval)
+ {
+ posInfInterval.isBefore(interval);
+ }
+
+ assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assert(!posInfInterval.isBefore(posInfInterval));
+ assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
+ assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
+ assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
+ assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
+ assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
+ assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
+ assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
+ assert(!posInfInterval.isBefore(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
+ assert(!posInfInterval.isBefore(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
+ assert(!posInfInterval.isBefore(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
+ assert(!posInfInterval.isBefore(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
+ assert(!posInfInterval.isBefore(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
+
+ assert(!posInfInterval.isBefore(PosInfInterval!Date(Date(2010, 7, 3))));
+ assert(!posInfInterval.isBefore(PosInfInterval!Date(Date(2010, 7, 4))));
+ assert(!posInfInterval.isBefore(PosInfInterval!Date(Date(2010, 7, 5))));
+ assert(!posInfInterval.isBefore(PosInfInterval!Date(Date(2012, 1, 6))));
+ assert(!posInfInterval.isBefore(PosInfInterval!Date(Date(2012, 1, 7))));
+ assert(!posInfInterval.isBefore(PosInfInterval!Date(Date(2012, 1, 8))));
+
+ assert(!PosInfInterval!Date(Date(2010, 7, 3)).isBefore(posInfInterval));
+ assert(!PosInfInterval!Date(Date(2010, 7, 4)).isBefore(posInfInterval));
+ assert(!PosInfInterval!Date(Date(2010, 7, 5)).isBefore(posInfInterval));
+ assert(!PosInfInterval!Date(Date(2012, 1, 6)).isBefore(posInfInterval));
+ assert(!PosInfInterval!Date(Date(2012, 1, 7)).isBefore(posInfInterval));
+ assert(!PosInfInterval!Date(Date(2012, 1, 8)).isBefore(posInfInterval));
+
+ assert(!posInfInterval.isBefore(NegInfInterval!Date(Date(2010, 7, 3))));
+ assert(!posInfInterval.isBefore(NegInfInterval!Date(Date(2010, 7, 4))));
+ assert(!posInfInterval.isBefore(NegInfInterval!Date(Date(2010, 7, 5))));
+ assert(!posInfInterval.isBefore(NegInfInterval!Date(Date(2012, 1, 6))));
+ assert(!posInfInterval.isBefore(NegInfInterval!Date(Date(2012, 1, 7))));
+ assert(!posInfInterval.isBefore(NegInfInterval!Date(Date(2012, 1, 8))));
+
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, posInfInterval.isBefore(interval)));
+ static assert(__traits(compiles, posInfInterval.isBefore(cInterval)));
+ static assert(__traits(compiles, posInfInterval.isBefore(iInterval)));
+ static assert(__traits(compiles, posInfInterval.isBefore(posInfInterval)));
+ static assert(__traits(compiles, posInfInterval.isBefore(cPosInfInterval)));
+ static assert(__traits(compiles, posInfInterval.isBefore(iPosInfInterval)));
+ static assert(__traits(compiles, posInfInterval.isBefore(negInfInterval)));
+ static assert(__traits(compiles, posInfInterval.isBefore(cNegInfInterval)));
+ static assert(__traits(compiles, posInfInterval.isBefore(iNegInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isBefore(interval)));
+ static assert(__traits(compiles, cPosInfInterval.isBefore(cInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isBefore(iInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isBefore(posInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isBefore(cPosInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isBefore(iPosInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isBefore(negInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isBefore(cNegInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isBefore(iNegInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isBefore(interval)));
+ static assert(__traits(compiles, iPosInfInterval.isBefore(cInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isBefore(iInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isBefore(posInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isBefore(cPosInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isBefore(iPosInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isBefore(negInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isBefore(cNegInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isBefore(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(PosInfInterval!Date(Date(1992, 5, 4))));
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(PosInfInterval!Date(Date(2013, 3, 7))));
+
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).isBefore(NegInfInterval!Date(Date(1996, 5, 4))));
+}
+
+//Test PosInfInterval's isAfter(time point).
+unittest
+{
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+
+ assert(posInfInterval.isAfter(Date(2009, 7, 3)));
+ assert(posInfInterval.isAfter(Date(2010, 7, 3)));
+ assert(!posInfInterval.isAfter(Date(2010, 7, 4)));
+ assert(!posInfInterval.isAfter(Date(2010, 7, 5)));
+ assert(!posInfInterval.isAfter(Date(2011, 7, 1)));
+ assert(!posInfInterval.isAfter(Date(2012, 1, 6)));
+ assert(!posInfInterval.isAfter(Date(2012, 1, 7)));
+ assert(!posInfInterval.isAfter(Date(2012, 1, 8)));
+ assert(!posInfInterval.isAfter(Date(2013, 1, 7)));
+
+ const cdate = Date(2010, 7, 6);
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ static assert(__traits(compiles, posInfInterval.isAfter(cdate)));
+ static assert(__traits(compiles, cPosInfInterval.isAfter(cdate)));
+ static assert(__traits(compiles, iPosInfInterval.isAfter(cdate)));
+
+ //Verify Examples.
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Date(1994, 12, 24)));
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Date(2000, 1, 5)));
+}
+
+//Test PosInfInterval's isAfter(Interval).
+unittest
+{
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+
+ static void testInterval(in PosInfInterval!Date posInfInterval, in Interval!Date interval)
+ {
+ posInfInterval.isAfter(interval);
+ }
+
+ assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assert(!posInfInterval.isAfter(posInfInterval));
+ assert(posInfInterval.isAfter(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
+ assert(!posInfInterval.isAfter(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
+ assert(posInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
+ assert(!posInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
+ assert(!posInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
+ assert(!posInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
+ assert(!posInfInterval.isAfter(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
+ assert(!posInfInterval.isAfter(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
+ assert(!posInfInterval.isAfter(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
+ assert(!posInfInterval.isAfter(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
+ assert(!posInfInterval.isAfter(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
+ assert(!posInfInterval.isAfter(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
+
+ assert(!posInfInterval.isAfter(PosInfInterval!Date(Date(2010, 7, 3))));
+ assert(!posInfInterval.isAfter(PosInfInterval!Date(Date(2010, 7, 4))));
+ assert(!posInfInterval.isAfter(PosInfInterval!Date(Date(2010, 7, 5))));
+ assert(!posInfInterval.isAfter(PosInfInterval!Date(Date(2012, 1, 6))));
+ assert(!posInfInterval.isAfter(PosInfInterval!Date(Date(2012, 1, 7))));
+ assert(!posInfInterval.isAfter(PosInfInterval!Date(Date(2012, 1, 8))));
+
+ assert(!PosInfInterval!Date(Date(2010, 7, 3)).isAfter(posInfInterval));
+ assert(!PosInfInterval!Date(Date(2010, 7, 4)).isAfter(posInfInterval));
+ assert(!PosInfInterval!Date(Date(2010, 7, 5)).isAfter(posInfInterval));
+ assert(!PosInfInterval!Date(Date(2012, 1, 6)).isAfter(posInfInterval));
+ assert(!PosInfInterval!Date(Date(2012, 1, 7)).isAfter(posInfInterval));
+ assert(!PosInfInterval!Date(Date(2012, 1, 8)).isAfter(posInfInterval));
+
+ assert(posInfInterval.isAfter(NegInfInterval!Date(Date(2010, 7, 3))));
+ assert(posInfInterval.isAfter(NegInfInterval!Date(Date(2010, 7, 4))));
+ assert(!posInfInterval.isAfter(NegInfInterval!Date(Date(2010, 7, 5))));
+ assert(!posInfInterval.isAfter(NegInfInterval!Date(Date(2012, 1, 6))));
+ assert(!posInfInterval.isAfter(NegInfInterval!Date(Date(2012, 1, 7))));
+ assert(!posInfInterval.isAfter(NegInfInterval!Date(Date(2012, 1, 8))));
+
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, posInfInterval.isAfter(interval)));
+ static assert(__traits(compiles, posInfInterval.isAfter(cInterval)));
+ static assert(__traits(compiles, posInfInterval.isAfter(iInterval)));
+ static assert(__traits(compiles, posInfInterval.isAfter(posInfInterval)));
+ static assert(__traits(compiles, posInfInterval.isAfter(cPosInfInterval)));
+ static assert(__traits(compiles, posInfInterval.isAfter(iPosInfInterval)));
+ static assert(__traits(compiles, posInfInterval.isAfter(negInfInterval)));
+ static assert(__traits(compiles, posInfInterval.isAfter(cNegInfInterval)));
+ static assert(__traits(compiles, posInfInterval.isAfter(iNegInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isAfter(interval)));
+ static assert(__traits(compiles, cPosInfInterval.isAfter(cInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isAfter(iInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isAfter(posInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isAfter(cPosInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isAfter(iPosInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isAfter(negInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isAfter(cNegInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isAfter(iNegInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isAfter(interval)));
+ static assert(__traits(compiles, iPosInfInterval.isAfter(cInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isAfter(iInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isAfter(posInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isAfter(cPosInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isAfter(iPosInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isAfter(negInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isAfter(cNegInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isAfter(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).isAfter(Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
+
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(PosInfInterval!Date(Date(1990, 1, 7))));
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(PosInfInterval!Date(Date(1999, 5, 4))));
+
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).isAfter(NegInfInterval!Date(Date(1996, 1, 2))));
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAfter(NegInfInterval!Date(Date(2000, 7, 1))));
+}
+
+//Test PosInfInterval's intersects().
+unittest
+{
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+
+ static void testInterval(in PosInfInterval!Date posInfInterval, in Interval!Date interval)
+ {
+ posInfInterval.intersects(interval);
+ }
+
+ assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assert(posInfInterval.intersects(posInfInterval));
+ assert(!posInfInterval.intersects(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
+ assert(posInfInterval.intersects(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
+ assert(!posInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
+ assert(posInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
+ assert(posInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
+ assert(posInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
+ assert(posInfInterval.intersects(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
+ assert(posInfInterval.intersects(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
+ assert(posInfInterval.intersects(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
+ assert(posInfInterval.intersects(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
+ assert(posInfInterval.intersects(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
+ assert(posInfInterval.intersects(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
+
+ assert(posInfInterval.intersects(PosInfInterval!Date(Date(2010, 7, 3))));
+ assert(posInfInterval.intersects(PosInfInterval!Date(Date(2010, 7, 4))));
+ assert(posInfInterval.intersects(PosInfInterval!Date(Date(2010, 7, 5))));
+ assert(posInfInterval.intersects(PosInfInterval!Date(Date(2012, 1, 6))));
+ assert(posInfInterval.intersects(PosInfInterval!Date(Date(2012, 1, 7))));
+ assert(posInfInterval.intersects(PosInfInterval!Date(Date(2012, 1, 8))));
+
+ assert(PosInfInterval!Date(Date(2010, 7, 3)).intersects(posInfInterval));
+ assert(PosInfInterval!Date(Date(2010, 7, 4)).intersects(posInfInterval));
+ assert(PosInfInterval!Date(Date(2010, 7, 5)).intersects(posInfInterval));
+ assert(PosInfInterval!Date(Date(2012, 1, 6)).intersects(posInfInterval));
+ assert(PosInfInterval!Date(Date(2012, 1, 7)).intersects(posInfInterval));
+ assert(PosInfInterval!Date(Date(2012, 1, 8)).intersects(posInfInterval));
+
+ assert(!posInfInterval.intersects(NegInfInterval!Date(Date(2010, 7, 3))));
+ assert(!posInfInterval.intersects(NegInfInterval!Date(Date(2010, 7, 4))));
+ assert(posInfInterval.intersects(NegInfInterval!Date(Date(2010, 7, 5))));
+ assert(posInfInterval.intersects(NegInfInterval!Date(Date(2012, 1, 6))));
+ assert(posInfInterval.intersects(NegInfInterval!Date(Date(2012, 1, 7))));
+ assert(posInfInterval.intersects(NegInfInterval!Date(Date(2012, 1, 8))));
+
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, posInfInterval.intersects(interval)));
+ static assert(__traits(compiles, posInfInterval.intersects(cInterval)));
+ static assert(__traits(compiles, posInfInterval.intersects(iInterval)));
+ static assert(__traits(compiles, posInfInterval.intersects(posInfInterval)));
+ static assert(__traits(compiles, posInfInterval.intersects(cPosInfInterval)));
+ static assert(__traits(compiles, posInfInterval.intersects(iPosInfInterval)));
+ static assert(__traits(compiles, posInfInterval.intersects(negInfInterval)));
+ static assert(__traits(compiles, posInfInterval.intersects(cNegInfInterval)));
+ static assert(__traits(compiles, posInfInterval.intersects(iNegInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.intersects(interval)));
+ static assert(__traits(compiles, cPosInfInterval.intersects(cInterval)));
+ static assert(__traits(compiles, cPosInfInterval.intersects(iInterval)));
+ static assert(__traits(compiles, cPosInfInterval.intersects(posInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.intersects(cPosInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.intersects(iPosInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.intersects(negInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.intersects(cNegInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.intersects(iNegInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.intersects(interval)));
+ static assert(__traits(compiles, iPosInfInterval.intersects(cInterval)));
+ static assert(__traits(compiles, iPosInfInterval.intersects(iInterval)));
+ static assert(__traits(compiles, iPosInfInterval.intersects(posInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.intersects(cPosInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.intersects(iPosInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.intersects(negInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.intersects(cNegInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.intersects(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).intersects(Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
+
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(PosInfInterval!Date(Date(1990, 1, 7))));
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(PosInfInterval!Date(Date(1999, 5, 4))));
+
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).intersects(NegInfInterval!Date(Date(1996, 1, 2))));
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).intersects(NegInfInterval!Date(Date(2000, 7, 1))));
+}
+
+//Test PosInfInterval's intersection().
+unittest
+{
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+
+ static void testInterval(I, J)(in I interval1, in J interval2)
+ {
+ interval1.intersection(interval2);
+ }
+
+ assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
+ assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
+
+ assertThrown!DateTimeException(testInterval(posInfInterval, NegInfInterval!Date(Date(2010, 7, 3))));
+ assertThrown!DateTimeException(testInterval(posInfInterval, NegInfInterval!Date(Date(2010, 7, 4))));
+
+ assertPred!"=="(posInfInterval.intersection(posInfInterval),
+ posInfInterval);
+ assertPred!"=="(posInfInterval.intersection(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))),
+ Interval!Date(Date(2010, 7, 4), Date(2013, 7, 3)));
+ assertPred!"=="(posInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))),
+ Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5)));
+ assertPred!"=="(posInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(posInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
+ assertPred!"=="(posInfInterval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))),
+ Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)));
+ assertPred!"=="(posInfInterval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))),
+ Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)));
+ assertPred!"=="(posInfInterval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))),
+ Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
+ assertPred!"=="(posInfInterval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))),
+ Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)));
+ assertPred!"=="(posInfInterval.intersection(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))),
+ Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)));
+ assertPred!"=="(posInfInterval.intersection(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))),
+ Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)));
+
+ assertPred!"=="(posInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 3))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 4))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 5))),
+ PosInfInterval!Date(Date(2010, 7, 5)));
+ assertPred!"=="(posInfInterval.intersection(PosInfInterval!Date(Date(2012, 1, 6))),
+ PosInfInterval!Date(Date(2012, 1, 6)));
+ assertPred!"=="(posInfInterval.intersection(PosInfInterval!Date(Date(2012, 1, 7))),
+ PosInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(posInfInterval.intersection(PosInfInterval!Date(Date(2012, 1, 8))),
+ PosInfInterval!Date(Date(2012, 1, 8)));
+
+ assertPred!"=="(PosInfInterval!Date(Date(2010, 7, 3)).intersection(posInfInterval),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(PosInfInterval!Date(Date(2010, 7, 4)).intersection(posInfInterval),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(PosInfInterval!Date(Date(2010, 7, 5)).intersection(posInfInterval),
+ PosInfInterval!Date(Date(2010, 7, 5)));
+ assertPred!"=="(PosInfInterval!Date(Date(2012, 1, 6)).intersection(posInfInterval),
+ PosInfInterval!Date(Date(2012, 1, 6)));
+ assertPred!"=="(PosInfInterval!Date(Date(2012, 1, 7)).intersection(posInfInterval),
+ PosInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(PosInfInterval!Date(Date(2012, 1, 8)).intersection(posInfInterval),
+ PosInfInterval!Date(Date(2012, 1, 8)));
+
+ assertPred!"=="(posInfInterval.intersection(NegInfInterval!Date(Date(2010, 7, 5))),
+ Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5)));
+ assertPred!"=="(posInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 6))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 6)));
+ assertPred!"=="(posInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 7))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
+ assertPred!"=="(posInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 8))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
+
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, posInfInterval.intersection(interval)));
+ static assert(__traits(compiles, posInfInterval.intersection(cInterval)));
+ static assert(__traits(compiles, posInfInterval.intersection(iInterval)));
+ static assert(__traits(compiles, posInfInterval.intersection(posInfInterval)));
+ static assert(__traits(compiles, posInfInterval.intersection(cPosInfInterval)));
+ static assert(__traits(compiles, posInfInterval.intersection(iPosInfInterval)));
+ static assert(__traits(compiles, posInfInterval.intersection(negInfInterval)));
+ static assert(__traits(compiles, posInfInterval.intersection(cNegInfInterval)));
+ static assert(__traits(compiles, posInfInterval.intersection(iNegInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.intersection(interval)));
+ static assert(__traits(compiles, cPosInfInterval.intersection(cInterval)));
+ static assert(__traits(compiles, cPosInfInterval.intersection(iInterval)));
+ static assert(__traits(compiles, cPosInfInterval.intersection(posInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.intersection(cPosInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.intersection(iPosInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.intersection(negInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.intersection(cNegInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.intersection(iNegInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.intersection(interval)));
+ static assert(__traits(compiles, iPosInfInterval.intersection(cInterval)));
+ static assert(__traits(compiles, iPosInfInterval.intersection(iInterval)));
+ static assert(__traits(compiles, iPosInfInterval.intersection(posInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.intersection(cPosInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.intersection(iPosInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.intersection(negInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.intersection(cNegInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.intersection(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == Interval!Date(Date(1996, 1 , 2), Date(2000, 8, 2)));
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) == Interval!Date(Date(1999, 1 , 12), Date(2011, 9, 17)));
+
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1996, 1 , 2)));
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(PosInfInterval!Date(Date(1999, 1, 12))) == PosInfInterval!Date(Date(1999, 1 , 12)));
+
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(NegInfInterval!Date(Date(1999, 7, 6))) == Interval!Date(Date(1996, 1 , 2), Date(1999, 7, 6)));
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).intersection(NegInfInterval!Date(Date(2013, 1, 12))) == Interval!Date(Date(1996, 1 , 2), Date(2013, 1, 12)));
+}
+
+//Test PosInfInterval's isAdjacent().
+unittest
+{
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+
+ static void testInterval(in PosInfInterval!Date posInfInterval, in Interval!Date interval)
+ {
+ posInfInterval.isAdjacent(interval);
+ }
+
+ assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assert(!posInfInterval.isAdjacent(posInfInterval));
+ assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
+ assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
+ assert(posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
+ assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
+ assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
+ assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
+ assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
+ assert(!posInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
+ assert(!posInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
+ assert(!posInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
+ assert(!posInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
+ assert(!posInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
+
+ assert(!posInfInterval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 3))));
+ assert(!posInfInterval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 4))));
+ assert(!posInfInterval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 5))));
+ assert(!posInfInterval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 6))));
+ assert(!posInfInterval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 7))));
+ assert(!posInfInterval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 8))));
+
+ assert(!PosInfInterval!Date(Date(2010, 7, 3)).isAdjacent(posInfInterval));
+ assert(!PosInfInterval!Date(Date(2010, 7, 4)).isAdjacent(posInfInterval));
+ assert(!PosInfInterval!Date(Date(2010, 7, 5)).isAdjacent(posInfInterval));
+ assert(!PosInfInterval!Date(Date(2012, 1, 6)).isAdjacent(posInfInterval));
+ assert(!PosInfInterval!Date(Date(2012, 1, 7)).isAdjacent(posInfInterval));
+ assert(!PosInfInterval!Date(Date(2012, 1, 8)).isAdjacent(posInfInterval));
+
+ assert(!posInfInterval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 3))));
+ assert(posInfInterval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 4))));
+ assert(!posInfInterval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 5))));
+ assert(!posInfInterval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 6))));
+ assert(!posInfInterval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 7))));
+ assert(!posInfInterval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 8))));
+
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, posInfInterval.isAdjacent(interval)));
+ static assert(__traits(compiles, posInfInterval.isAdjacent(cInterval)));
+ static assert(__traits(compiles, posInfInterval.isAdjacent(iInterval)));
+ static assert(__traits(compiles, posInfInterval.isAdjacent(posInfInterval)));
+ static assert(__traits(compiles, posInfInterval.isAdjacent(cPosInfInterval)));
+ static assert(__traits(compiles, posInfInterval.isAdjacent(iPosInfInterval)));
+ static assert(__traits(compiles, posInfInterval.isAdjacent(negInfInterval)));
+ static assert(__traits(compiles, posInfInterval.isAdjacent(cNegInfInterval)));
+ static assert(__traits(compiles, posInfInterval.isAdjacent(iNegInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isAdjacent(interval)));
+ static assert(__traits(compiles, cPosInfInterval.isAdjacent(cInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isAdjacent(iInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isAdjacent(posInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isAdjacent(cPosInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isAdjacent(iPosInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isAdjacent(negInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isAdjacent(cNegInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.isAdjacent(iNegInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isAdjacent(interval)));
+ static assert(__traits(compiles, iPosInfInterval.isAdjacent(cInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isAdjacent(iInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isAdjacent(posInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isAdjacent(cPosInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isAdjacent(iPosInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isAdjacent(negInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isAdjacent(cNegInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.isAdjacent(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(Interval!Date(Date(1989, 3, 1), Date(1996, 1, 2))));
+ assert(!PosInfInterval!Date(Date(1999, 1, 12)).isAdjacent(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(PosInfInterval!Date(Date(1990, 1, 7))));
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(PosInfInterval!Date(Date(1996, 1, 2))));
+
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(NegInfInterval!Date(Date(1996, 1, 2))));
+ assert(!PosInfInterval!Date(Date(1996, 1, 2)).isAdjacent(NegInfInterval!Date(Date(2000, 7, 1))));
+}
+
+//Test PosInfInterval's merge().
+unittest
+{
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+
+ static void testInterval(in PosInfInterval!Date posInfInterval, in Interval!Date interval)
+ {
+ posInfInterval.merge(interval);
+ }
+
+ assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
+
+ assertPred!"=="(posInfInterval.merge(posInfInterval),
+ posInfInterval);
+ assertPred!"=="(posInfInterval.merge(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))),
+ PosInfInterval!Date(Date(2010, 7, 1)));
+ assertPred!"=="(posInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))),
+ PosInfInterval!Date(Date(2010, 7, 3)));
+ assertPred!"=="(posInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))),
+ PosInfInterval!Date(Date(2010, 7, 3)));
+ assertPred!"=="(posInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))),
+ PosInfInterval!Date(Date(2010, 7, 3)));
+ assertPred!"=="(posInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))),
+ PosInfInterval!Date(Date(2010, 7, 3)));
+ assertPred!"=="(posInfInterval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.merge(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.merge(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+
+ assertPred!"=="(posInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 3))),
+ PosInfInterval!Date(Date(2010, 7, 3)));
+ assertPred!"=="(posInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 4))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 5))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 6))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 7))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 8))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+
+ assertPred!"=="(PosInfInterval!Date(Date(2010, 7, 3)).merge(posInfInterval),
+ PosInfInterval!Date(Date(2010, 7, 3)));
+ assertPred!"=="(PosInfInterval!Date(Date(2010, 7, 4)).merge(posInfInterval),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(PosInfInterval!Date(Date(2010, 7, 5)).merge(posInfInterval),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(PosInfInterval!Date(Date(2012, 1, 6)).merge(posInfInterval),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(PosInfInterval!Date(Date(2012, 1, 7)).merge(posInfInterval),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(PosInfInterval!Date(Date(2012, 1, 8)).merge(posInfInterval),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+
+ static assert(!__traits(compiles, posInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 3)))));
+ static assert(!__traits(compiles, posInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 4)))));
+ static assert(!__traits(compiles, posInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 5)))));
+ static assert(!__traits(compiles, posInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 6)))));
+ static assert(!__traits(compiles, posInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 7)))));
+ static assert(!__traits(compiles, posInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 8)))));
+
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, posInfInterval.merge(interval)));
+ static assert(__traits(compiles, posInfInterval.merge(cInterval)));
+ static assert(__traits(compiles, posInfInterval.merge(iInterval)));
+ static assert(__traits(compiles, posInfInterval.merge(posInfInterval)));
+ static assert(__traits(compiles, posInfInterval.merge(cPosInfInterval)));
+ static assert(__traits(compiles, posInfInterval.merge(iPosInfInterval)));
+ static assert(!__traits(compiles, posInfInterval.merge(negInfInterval)));
+ static assert(!__traits(compiles, posInfInterval.merge(cNegInfInterval)));
+ static assert(!__traits(compiles, posInfInterval.merge(iNegInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.merge(interval)));
+ static assert(__traits(compiles, cPosInfInterval.merge(cInterval)));
+ static assert(__traits(compiles, cPosInfInterval.merge(iInterval)));
+ static assert(__traits(compiles, cPosInfInterval.merge(posInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.merge(cPosInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.merge(iPosInfInterval)));
+ static assert(!__traits(compiles, cPosInfInterval.merge(negInfInterval)));
+ static assert(!__traits(compiles, cPosInfInterval.merge(cNegInfInterval)));
+ static assert(!__traits(compiles, cPosInfInterval.merge(iNegInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.merge(interval)));
+ static assert(__traits(compiles, iPosInfInterval.merge(cInterval)));
+ static assert(__traits(compiles, iPosInfInterval.merge(iInterval)));
+ static assert(__traits(compiles, iPosInfInterval.merge(posInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.merge(cPosInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.merge(iPosInfInterval)));
+ static assert(!__traits(compiles, iPosInfInterval.merge(negInfInterval)));
+ static assert(!__traits(compiles, iPosInfInterval.merge(cNegInfInterval)));
+ static assert(!__traits(compiles, iPosInfInterval.merge(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == PosInfInterval!Date(Date(1990, 7 , 6)));
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) == PosInfInterval!Date(Date(1996, 1 , 2)));
+
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1990, 7 , 6)));
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).merge(PosInfInterval!Date(Date(1999, 1, 12))) == PosInfInterval!Date(Date(1996, 1 , 2)));
+}
+
+//Test PosInfInterval's span().
+unittest
+{
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+
+ static void testInterval(in PosInfInterval!Date posInfInterval, in Interval!Date interval)
+ {
+ posInfInterval.span(interval);
+ }
+
+ assertThrown!DateTimeException(testInterval(posInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assertPred!"=="(posInfInterval.span(posInfInterval),
+ posInfInterval);
+ assertPred!"=="(posInfInterval.span(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))),
+ PosInfInterval!Date(Date(2010, 7, 1)));
+ assertPred!"=="(posInfInterval.span(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))),
+ PosInfInterval!Date(Date(2010, 7, 1)));
+ assertPred!"=="(posInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))),
+ PosInfInterval!Date(Date(2010, 7, 3)));
+ assertPred!"=="(posInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))),
+ PosInfInterval!Date(Date(2010, 7, 3)));
+ assertPred!"=="(posInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))),
+ PosInfInterval!Date(Date(2010, 7, 3)));
+ assertPred!"=="(posInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))),
+ PosInfInterval!Date(Date(2010, 7, 3)));
+ assertPred!"=="(posInfInterval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.span(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.span(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+
+ assertPred!"=="(posInfInterval.span(PosInfInterval!Date(Date(2010, 7, 3))),
+ PosInfInterval!Date(Date(2010, 7, 3)));
+ assertPred!"=="(posInfInterval.span(PosInfInterval!Date(Date(2010, 7, 4))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.span(PosInfInterval!Date(Date(2010, 7, 5))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.span(PosInfInterval!Date(Date(2012, 1, 6))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.span(PosInfInterval!Date(Date(2012, 1, 7))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(posInfInterval.span(PosInfInterval!Date(Date(2012, 1, 8))),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+
+ assertPred!"=="(PosInfInterval!Date(Date(2010, 7, 3)).span(posInfInterval),
+ PosInfInterval!Date(Date(2010, 7, 3)));
+ assertPred!"=="(PosInfInterval!Date(Date(2010, 7, 4)).span(posInfInterval),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(PosInfInterval!Date(Date(2010, 7, 5)).span(posInfInterval),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(PosInfInterval!Date(Date(2012, 1, 6)).span(posInfInterval),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(PosInfInterval!Date(Date(2012, 1, 7)).span(posInfInterval),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(PosInfInterval!Date(Date(2012, 1, 8)).span(posInfInterval),
+ PosInfInterval!Date(Date(2010, 7, 4)));
+
+ static assert(!__traits(compiles, posInfInterval.span(NegInfInterval!Date(Date(2010, 7, 3)))));
+ static assert(!__traits(compiles, posInfInterval.span(NegInfInterval!Date(Date(2010, 7, 4)))));
+ static assert(!__traits(compiles, posInfInterval.span(NegInfInterval!Date(Date(2010, 7, 5)))));
+ static assert(!__traits(compiles, posInfInterval.span(NegInfInterval!Date(Date(2012, 1, 6)))));
+ static assert(!__traits(compiles, posInfInterval.span(NegInfInterval!Date(Date(2012, 1, 7)))));
+ static assert(!__traits(compiles, posInfInterval.span(NegInfInterval!Date(Date(2012, 1, 8)))));
+
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, posInfInterval.span(interval)));
+ static assert(__traits(compiles, posInfInterval.span(cInterval)));
+ static assert(__traits(compiles, posInfInterval.span(iInterval)));
+ static assert(__traits(compiles, posInfInterval.span(posInfInterval)));
+ static assert(__traits(compiles, posInfInterval.span(cPosInfInterval)));
+ static assert(__traits(compiles, posInfInterval.span(iPosInfInterval)));
+ static assert(!__traits(compiles, posInfInterval.span(negInfInterval)));
+ static assert(!__traits(compiles, posInfInterval.span(cNegInfInterval)));
+ static assert(!__traits(compiles, posInfInterval.span(iNegInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.span(interval)));
+ static assert(__traits(compiles, cPosInfInterval.span(cInterval)));
+ static assert(__traits(compiles, cPosInfInterval.span(iInterval)));
+ static assert(__traits(compiles, cPosInfInterval.span(posInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.span(cPosInfInterval)));
+ static assert(__traits(compiles, cPosInfInterval.span(iPosInfInterval)));
+ static assert(!__traits(compiles, cPosInfInterval.span(negInfInterval)));
+ static assert(!__traits(compiles, cPosInfInterval.span(cNegInfInterval)));
+ static assert(!__traits(compiles, cPosInfInterval.span(iNegInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.span(interval)));
+ static assert(__traits(compiles, iPosInfInterval.span(cInterval)));
+ static assert(__traits(compiles, iPosInfInterval.span(iInterval)));
+ static assert(__traits(compiles, iPosInfInterval.span(posInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.span(cPosInfInterval)));
+ static assert(__traits(compiles, iPosInfInterval.span(iPosInfInterval)));
+ static assert(!__traits(compiles, iPosInfInterval.span(negInfInterval)));
+ static assert(!__traits(compiles, iPosInfInterval.span(cNegInfInterval)));
+ static assert(!__traits(compiles, iPosInfInterval.span(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).span(Interval!Date(Date(500, 8, 9), Date(1602, 1, 31))) == PosInfInterval!Date(Date(500, 8, 9)));
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).span(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == PosInfInterval!Date(Date(1990, 7 , 6)));
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).span(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))) == PosInfInterval!Date(Date(1996, 1 , 2)));
+
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).span(PosInfInterval!Date(Date(1990, 7, 6))) == PosInfInterval!Date(Date(1990, 7 , 6)));
+ assert(PosInfInterval!Date(Date(1996, 1, 2)).span(PosInfInterval!Date(Date(1999, 1, 12))) == PosInfInterval!Date(Date(1996, 1 , 2)));
+}
+
+//Test PosInfInterval's shift().
+unittest
+{
+ auto interval = PosInfInterval!Date(Date(2010, 7, 4));
+
+ static void testInterval(I)(I interval, in Duration duration, in I expected, size_t line = __LINE__)
+ {
+ interval.shift(duration);
+ assertPred!"=="(interval, expected, "", __FILE__, line);
+ }
+
+ testInterval(interval, dur!"days"(22), PosInfInterval!Date(Date(2010, 7, 26)));
+ testInterval(interval, dur!"days"(-22), PosInfInterval!Date(Date(2010, 6, 12)));
+
+ const cInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ static assert(!__traits(compiles, cInterval.shift(dur!"days"(5))));
+ static assert(!__traits(compiles, iInterval.shift(dur!"days"(5))));
+
+ //Verify Examples.
+ auto interval1 = PosInfInterval!Date(Date(1996, 1, 2));
+ auto interval2 = PosInfInterval!Date(Date(1996, 1, 2));
+
+ interval1.shift(dur!"days"(50));
+ assert(interval1 == PosInfInterval!Date(Date(1996, 2, 21)));
+
+ interval2.shift(dur!"days"(-50));
+ assert(interval2 == PosInfInterval!Date(Date(1995, 11, 13)));
+}
+
+//Test PosInfInterval's shift(int, int, AllowDayOverflow).
+unittest
+{
+ {
+ auto interval = PosInfInterval!Date(Date(2010, 7, 4));
+
+ static void testInterval(I)(I interval, int years, int months, AllowDayOverflow allow, in I expected, size_t line = __LINE__)
+ {
+ interval.shift(years, months, allow);
+ assertPred!"=="(interval, expected, "", __FILE__, line);
+ }
+
+ testInterval(interval, 5, 0, AllowDayOverflow.yes, PosInfInterval!Date(Date(2015, 7, 4)));
+ testInterval(interval, -5, 0, AllowDayOverflow.yes, PosInfInterval!Date(Date(2005, 7, 4)));
+
+ auto interval2 = PosInfInterval!Date(Date(2000, 1, 29));
+
+ testInterval(interval2, 1, 1, AllowDayOverflow.yes, PosInfInterval!Date(Date(2001, 3, 1)));
+ testInterval(interval2, 1, -1, AllowDayOverflow.yes, PosInfInterval!Date(Date(2000, 12, 29)));
+ testInterval(interval2, -1, -1, AllowDayOverflow.yes, PosInfInterval!Date(Date(1998, 12, 29)));
+ testInterval(interval2, -1, 1, AllowDayOverflow.yes, PosInfInterval!Date(Date(1999, 3, 1)));
+
+ testInterval(interval2, 1, 1, AllowDayOverflow.no, PosInfInterval!Date(Date(2001, 2, 28)));
+ testInterval(interval2, 1, -1, AllowDayOverflow.no, PosInfInterval!Date(Date(2000, 12, 29)));
+ testInterval(interval2, -1, -1, AllowDayOverflow.no, PosInfInterval!Date(Date(1998, 12, 29)));
+ testInterval(interval2, -1, 1, AllowDayOverflow.no, PosInfInterval!Date(Date(1999, 2, 28)));
+ }
+
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ static assert(!__traits(compiles, cPosInfInterval.shift(1)));
+ static assert(!__traits(compiles, iPosInfInterval.shift(1)));
+
+ //Verify Examples.
+ auto interval1 = PosInfInterval!Date(Date(1996, 1, 2));
+ auto interval2 = PosInfInterval!Date(Date(1996, 1, 2));
+
+ interval1.shift(2);
+ assert(interval1 == PosInfInterval!Date(Date(1998, 1, 2)));
+
+ interval2.shift(-2);
+ assert(interval2 == PosInfInterval!Date(Date(1994, 1, 2)));
+}
+
+//Test PosInfInterval's expand().
+unittest
+{
+ auto interval = PosInfInterval!Date(Date(2000, 7, 4));
+
+ static void testInterval(I)(I interval, in Duration duration, in I expected, size_t line = __LINE__)
+ {
+ interval.expand(duration);
+ assertPred!"=="(interval, expected, "", __FILE__, line);
+ }
+
+ testInterval(interval, dur!"days"(22), PosInfInterval!Date(Date(2000, 6, 12)));
+ testInterval(interval, dur!"days"(-22), PosInfInterval!Date(Date(2000, 7, 26)));
+
+ const cInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ static assert(!__traits(compiles, cInterval.expand(dur!"days"(5))));
+ static assert(!__traits(compiles, iInterval.expand(dur!"days"(5))));
+
+ //Verify Examples.
+ auto interval1 = PosInfInterval!Date(Date(1996, 1, 2));
+ auto interval2 = PosInfInterval!Date(Date(1996, 1, 2));
+
+ interval1.expand(dur!"days"(2));
+ assert(interval1 == PosInfInterval!Date(Date(1995, 12, 31)));
+
+ interval2.expand(dur!"days"(-2));
+ assert(interval2 == PosInfInterval!Date(Date(1996, 1, 4)));
+}
+
+//Test PosInfInterval's expand(int, int, AllowDayOverflow).
+unittest
+{
+ {
+ auto interval = PosInfInterval!Date(Date(2000, 7, 4));
+
+ static void testInterval(I)(I interval, int years, int months, AllowDayOverflow allow, in I expected, size_t line = __LINE__)
+ {
+ interval.expand(years, months, allow);
+ assertPred!"=="(interval, expected, "", __FILE__, line);
+ }
+
+ testInterval(interval, 5, 0, AllowDayOverflow.yes, PosInfInterval!Date(Date(1995, 7, 4)));
+ testInterval(interval, -5, 0, AllowDayOverflow.yes, PosInfInterval!Date(Date(2005, 7, 4)));
+
+ auto interval2 = PosInfInterval!Date(Date(2000, 1, 29));
+
+ testInterval(interval2, 1, 1, AllowDayOverflow.yes, PosInfInterval!Date(Date(1998, 12, 29)));
+ testInterval(interval2, 1, -1, AllowDayOverflow.yes, PosInfInterval!Date(Date(1999, 3, 1)));
+ testInterval(interval2, -1, -1, AllowDayOverflow.yes, PosInfInterval!Date(Date(2001, 3, 1)));
+ testInterval(interval2, -1, 1, AllowDayOverflow.yes, PosInfInterval!Date(Date(2000, 12, 29)));
+
+ testInterval(interval2, 1, 1, AllowDayOverflow.no, PosInfInterval!Date(Date(1998, 12, 29)));
+ testInterval(interval2, 1, -1, AllowDayOverflow.no, PosInfInterval!Date(Date(1999, 2, 28)));
+ testInterval(interval2, -1, -1, AllowDayOverflow.no, PosInfInterval!Date(Date(2001, 2, 28)));
+ testInterval(interval2, -1, 1, AllowDayOverflow.no, PosInfInterval!Date(Date(2000, 12, 29)));
+ }
+
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ static assert(!__traits(compiles, cPosInfInterval.expand(1)));
+ static assert(!__traits(compiles, iPosInfInterval.expand(1)));
+
+ //Verify Examples.
+ auto interval1 = PosInfInterval!Date(Date(1996, 1, 2));
+ auto interval2 = PosInfInterval!Date(Date(1996, 1, 2));
+
+ interval1.expand(2);
+ assert(interval1 == PosInfInterval!Date(Date(1994, 1, 2)));
+
+ interval2.expand(-2);
+ assert(interval2 == PosInfInterval!Date(Date(1998, 1, 2)));
+}
+
+//Test PosInfInterval's fwdRange().
+unittest
+{
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 9, 19));
+
+ static void testInterval(PosInfInterval!Date posInfInterval)
+ {
+ posInfInterval.fwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).popFront();
+ }
+
+ assertThrown!DateTimeException(testInterval(posInfInterval));
+
+ assertPred!"=="(PosInfInterval!Date(Date(2010, 9, 12)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).front,
+ Date(2010, 9, 12));
+
+ assertPred!"=="(PosInfInterval!Date(Date(2010, 9, 12)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri), PopFirst.yes).front,
+ Date(2010, 9, 17));
+
+ //Verify Examples.
+ auto interval = PosInfInterval!Date(Date(2010, 9, 1));
+ auto func = (in Date date)
+ {
+ if((date.day & 1) == 0)
+ return date + dur!"days"(2);
+
+ return date + dur!"days"(1);
+ };
+ auto range = interval.fwdRange(func);
+
+ assert(range.front == Date(2010, 9, 1)); //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 2).
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 2));
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 4));
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 6));
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 8));
+
+ range.popFront();
+ assert(!range.empty);
+
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ static assert(__traits(compiles, cPosInfInterval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri))));
+ static assert(__traits(compiles, iPosInfInterval.fwdRange(everyDayOfWeek!Date(DayOfWeek.fri))));
+}
+
+//Test PosInfInterval's toString().
+unittest
+{
+ assertPred!"=="(PosInfInterval!Date(Date(2010, 7, 4)).toString(), "[2010-Jul-04 - ∞)");
+
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ static assert(__traits(compiles, cPosInfInterval.toString()));
+ static assert(__traits(compiles, iPosInfInterval.toString()));
+}
+
+
+/++
+ Represents an interval of time which has negative infinity as its begin point.
+
+ Any ranges which iterate over a $(D NegInfInterval) are infinite. So, the
+ main purpose of using $(D NegInfInterval) is to create an infinite range
+ which starts at negative infinity and goes to a fixed end point. You would
+ then iterate over it in reverse.
+ +/
+struct NegInfInterval(TP)
+{
+public:
+
+ /++
+ Params:
+ begin = The time point which begins the interval.
+
+ Examples:
+--------------------
+auto interval = PosInfInterval!Date(Date(1996, 1, 2));
+--------------------
+ +/
+ this(in TP end) pure nothrow
+ {
+ _end = cast(TP)end;
+ }
+
+
+ /++
+ Params:
+ rhs = The NegInfInterval to assign to this one.
+ +/
+ /+ref+/ NegInfInterval opAssign(const ref NegInfInterval rhs) pure nothrow
+ {
+ _end = cast(TP)rhs._end;
+
+ return this;
+ }
+
+
+ /++
+ Params:
+ rhs = The NegInfInterval to assign to this one.
+ +/
+ /+ref+/ NegInfInterval opAssign(NegInfInterval rhs) pure nothrow
+ {
+ _end = cast(TP)rhs._end;
+
+ return this;
+ }
+
+
+ /++
+ The end point of the interval. It is excluded from the interval.
+
+ Examples:
+--------------------
+assert(NegInfInterval!Date(Date(2012, 3, 1)).end == Date(2012, 3, 1));
+--------------------
+ +/
+ @property TP end() const pure nothrow
+ {
+ return cast(TP)_end;
+ }
+
+
+ /++
+ The end point of the interval. It is excluded from the interval.
+
+ Params:
+ timePoint = The time point to set end to.
+ +/
+ @property void end(TP timePoint) pure nothrow
+ {
+ _end = timePoint;
+ }
+
+
+ /++
+ Whether the interval's length is 0. Always returns false.
+
+ Examples:
+--------------------
+assert(!NegInfInterval!Date(Date(1996, 1, 2)).empty);
+--------------------
+ +/
+ @property bool empty() const pure nothrow
+ {
+ return false;
+ }
+
+
+ /++
+ Whether the given time point is within this interval.
+
+ Params:
+ timePoint = The time point to check for inclusion in this interval.
+
+ Examples:
+--------------------
+assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Date(1994, 12, 24)));
+assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Date(2000, 1, 5)));
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(Date(2012, 3, 1)));
+--------------------
+ +/
+ bool contains(TP timePoint) const pure nothrow
+ {
+ return timePoint < _end;
+ }
+
+
+ /++
+ Whether the given interval is completely within this interval.
+
+ Params:
+ interval = The interval to check for inclusion in this interval.
+
+ Throws:
+ DateTimeException if the given interval is empty.
+
+ Examples:
+--------------------
+assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(Interval!Date(Date(1998, 2, 28), Date(2013, 5, 1))));
+--------------------
+ +/
+ bool contains(in Interval!TP interval) const pure
+ {
+ interval._enforceNotEmpty();
+
+ return interval._end <= _end;
+ }
+
+
+ /++
+ Whether the given interval is completely within this interval.
+
+ Always returns false because an interval beginning at negative infinity
+ can never contain an interval going to positive infinity.
+
+ Params:
+ interval = The interval to check for inclusion in this interval.
+
+ Examples:
+--------------------
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(PosInfInterval!Date(Date(1999, 5, 4))));
+--------------------
+ +/
+ bool contains(in PosInfInterval!TP interval) const pure nothrow
+ {
+ return false;
+ }
+
+
+ /++
+ Whether the given interval is completely within this interval.
+
+ Params:
+ interval = The interval to check for inclusion in this interval.
+
+ Examples:
+--------------------
+assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(NegInfInterval!Date(Date(1996, 5, 4))));
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(NegInfInterval!Date(Date(2013, 7, 9))));
+--------------------
+ +/
+ bool contains(in NegInfInterval interval) const pure nothrow
+ {
+ return interval._end <= _end;
+ }
+
+
+ /++
+ Whether this interval is before the given time point.
+
+ Params:
+ timePoint = The time point to check whether this interval is
+ before it.
+
+ Examples:
+--------------------
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Date(1994, 12, 24)));
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Date(2000, 1, 5)));
+assert(NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Date(2012, 3, 1)));
+--------------------
+ +/
+ bool isBefore(in TP timePoint) const pure nothrow
+ {
+ return timePoint >= _end;
+ }
+
+
+ /++
+ Whether this interval is before the given interval and does not
+ intersect with it.
+
+ Params:
+ interval = The interval to check for against this interval.
+
+ Throws:
+ DateTimeException if the given interval is empty
+
+ Examples:
+--------------------
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+assert(NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3))));
+--------------------
+ +/
+ bool isBefore(in Interval!TP interval) const pure
+ {
+ interval._enforceNotEmpty();
+
+ return _end <= interval._begin;
+ }
+
+
+ /++
+ Whether this interval is before the given interval and does not
+ intersect with it.
+
+ Params:
+ interval = The interval to check for against this interval.
+
+ Examples:
+--------------------
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(PosInfInterval!Date(Date(1999, 5, 4))));
+assert(NegInfInterval!Date(Date(2012, 3, 1)).isBefore(PosInfInterval!Date(Date(2012, 3, 1))));
+--------------------
+ +/
+ bool isBefore(in PosInfInterval!TP interval) const pure nothrow
+ {
+ return _end <= interval._begin;
+ }
+
+
+ /++
+ Whether this interval is before the given interval and does not
+ intersect with it.
+
+ Always returns false because an interval beginning at negative
+ infinity can never be before another interval beginning at negative
+ infinity.
+
+ Params:
+ interval = The interval to check for against this interval.
+
+ Examples:
+--------------------
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(NegInfInterval!Date(Date(1996, 5, 4))));
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(NegInfInterval!Date(Date(2013, 7, 9))));
+--------------------
+ +/
+ bool isBefore(in NegInfInterval interval) const pure nothrow
+ {
+ return false;
+ }
+
+
+ /++
+ Whether this interval is after the given time point.
+
+ Always returns false because an interval begginning at negative infinity
+ can never be after any time point.
+
+ Params:
+ timePoint = The time point to check whether this Interval is after it.
+
+ Examples:
+--------------------
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Date(1994, 12, 24)));
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Date(2000, 1, 5)));
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Date(2012, 3, 1)));
+--------------------
+ +/
+ bool isAfter(in TP timePoint) const pure nothrow
+ {
+ return false;
+ }
+
+
+ /++
+ Whether this interval is after the given interval and does not
+ intersect with it.
+
+ Always returns false (unless the given interval is empty) because an
+ interval beginning at negative infinity can never be after any other
+ interval.
+
+ Params:
+ interval = The interval to check against this interval.
+
+ Throws:
+ DateTimeException if the given interval is empty.
+
+ Examples:
+--------------------
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3))));
+--------------------
+ +/
+ bool isAfter(in Interval!TP interval) const pure
+ {
+ interval._enforceNotEmpty();
+
+ return false;
+ }
+
+
+ /++
+ Whether this interval is after the given interval and does not intersect
+ with it.
+
+ Always returns false because an interval beginning at negative infinity
+ can never be after any other interval.
+
+ Params:
+ interval = The interval to check against this interval.
+
+ Examples:
+--------------------
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(PosInfInterval!Date(Date(1999, 5, 4))));
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(PosInfInterval!Date(Date(2012, 3, 1))));
+--------------------
+ +/
+ bool isAfter(in PosInfInterval!TP interval) const pure nothrow
+ {
+ return false;
+ }
+
+
+ /++
+ Whether this interval is after the given interval and does not intersect
+ with it.
+
+ Always returns false because an interval beginning at negative infinity
+ can never be after any other interval.
+
+ Params:
+ interval = The interval to check against this interval.
+
+ Examples:
+--------------------
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(NegInfInterval!Date(Date(1996, 5, 4))));
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(NegInfInterval!Date(Date(2013, 7, 9))));
+--------------------
+ +/
+ bool isAfter(in NegInfInterval interval) const pure nothrow
+ {
+ return false;
+ }
+
+
+ /++
+ Whether the given interval overlaps with this interval.
+
+ Params:
+ interval = The interval to check for intersection with this interval.
+
+ Throws:
+ DateTimeException if the given interval is empty.
+
+ Examples:
+--------------------
+assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).intersects(Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3))));
+--------------------
+ +/
+ bool intersects(in Interval!TP interval) const pure
+ {
+ interval._enforceNotEmpty();
+
+ return interval._begin < _end;
+ }
+
+
+ /++
+ Whether the given interval overlaps with this interval.
+
+ Params:
+ interval = The interval to check for intersection with this interval.
+
+ Examples:
+--------------------
+assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(PosInfInterval!Date(Date(1999, 5, 4))));
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).intersects(PosInfInterval!Date(Date(2012, 3, 1))));
+--------------------
+ +/
+ bool intersects(in PosInfInterval!TP interval) const pure nothrow
+ {
+ return interval._begin < _end;
+ }
+
+
+ /++
+ Whether the given interval overlaps with this interval.
+
+ Always returns true because two intervals beginning at negative infinity
+ always overlap.
+
+ Params:
+ interval = The interval to check for intersection with this interval.
+
+ Examples:
+--------------------
+assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(NegInfInterval!Date(Date(1996, 5, 4))));
+assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(NegInfInterval!Date(Date(2013, 7, 9))));
+--------------------
+ +/
+ bool intersects(in NegInfInterval!TP interval) const pure nothrow
+ {
+ return true;
+ }
+
+
+ /++
+ Returns the intersection of two intervals
+
+ Params:
+ interval = The interval to intersect with this interval.
+
+ Throws:
+ DateTimeException if the two intervals do not intersect or if the
+ given interval is empty.
+
+ Examples:
+--------------------
+assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == Interval!Date(Date(1990, 7 , 6), Date(2000, 8, 2)));
+assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(Interval!Date(Date(1999, 1, 12), Date(2015, 9, 2))) == Interval!Date(Date(1999, 1 , 12), Date(2012, 3, 1)));
+--------------------
+ +/
+ Interval!TP intersection(in Interval!TP interval) const
+ {
+ enforce(this.intersects(interval), new DateTimeException(format("%s and %s do not intersect.", this, interval)));
+
+ auto end = _end < interval._end ? _end : interval._end;
+
+ return Interval!TP(interval._begin, end);
+ }
+
+
+ /++
+ Returns the intersection of two intervals
+
+ Params:
+ interval = The interval to intersect with this interval.
+
+ Throws:
+ DateTimeException if the two intervals do not intersect.
+
+ Examples:
+--------------------
+assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(PosInfInterval!Date(Date(1990, 7, 6))) == Interval!Date(Date(1990, 7 , 6), Date(2012, 3, 1)));
+assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(PosInfInterval!Date(Date(1999, 1, 12))) == Interval!Date(Date(1999, 1 , 12), Date(2012, 3, 1)));
+--------------------
+ +/
+ Interval!TP intersection(in PosInfInterval!TP interval) const
+ {
+ enforce(this.intersects(interval), new DateTimeException(format("%s and %s do not intersect.", this, interval)));
+
+ return Interval!TP(interval._begin, _end);
+ }
+
+
+ /++
+ Returns the intersection of two intervals
+
+ Params:
+ interval = The interval to intersect with this interval.
+
+ Examples:
+--------------------
+assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(NegInfInterval!Date(Date(1999, 7, 6))) == NegInfInterval!Date(Date(1999, 7 , 6)));
+assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2012, 3 , 1)));
+--------------------
+ +/
+ NegInfInterval intersection(in NegInfInterval interval) const nothrow
+ {
+ return NegInfInterval(_end < interval._end ? _end : interval._end);
+ }
+
+
+ /++
+ Whether the given interval is adjacent to this interval.
+
+ Params:
+ interval = The interval to check whether its adjacent with this
+ interval.
+
+ Throws:
+ DateTimeException if the given interval is empty.
+
+ Examples:
+--------------------
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(1999, 1, 12), Date(2012, 3, 1))));
+assert(NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(2012, 3, 1), Date(2019, 2, 2))));
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3))));
+--------------------
+ +/
+ bool isAdjacent(in Interval!TP interval) const pure
+ {
+ interval._enforceNotEmpty();
+
+ return interval._begin == _end;
+ }
+
+
+ /++
+ Whether the given interval is adjacent to this interval.
+
+ Params:
+ interval = The interval to check whether its adjacent with this
+ interval.
+
+ Examples:
+--------------------
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(PosInfInterval!Date(Date(1999, 5, 4))));
+assert(NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(PosInfInterval!Date(Date(2012, 3, 1))));
+--------------------
+ +/
+ bool isAdjacent(in PosInfInterval!TP interval) const pure nothrow
+ {
+ return interval._begin == _end;
+ }
+
+
+ /++
+ Whether the given interval is adjacent to this interval.
+
+ Always returns false because two intervals beginning at negative
+ infinity can never be adjacent to one another.
+
+ Params:
+ interval = The interval to check whether its adjacent with this
+ interval.
+
+ Examples:
+--------------------
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(NegInfInterval!Date(Date(1996, 5, 4))));
+assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(NegInfInterval!Date(Date(2012, 3, 1))));
+--------------------
+ +/
+ bool isAdjacent(in NegInfInterval interval) const pure nothrow
+ {
+ return false;
+ }
+
+
+ /++
+ Returns the union of two intervals
+
+ Params:
+ interval = The interval to merge with this interval.
+
+ Throws:
+ DateTimeException if the two intervals do not intersect and are
+ not adjacent or if the given interval is empty.
+
+ Note:
+ There is no overload for $(D merge()) which takes a PosInfInterval.
+ This is because you can't have an interval which goes from negative
+ infinity to positive infinity.
+
+ Examples:
+--------------------
+assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == NegInfInterval!Date(Date(2012, 3 , 1)));
+assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(Interval!Date(Date(1999, 1, 12), Date(2015, 9, 2))) == NegInfInterval!Date(Date(2015, 9 , 2)));
+--------------------
+ +/
+ NegInfInterval merge(in Interval!TP interval) const
+ {
+ enforce(this.isAdjacent(interval) || this.intersects(interval),
+ new DateTimeException(format("%s and %s are not adjacent and do not intersect.", this, interval)));
+
+ return NegInfInterval(_end > interval._end ? _end : interval._end);
+ }
+
+
+ /++
+ Returns the union of two intervals
+
+ Params:
+ interval = The interval to merge with this interval.
+
+ Note:
+ There is no overload for $(D merge()) which takes a PosInfInterval.
+ This is because you can't have an interval which goes from negative
+ infinity to positive infinity.
+
+ Examples:
+--------------------
+assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(NegInfInterval!Date(Date(1999, 7, 6))) == NegInfInterval!Date(Date(2012, 3 , 1)));
+assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2013, 1 , 12)));
+--------------------
+ +/
+ NegInfInterval merge(in NegInfInterval interval) const pure nothrow
+ {
+ return NegInfInterval(_end > interval._end ? _end : interval._end);
+ }
+
+
+ /++
+ Returns an interval that covers from the earliest time point of two
+ intervals up to (but not including) the latest time point of two
+ intervals.
+
+ Params:
+ interval = The interval to create a span together with this
+ interval.
+
+ Throws:
+ DateTimeException if the given interval is empty.
+
+ Note:
+ There is no overload for $(D span()) which takes a PosInfInterval.
+ This is because you can't have an interval which goes from negative
+ infinity to positive infinity.
+
+ Examples:
+--------------------
+assert(NegInfInterval!Date(Date(2012, 3, 1)).span(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == NegInfInterval!Date(Date(2012, 3 , 1)));
+assert(NegInfInterval!Date(Date(2012, 3, 1)).span(Interval!Date(Date(1999, 1, 12), Date(2015, 9, 2))) == NegInfInterval!Date(Date(2015, 9 , 2)));
+assert(NegInfInterval!Date(Date(1600, 1, 7)).span(Interval!Date(Date(2012, 3, 11), Date(2017, 7, 1))) == NegInfInterval!Date(Date(2017, 7 , 1)));
+--------------------
+ +/
+ NegInfInterval span(in Interval!TP interval) const pure
+ {
+ interval._enforceNotEmpty();
+
+ return NegInfInterval(_end > interval._end ? _end : interval._end);
+ }
+
+
+ /++
+ Returns an interval that covers from the earliest time point of two
+ intervals up to (but not including) the latest time point of two
+ intervals.
+
+ Params:
+ interval = The interval to create a span together with this interval.
+
+ Note:
+ There is no overload for $(D span()) which takes a PosInfInterval.
+ This is because you can't have an interval which goes from negative
+ infinity to positive infinity.
+
+ Examples:
+--------------------
+assert(NegInfInterval!Date(Date(2012, 3, 1)).span(NegInfInterval!Date(Date(1999, 7, 6))) == NegInfInterval!Date(Date(2012, 3 , 1)));
+assert(NegInfInterval!Date(Date(2012, 3, 1)).span(NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2013, 1 , 12)));
+--------------------
+ +/
+ NegInfInterval span(in NegInfInterval interval) const pure nothrow
+ {
+ return NegInfInterval(_end > interval._end ? _end : interval._end);
+ }
+
+
+ /++
+ Shifts the end of this interval forward or backwards in time by the
+ given duration (a positive duration shifts the interval forward; a
+ negative duration shifts it backward). Effectively, it does
+ $(D end += duration).
+
+ Params:
+ duration = The duration to shift the interval by.
+
+ Examples:
+--------------------
+auto interval1 = NegInfInterval!Date(Date(2012, 4, 5));
+auto interval2 = NegInfInterval!Date(Date(2012, 4, 5));
+
+interval1.shift(dur!"days"(50));
+assert(interval1 == NegInfInterval!Date(Date(2012, 5, 25)));
+
+interval2.shift(dur!"days"(-50));
+assert(interval2 == NegInfInterval!Date( Date(2012, 2, 15)));
+--------------------
+ +/
+ void shift(D)(D duration) pure nothrow
+ if(__traits(compiles, end + duration))
+ {
+ _end += duration;
+ }
+
+
+ static if(__traits(compiles, end.add!"months"(1)) &&
+ __traits(compiles, end.add!"years"(1)))
+ {
+ /++
+ Shifts the end of this interval forward or backwards in time by the
+ given number of years and/or months (a positive number of years and
+ months shifts the interval forward; a negative number shifts it
+ backward). It adds the years the given years and months to end. It
+ effectively calls $(D add!"years"()) and then $(D add!"months"())
+ on end with the given number of years and months.
+
+ Params:
+ years = The number of years to shift the interval by.
+ months = The number of months to shift the interval by.
+ allowOverflow = Whether the days should be allowed to overflow on end, causing its month to increment.
+
+ Throws:
+ DateTimeException if empty is true or if the resulting interval would be invalid.
+
+ Examples:
+--------------------
+auto interval1 = NegInfInterval!Date(Date(2012, 3, 1));
+auto interval2 = NegInfInterval!Date(Date(2012, 3, 1));
+
+interval1.shift(2);
+assert(interval1 == NegInfInterval!Date(Date(2014, 3, 1)));
+
+interval2.shift(-2);
+assert(interval2 == NegInfInterval!Date(Date(2010, 3, 1)));
+--------------------
+ +/
+ void shift(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
+ if(isIntegral!T)
+ {
+ auto end = _end;
+
+ end.add!"years"(years, allowOverflow);
+ end.add!"months"(months, allowOverflow);
+
+ _end = end;
+ }
+ }
+
+
+ /++
+ Expands the interval forwards in time. Effectively, it does
+ $(D end += duration).
+
+ Params:
+ duration = The duration to expand the interval by.
+ dir = The direction in time to expand the interval.
+
+ Examples:
+--------------------
+auto interval1 = NegInfInterval!Date(Date(2012, 3, 1));
+auto interval2 = NegInfInterval!Date(Date(2012, 3, 1));
+
+interval1.expand(dur!"days"(2));
+assert(interval1 == NegInfInterval!Date(Date(2012, 3, 3)));
+
+interval2.expand(dur!"days"(-2));
+assert(interval2 == NegInfInterval!Date(Date(2012, 2, 28)));
+--------------------
+ +/
+ void expand(D)(D duration) pure nothrow
+ if(__traits(compiles, end + duration))
+ {
+ _end += duration;
+ }
+
+
+ static if(__traits(compiles, end.add!"months"(1)) &&
+ __traits(compiles, end.add!"years"(1)))
+ {
+ /++
+ Expands the interval forwards and/or backwards in time. Effectively,
+ it adds the given number of months/years to end.
+
+ Params:
+ years = The number of years to expand the interval by.
+ months = The number of months to expand the interval by.
+ allowOverflow = Whether the days should be allowed to overflow
+ on end, causing their month to increment.
+
+ Throws:
+ DateTimeException if empty is true or if the resulting interval
+ would be invalid.
+
+ Examples:
+--------------------
+auto interval1 = NegInfInterval!Date(Date(2012, 3, 1));
+auto interval2 = NegInfInterval!Date(Date(2012, 3, 1));
+
+interval1.expand(2);
+assert(interval1 == NegInfInterval!Date(Date(2014, 3, 1)));
+
+interval2.expand(-2);
+assert(interval2 == NegInfInterval!Date(Date(2010, 3, 1)));
+--------------------
+ +/
+ void expand(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
+ if(isIntegral!T)
+ {
+ auto end = _end;
+
+ end.add!"years"(years, allowOverflow);
+ end.add!"months"(months, allowOverflow);
+
+ _end = end;
+
+ return;
+ }
+ }
+
+
+ /++
+ Returns a range which iterates backwards over the interval, starting
+ at end, using $(D func()) to generate each successive time point.
+
+ The range's front is the interval's end. $(D func) is used to generate
+ the next front when $(D popFront()) is called. If $(D popFirst)
+ is true, then $(D popFront()) is called before the range is returned
+ (so that front is a time point which $(D func()) would generate).
+
+ If $(D func()) ever generates a time point less than or equal to the
+ current front of the range, then a DateTimeException will be thrown.
+
+ There are helper functions in this module which generate common delegates
+ to pass to $(D bwdRange()). Their documentation starts with
+ "Generates a range-generating function for intervals," so you can easily
+ search for them.
+
+ Params:
+ func = The function used to generate the time points of the
+ range over the interval.
+ popFirst = Whether popFront() should be called on the range before
+ returning it.
+
+ Warning:
+ func must be logically pure. Ideally, $(D func) would be a function
+ pointer to a pure function, but forcing func to be pure is far too
+ restrictive to be useful, and in order to have the ease of use of
+ having functions which generate functions to pass to $(D fwdRange()),
+ $(D func) must be a delegate.
+
+ If $(D func) retains state which changes as it is called, then some
+ algorithms will not work correctly, because the range's $(D save)
+ will have failed to have really saved the range's state. So, if you
+ want to avoid such bugs, don't pass a delegate which is not
+ logically pure to $(D fwdRange()). If $(D func) is given the same
+ time point with two different calls, it must return the same result
+ both times.
+
+ Of course, none of the functions in this module have this problem, so
+ it's only relevant if you're creating your own delegate.
+
+ Examples:
+--------------------
+auto interval = NegInfInterval!Date(Date(2010, 9, 9));
+auto func = (in Date date) //For iterating over even-numbered days.
+ {
+ if((date.day & 1) == 0)
+ return date - dur!"days"(2);
+
+ return date - dur!"days"(1);
+ };
+auto range = interval.bwdRange(func);
+
+assert(range.front == Date(2010, 9, 9)); //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 8).
+
+range.popFront();
+assert(range.front == Date(2010, 9, 8));
+
+range.popFront();
+assert(range.front == Date(2010, 9, 6));
+
+range.popFront();
+assert(range.front == Date(2010, 9, 4));
+
+range.popFront();
+assert(range.front == Date(2010, 9, 2));
+
+range.popFront();
+assert(!range.empty);
+--------------------
+ +/
+ NegInfIntervalRange!(TP) bwdRange(TP delegate(in TP) func, PopFirst popFirst = PopFirst.no) const
+ {
+ auto range = NegInfIntervalRange!(TP)(this, func);
+
+ if(popFirst == PopFirst.yes)
+ range.popFront();
+
+ return range;
+ }
+
+
+ /+
+ Converts this interval to a string.
+ +/
+ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't
+ //have versions of toString() with extra modifiers, so we define one version
+ //with modifiers and one without.
+ string toString()
+ {
+ return _toStringImpl();
+ }
+
+
+ /++
+ Converts this interval to a string.
+ +/
+ //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't
+ //have versions of toString() with extra modifiers, so we define one version
+ //with modifiers and one without.
+ string toString() const nothrow
+ {
+ return _toStringImpl();
+ }
+
+private:
+
+ /++
+ Since we have two versions of toString(), we have _toStringImpl()
+ so that they can share implementations.
+ +/
+ string _toStringImpl() const nothrow
+ {
+ try
+ return format("[-∞ - %s)", _end);
+ catch(Exception e)
+ assert(0, "format() threw.");
+ }
+
+
+ TP _end;
+}
+
+//Test NegInfInterval's constructor.
+unittest
+{
+ NegInfInterval!Date(Date.init);
+ NegInfInterval!TimeOfDay(TimeOfDay.init);
+ NegInfInterval!DateTime(DateTime.init);
+ NegInfInterval!SysTime(SysTime(0));
+}
+
+//Test NegInfInterval's end.
+unittest
+{
+ assertPred!"=="(NegInfInterval!Date(Date(2010, 1, 1)).end, Date(2010, 1, 1));
+ assertPred!"=="(NegInfInterval!Date(Date(2010, 1, 1)).end, Date(2010, 1, 1));
+ assertPred!"=="(NegInfInterval!Date(Date(1998, 1, 1)).end, Date(1998, 1, 1));
+
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, cNegInfInterval.end));
+ static assert(__traits(compiles, iNegInfInterval.end));
+
+ //Verify Examples.
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).end == Date(2012, 3, 1));
+}
+
+//Test NegInfInterval's empty.
+unittest
+{
+ assert(!NegInfInterval!Date(Date(2010, 1, 1)).empty);
+ assert(!NegInfInterval!TimeOfDay(TimeOfDay(0, 30, 0)).empty);
+ assert(!NegInfInterval!DateTime(DateTime(2010, 1, 1, 0, 30, 0)).empty);
+ assert(!NegInfInterval!SysTime(SysTime(DateTime(2010, 1, 1, 0, 30, 0))).empty);
+
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, cNegInfInterval.empty));
+ static assert(__traits(compiles, iNegInfInterval.empty));
+
+ //Verify Examples.
+ assert(!NegInfInterval!Date(Date(1996, 1, 2)).empty);
+}
+
+//Test NegInfInterval's contains(time point).
+unittest
+{
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+
+ assert(negInfInterval.contains(Date(2009, 7, 4)));
+ assert(negInfInterval.contains(Date(2010, 7, 3)));
+ assert(negInfInterval.contains(Date(2010, 7, 4)));
+ assert(negInfInterval.contains(Date(2010, 7, 5)));
+ assert(negInfInterval.contains(Date(2011, 7, 1)));
+ assert(negInfInterval.contains(Date(2012, 1, 6)));
+ assert(!negInfInterval.contains(Date(2012, 1, 7)));
+ assert(!negInfInterval.contains(Date(2012, 1, 8)));
+ assert(!negInfInterval.contains(Date(2013, 1, 7)));
+
+ const cdate = Date(2010, 7, 6);
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, negInfInterval.contains(cdate)));
+ static assert(__traits(compiles, cNegInfInterval.contains(cdate)));
+ static assert(__traits(compiles, iNegInfInterval.contains(cdate)));
+
+ //Verify Examples.
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Date(1994, 12, 24)));
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Date(2000, 1, 5)));
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(Date(2012, 3, 1)));
+}
+
+//Test NegInfInterval's contains(Interval).
+unittest
+{
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+
+ static void testInterval(in NegInfInterval!Date negInfInterval, in Interval!Date interval)
+ {
+ negInfInterval.contains(interval);
+ }
+
+ assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assert(negInfInterval.contains(negInfInterval));
+ assert(negInfInterval.contains(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
+ assert(!negInfInterval.contains(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
+ assert(negInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
+ assert(negInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
+ assert(negInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
+ assert(!negInfInterval.contains(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
+ assert(negInfInterval.contains(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
+ assert(negInfInterval.contains(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
+ assert(negInfInterval.contains(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
+ assert(!negInfInterval.contains(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
+ assert(!negInfInterval.contains(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
+ assert(!negInfInterval.contains(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
+
+ assert(negInfInterval.contains(NegInfInterval!Date(Date(2010, 7, 3))));
+ assert(negInfInterval.contains(NegInfInterval!Date(Date(2010, 7, 4))));
+ assert(negInfInterval.contains(NegInfInterval!Date(Date(2010, 7, 5))));
+ assert(negInfInterval.contains(NegInfInterval!Date(Date(2012, 1, 6))));
+ assert(negInfInterval.contains(NegInfInterval!Date(Date(2012, 1, 7))));
+ assert(!negInfInterval.contains(NegInfInterval!Date(Date(2012, 1, 8))));
+
+ assert(!NegInfInterval!Date(Date(2010, 7, 3)).contains(negInfInterval));
+ assert(!NegInfInterval!Date(Date(2010, 7, 4)).contains(negInfInterval));
+ assert(!NegInfInterval!Date(Date(2010, 7, 5)).contains(negInfInterval));
+ assert(!NegInfInterval!Date(Date(2012, 1, 6)).contains(negInfInterval));
+ assert(NegInfInterval!Date(Date(2012, 1, 7)).contains(negInfInterval));
+ assert(NegInfInterval!Date(Date(2012, 1, 8)).contains(negInfInterval));
+
+ assert(!negInfInterval.contains(PosInfInterval!Date(Date(2010, 7, 3))));
+ assert(!negInfInterval.contains(PosInfInterval!Date(Date(2010, 7, 4))));
+ assert(!negInfInterval.contains(PosInfInterval!Date(Date(2010, 7, 5))));
+ assert(!negInfInterval.contains(PosInfInterval!Date(Date(2012, 1, 6))));
+ assert(!negInfInterval.contains(PosInfInterval!Date(Date(2012, 1, 7))));
+ assert(!negInfInterval.contains(PosInfInterval!Date(Date(2012, 1, 8))));
+
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, negInfInterval.contains(interval)));
+ static assert(__traits(compiles, negInfInterval.contains(cInterval)));
+ static assert(__traits(compiles, negInfInterval.contains(iInterval)));
+ static assert(__traits(compiles, negInfInterval.contains(posInfInterval)));
+ static assert(__traits(compiles, negInfInterval.contains(cPosInfInterval)));
+ static assert(__traits(compiles, negInfInterval.contains(iPosInfInterval)));
+ static assert(__traits(compiles, negInfInterval.contains(negInfInterval)));
+ static assert(__traits(compiles, negInfInterval.contains(cNegInfInterval)));
+ static assert(__traits(compiles, negInfInterval.contains(iNegInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.contains(interval)));
+ static assert(__traits(compiles, cNegInfInterval.contains(cInterval)));
+ static assert(__traits(compiles, cNegInfInterval.contains(iInterval)));
+ static assert(__traits(compiles, cNegInfInterval.contains(posInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.contains(cPosInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.contains(iPosInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.contains(negInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.contains(cNegInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.contains(iNegInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.contains(interval)));
+ static assert(__traits(compiles, iNegInfInterval.contains(cInterval)));
+ static assert(__traits(compiles, iNegInfInterval.contains(iInterval)));
+ static assert(__traits(compiles, iNegInfInterval.contains(posInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.contains(cPosInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.contains(iPosInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.contains(negInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.contains(cNegInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.contains(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(Interval!Date(Date(1998, 2, 28), Date(2013, 5, 1))));
+
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(PosInfInterval!Date(Date(1999, 5, 4))));
+
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).contains(NegInfInterval!Date(Date(1996, 5, 4))));
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).contains(NegInfInterval!Date(Date(2013, 7, 9))));
+}
+
+//Test NegInfInterval's isBefore(time point).
+unittest
+{
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+
+ assert(!negInfInterval.isBefore(Date(2009, 7, 4)));
+ assert(!negInfInterval.isBefore(Date(2010, 7, 3)));
+ assert(!negInfInterval.isBefore(Date(2010, 7, 4)));
+ assert(!negInfInterval.isBefore(Date(2010, 7, 5)));
+ assert(!negInfInterval.isBefore(Date(2011, 7, 1)));
+ assert(!negInfInterval.isBefore(Date(2012, 1, 6)));
+ assert(negInfInterval.isBefore(Date(2012, 1, 7)));
+ assert(negInfInterval.isBefore(Date(2012, 1, 8)));
+ assert(negInfInterval.isBefore(Date(2013, 1, 7)));
+
+ const cdate = Date(2010, 7, 6);
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, negInfInterval.isBefore(cdate)));
+ static assert(__traits(compiles, cNegInfInterval.isBefore(cdate)));
+ static assert(__traits(compiles, iNegInfInterval.isBefore(cdate)));
+
+ //Verify Examples.
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Date(1994, 12, 24)));
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Date(2000, 1, 5)));
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Date(2012, 3, 1)));
+}
+
+//Test NegInfInterval's isBefore(Interval).
+unittest
+{
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+
+ static void testInterval(in NegInfInterval!Date negInfInterval, in Interval!Date interval)
+ {
+ negInfInterval.isBefore(interval);
+ }
+
+ assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assert(!negInfInterval.isBefore(negInfInterval));
+ assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
+ assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
+ assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
+ assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
+ assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
+ assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
+ assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
+ assert(!negInfInterval.isBefore(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
+ assert(!negInfInterval.isBefore(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
+ assert(!negInfInterval.isBefore(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
+ assert(negInfInterval.isBefore(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
+ assert(negInfInterval.isBefore(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
+
+ assert(!negInfInterval.isBefore(NegInfInterval!Date(Date(2010, 7, 3))));
+ assert(!negInfInterval.isBefore(NegInfInterval!Date(Date(2010, 7, 4))));
+ assert(!negInfInterval.isBefore(NegInfInterval!Date(Date(2010, 7, 5))));
+ assert(!negInfInterval.isBefore(NegInfInterval!Date(Date(2012, 1, 6))));
+ assert(!negInfInterval.isBefore(NegInfInterval!Date(Date(2012, 1, 7))));
+ assert(!negInfInterval.isBefore(NegInfInterval!Date(Date(2012, 1, 8))));
+
+ assert(!NegInfInterval!Date(Date(2010, 7, 3)).isBefore(negInfInterval));
+ assert(!NegInfInterval!Date(Date(2010, 7, 4)).isBefore(negInfInterval));
+ assert(!NegInfInterval!Date(Date(2010, 7, 5)).isBefore(negInfInterval));
+ assert(!NegInfInterval!Date(Date(2012, 1, 6)).isBefore(negInfInterval));
+ assert(!NegInfInterval!Date(Date(2012, 1, 7)).isBefore(negInfInterval));
+ assert(!NegInfInterval!Date(Date(2012, 1, 8)).isBefore(negInfInterval));
+
+ assert(!negInfInterval.isBefore(PosInfInterval!Date(Date(2010, 7, 3))));
+ assert(!negInfInterval.isBefore(PosInfInterval!Date(Date(2010, 7, 4))));
+ assert(!negInfInterval.isBefore(PosInfInterval!Date(Date(2010, 7, 5))));
+ assert(!negInfInterval.isBefore(PosInfInterval!Date(Date(2012, 1, 6))));
+ assert(negInfInterval.isBefore(PosInfInterval!Date(Date(2012, 1, 7))));
+ assert(negInfInterval.isBefore(PosInfInterval!Date(Date(2012, 1, 8))));
+
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, negInfInterval.isBefore(interval)));
+ static assert(__traits(compiles, negInfInterval.isBefore(cInterval)));
+ static assert(__traits(compiles, negInfInterval.isBefore(iInterval)));
+ static assert(__traits(compiles, negInfInterval.isBefore(posInfInterval)));
+ static assert(__traits(compiles, negInfInterval.isBefore(cPosInfInterval)));
+ static assert(__traits(compiles, negInfInterval.isBefore(iPosInfInterval)));
+ static assert(__traits(compiles, negInfInterval.isBefore(negInfInterval)));
+ static assert(__traits(compiles, negInfInterval.isBefore(cNegInfInterval)));
+ static assert(__traits(compiles, negInfInterval.isBefore(iNegInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isBefore(interval)));
+ static assert(__traits(compiles, cNegInfInterval.isBefore(cInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isBefore(iInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isBefore(posInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isBefore(cPosInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isBefore(iPosInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isBefore(negInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isBefore(cNegInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isBefore(iNegInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isBefore(interval)));
+ static assert(__traits(compiles, iNegInfInterval.isBefore(cInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isBefore(iInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isBefore(posInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isBefore(cPosInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isBefore(iPosInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isBefore(negInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isBefore(cNegInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isBefore(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).isBefore(Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3))));
+
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(PosInfInterval!Date(Date(1999, 5, 4))));
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).isBefore(PosInfInterval!Date(Date(2012, 3, 1))));
+
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(NegInfInterval!Date(Date(1996, 5, 4))));
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isBefore(NegInfInterval!Date(Date(2013, 7, 9))));
+}
+
+//Test NegInfInterval's isAfter(time point).
+unittest
+{
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+
+ assert(!negInfInterval.isAfter(Date(2009, 7, 4)));
+ assert(!negInfInterval.isAfter(Date(2010, 7, 3)));
+ assert(!negInfInterval.isAfter(Date(2010, 7, 4)));
+ assert(!negInfInterval.isAfter(Date(2010, 7, 5)));
+ assert(!negInfInterval.isAfter(Date(2011, 7, 1)));
+ assert(!negInfInterval.isAfter(Date(2012, 1, 6)));
+ assert(!negInfInterval.isAfter(Date(2012, 1, 7)));
+ assert(!negInfInterval.isAfter(Date(2012, 1, 8)));
+ assert(!negInfInterval.isAfter(Date(2013, 1, 7)));
+
+ const cdate = Date(2010, 7, 6);
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, negInfInterval.isAfter(cdate)));
+ static assert(__traits(compiles, cNegInfInterval.isAfter(cdate)));
+ static assert(__traits(compiles, iNegInfInterval.isAfter(cdate)));
+}
+
+//Test NegInfInterval's isAfter(Interval).
+unittest
+{
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+
+ static void testInterval(in NegInfInterval!Date negInfInterval, in Interval!Date interval)
+ {
+ negInfInterval.isAfter(interval);
+ }
+
+ assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assert(!negInfInterval.isAfter(negInfInterval));
+ assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
+ assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
+ assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
+ assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
+ assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
+ assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
+ assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
+ assert(!negInfInterval.isAfter(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
+ assert(!negInfInterval.isAfter(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
+ assert(!negInfInterval.isAfter(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
+ assert(!negInfInterval.isAfter(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
+ assert(!negInfInterval.isAfter(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
+
+ assert(!negInfInterval.isAfter(NegInfInterval!Date(Date(2010, 7, 3))));
+ assert(!negInfInterval.isAfter(NegInfInterval!Date(Date(2010, 7, 4))));
+ assert(!negInfInterval.isAfter(NegInfInterval!Date(Date(2010, 7, 5))));
+ assert(!negInfInterval.isAfter(NegInfInterval!Date(Date(2012, 1, 6))));
+ assert(!negInfInterval.isAfter(NegInfInterval!Date(Date(2012, 1, 7))));
+ assert(!negInfInterval.isAfter(NegInfInterval!Date(Date(2012, 1, 8))));
+
+ assert(!NegInfInterval!Date(Date(2010, 7, 3)).isAfter(negInfInterval));
+ assert(!NegInfInterval!Date(Date(2010, 7, 4)).isAfter(negInfInterval));
+ assert(!NegInfInterval!Date(Date(2010, 7, 5)).isAfter(negInfInterval));
+ assert(!NegInfInterval!Date(Date(2012, 1, 6)).isAfter(negInfInterval));
+ assert(!NegInfInterval!Date(Date(2012, 1, 7)).isAfter(negInfInterval));
+ assert(!NegInfInterval!Date(Date(2012, 1, 8)).isAfter(negInfInterval));
+
+ assert(!negInfInterval.isAfter(PosInfInterval!Date(Date(2010, 7, 3))));
+ assert(!negInfInterval.isAfter(PosInfInterval!Date(Date(2010, 7, 4))));
+ assert(!negInfInterval.isAfter(PosInfInterval!Date(Date(2010, 7, 5))));
+ assert(!negInfInterval.isAfter(PosInfInterval!Date(Date(2012, 1, 6))));
+ assert(!negInfInterval.isAfter(PosInfInterval!Date(Date(2012, 1, 7))));
+ assert(!negInfInterval.isAfter(PosInfInterval!Date(Date(2012, 1, 8))));
+
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, negInfInterval.isAfter(interval)));
+ static assert(__traits(compiles, negInfInterval.isAfter(cInterval)));
+ static assert(__traits(compiles, negInfInterval.isAfter(iInterval)));
+ static assert(__traits(compiles, negInfInterval.isAfter(posInfInterval)));
+ static assert(__traits(compiles, negInfInterval.isAfter(cPosInfInterval)));
+ static assert(__traits(compiles, negInfInterval.isAfter(iPosInfInterval)));
+ static assert(__traits(compiles, negInfInterval.isAfter(negInfInterval)));
+ static assert(__traits(compiles, negInfInterval.isAfter(cNegInfInterval)));
+ static assert(__traits(compiles, negInfInterval.isAfter(iNegInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isAfter(interval)));
+ static assert(__traits(compiles, cNegInfInterval.isAfter(cInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isAfter(iInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isAfter(posInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isAfter(cPosInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isAfter(iPosInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isAfter(negInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isAfter(cNegInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isAfter(iNegInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isAfter(interval)));
+ static assert(__traits(compiles, iNegInfInterval.isAfter(cInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isAfter(iInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isAfter(posInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isAfter(cPosInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isAfter(iPosInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isAfter(negInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isAfter(cNegInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isAfter(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Date(1994, 12, 24)));
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Date(2000, 1, 5)));
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Date(2012, 3, 1)));
+
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3))));
+
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(PosInfInterval!Date(Date(1999, 5, 4))));
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(PosInfInterval!Date(Date(2012, 3, 1))));
+
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(NegInfInterval!Date(Date(1996, 5, 4))));
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAfter(NegInfInterval!Date(Date(2013, 7, 9))));
+}
+
+//Test NegInfInterval's intersects().
+unittest
+{
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+
+ static void testInterval(in NegInfInterval!Date negInfInterval, in Interval!Date interval)
+ {
+ negInfInterval.intersects(interval);
+ }
+
+ assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assert(negInfInterval.intersects(negInfInterval));
+ assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
+ assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
+ assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
+ assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
+ assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
+ assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
+ assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
+ assert(negInfInterval.intersects(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
+ assert(negInfInterval.intersects(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
+ assert(negInfInterval.intersects(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
+ assert(!negInfInterval.intersects(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
+ assert(!negInfInterval.intersects(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
+
+ assert(negInfInterval.intersects(NegInfInterval!Date(Date(2010, 7, 3))));
+ assert(negInfInterval.intersects(NegInfInterval!Date(Date(2010, 7, 4))));
+ assert(negInfInterval.intersects(NegInfInterval!Date(Date(2010, 7, 5))));
+ assert(negInfInterval.intersects(NegInfInterval!Date(Date(2012, 1, 6))));
+ assert(negInfInterval.intersects(NegInfInterval!Date(Date(2012, 1, 7))));
+ assert(negInfInterval.intersects(NegInfInterval!Date(Date(2012, 1, 8))));
+
+ assert(NegInfInterval!Date(Date(2010, 7, 3)).intersects(negInfInterval));
+ assert(NegInfInterval!Date(Date(2010, 7, 4)).intersects(negInfInterval));
+ assert(NegInfInterval!Date(Date(2010, 7, 5)).intersects(negInfInterval));
+ assert(NegInfInterval!Date(Date(2012, 1, 6)).intersects(negInfInterval));
+ assert(NegInfInterval!Date(Date(2012, 1, 7)).intersects(negInfInterval));
+ assert(NegInfInterval!Date(Date(2012, 1, 8)).intersects(negInfInterval));
+
+ assert(negInfInterval.intersects(PosInfInterval!Date(Date(2010, 7, 3))));
+ assert(negInfInterval.intersects(PosInfInterval!Date(Date(2010, 7, 4))));
+ assert(negInfInterval.intersects(PosInfInterval!Date(Date(2010, 7, 5))));
+ assert(negInfInterval.intersects(PosInfInterval!Date(Date(2012, 1, 6))));
+ assert(!negInfInterval.intersects(PosInfInterval!Date(Date(2012, 1, 7))));
+ assert(!negInfInterval.intersects(PosInfInterval!Date(Date(2012, 1, 8))));
+
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, negInfInterval.intersects(interval)));
+ static assert(__traits(compiles, negInfInterval.intersects(cInterval)));
+ static assert(__traits(compiles, negInfInterval.intersects(iInterval)));
+ static assert(__traits(compiles, negInfInterval.intersects(posInfInterval)));
+ static assert(__traits(compiles, negInfInterval.intersects(cPosInfInterval)));
+ static assert(__traits(compiles, negInfInterval.intersects(iPosInfInterval)));
+ static assert(__traits(compiles, negInfInterval.intersects(negInfInterval)));
+ static assert(__traits(compiles, negInfInterval.intersects(cNegInfInterval)));
+ static assert(__traits(compiles, negInfInterval.intersects(iNegInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.intersects(interval)));
+ static assert(__traits(compiles, cNegInfInterval.intersects(cInterval)));
+ static assert(__traits(compiles, cNegInfInterval.intersects(iInterval)));
+ static assert(__traits(compiles, cNegInfInterval.intersects(posInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.intersects(cPosInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.intersects(iPosInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.intersects(negInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.intersects(cNegInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.intersects(iNegInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.intersects(interval)));
+ static assert(__traits(compiles, iNegInfInterval.intersects(cInterval)));
+ static assert(__traits(compiles, iNegInfInterval.intersects(iInterval)));
+ static assert(__traits(compiles, iNegInfInterval.intersects(posInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.intersects(cPosInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.intersects(iPosInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.intersects(negInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.intersects(cNegInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.intersects(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(Interval!Date(Date(1999, 1, 12), Date(2011, 9, 17))));
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).intersects(Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3))));
+
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(PosInfInterval!Date(Date(1999, 5, 4))));
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).intersects(PosInfInterval!Date(Date(2012, 3, 1))));
+
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(NegInfInterval!Date(Date(1996, 5, 4))));
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).intersects(NegInfInterval!Date(Date(2013, 7, 9))));
+}
+
+//Test NegInfInterval's intersection().
+unittest
+{
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+
+ static void testInterval(I, J)(in I interval1, in J interval2)
+ {
+ interval1.intersection(interval2);
+ }
+
+ assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
+ assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
+
+ assertThrown!DateTimeException(testInterval(negInfInterval, PosInfInterval!Date(Date(2012, 1, 7))));
+ assertThrown!DateTimeException(testInterval(negInfInterval, PosInfInterval!Date(Date(2012, 1, 8))));
+
+ assertPred!"=="(negInfInterval.intersection(negInfInterval),
+ negInfInterval);
+ assertPred!"=="(negInfInterval.intersection(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))),
+ Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)));
+ assertPred!"=="(negInfInterval.intersection(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))),
+ Interval!Date(Date(2010, 7, 1), Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))),
+ Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)));
+ assertPred!"=="(negInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))),
+ Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)));
+ assertPred!"=="(negInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))),
+ Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))),
+ Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))),
+ Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)));
+ assertPred!"=="(negInfInterval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))),
+ Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))),
+ Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))),
+ Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
+
+ assertPred!"=="(negInfInterval.intersection(NegInfInterval!Date(Date(2010, 7, 3))),
+ NegInfInterval!Date(Date(2010, 7, 3)));
+ assertPred!"=="(negInfInterval.intersection(NegInfInterval!Date(Date(2010, 7, 4))),
+ NegInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(negInfInterval.intersection(NegInfInterval!Date(Date(2010, 7, 5))),
+ NegInfInterval!Date(Date(2010, 7, 5)));
+ assertPred!"=="(negInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 6))),
+ NegInfInterval!Date(Date(2012, 1, 6)));
+ assertPred!"=="(negInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 7))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 8))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+
+ assertPred!"=="(NegInfInterval!Date(Date(2010, 7, 3)).intersection(negInfInterval),
+ NegInfInterval!Date(Date(2010, 7, 3)));
+ assertPred!"=="(NegInfInterval!Date(Date(2010, 7, 4)).intersection(negInfInterval),
+ NegInfInterval!Date(Date(2010, 7, 4)));
+ assertPred!"=="(NegInfInterval!Date(Date(2010, 7, 5)).intersection(negInfInterval),
+ NegInfInterval!Date(Date(2010, 7, 5)));
+ assertPred!"=="(NegInfInterval!Date(Date(2012, 1, 6)).intersection(negInfInterval),
+ NegInfInterval!Date(Date(2012, 1, 6)));
+ assertPred!"=="(NegInfInterval!Date(Date(2012, 1, 7)).intersection(negInfInterval),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(NegInfInterval!Date(Date(2012, 1, 8)).intersection(negInfInterval),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+
+ assertPred!"=="(negInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 3))),
+ Interval!Date(Date(2010, 7, 3), Date(2012, 1 ,7)));
+ assertPred!"=="(negInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 4))),
+ Interval!Date(Date(2010, 7, 4), Date(2012, 1 ,7)));
+ assertPred!"=="(negInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 5))),
+ Interval!Date(Date(2010, 7, 5), Date(2012, 1 ,7)));
+ assertPred!"=="(negInfInterval.intersection(PosInfInterval!Date(Date(2012, 1, 6))),
+ Interval!Date(Date(2012, 1, 6), Date(2012, 1 ,7)));
+
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, negInfInterval.intersection(interval)));
+ static assert(__traits(compiles, negInfInterval.intersection(cInterval)));
+ static assert(__traits(compiles, negInfInterval.intersection(iInterval)));
+ static assert(__traits(compiles, negInfInterval.intersection(posInfInterval)));
+ static assert(__traits(compiles, negInfInterval.intersection(cPosInfInterval)));
+ static assert(__traits(compiles, negInfInterval.intersection(iPosInfInterval)));
+ static assert(__traits(compiles, negInfInterval.intersection(negInfInterval)));
+ static assert(__traits(compiles, negInfInterval.intersection(cNegInfInterval)));
+ static assert(__traits(compiles, negInfInterval.intersection(iNegInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.intersection(interval)));
+ static assert(__traits(compiles, cNegInfInterval.intersection(cInterval)));
+ static assert(__traits(compiles, cNegInfInterval.intersection(iInterval)));
+ static assert(__traits(compiles, cNegInfInterval.intersection(posInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.intersection(cPosInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.intersection(iPosInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.intersection(negInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.intersection(cNegInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.intersection(iNegInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.intersection(interval)));
+ static assert(__traits(compiles, iNegInfInterval.intersection(cInterval)));
+ static assert(__traits(compiles, iNegInfInterval.intersection(iInterval)));
+ static assert(__traits(compiles, iNegInfInterval.intersection(posInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.intersection(cPosInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.intersection(iPosInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.intersection(negInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.intersection(cNegInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.intersection(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == Interval!Date(Date(1990, 7 , 6), Date(2000, 8, 2)));
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(Interval!Date(Date(1999, 1, 12), Date(2015, 9, 2))) == Interval!Date(Date(1999, 1 , 12), Date(2012, 3, 1)));
+
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(PosInfInterval!Date(Date(1990, 7, 6))) == Interval!Date(Date(1990, 7 , 6), Date(2012, 3, 1)));
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(PosInfInterval!Date(Date(1999, 1, 12))) == Interval!Date(Date(1999, 1 , 12), Date(2012, 3, 1)));
+
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(NegInfInterval!Date(Date(1999, 7, 6))) == NegInfInterval!Date(Date(1999, 7 , 6)));
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).intersection(NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2012, 3 , 1)));
+}
+
+//Test NegInfInterval's isAdjacent().
+unittest
+{
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+
+ static void testInterval(in NegInfInterval!Date negInfInterval, in Interval!Date interval)
+ {
+ negInfInterval.isAdjacent(interval);
+ }
+
+ assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assert(!negInfInterval.isAdjacent(negInfInterval));
+ assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))));
+ assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))));
+ assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))));
+ assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))));
+ assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))));
+ assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))));
+ assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))));
+ assert(!negInfInterval.isAdjacent(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))));
+ assert(!negInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))));
+ assert(!negInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))));
+ assert(negInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))));
+ assert(!negInfInterval.isAdjacent(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
+
+ assert(!negInfInterval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 3))));
+ assert(!negInfInterval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 4))));
+ assert(!negInfInterval.isAdjacent(NegInfInterval!Date(Date(2010, 7, 5))));
+ assert(!negInfInterval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 6))));
+ assert(!negInfInterval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 7))));
+ assert(!negInfInterval.isAdjacent(NegInfInterval!Date(Date(2012, 1, 8))));
+
+ assert(!NegInfInterval!Date(Date(2010, 7, 3)).isAdjacent(negInfInterval));
+ assert(!NegInfInterval!Date(Date(2010, 7, 4)).isAdjacent(negInfInterval));
+ assert(!NegInfInterval!Date(Date(2010, 7, 5)).isAdjacent(negInfInterval));
+ assert(!NegInfInterval!Date(Date(2012, 1, 6)).isAdjacent(negInfInterval));
+ assert(!NegInfInterval!Date(Date(2012, 1, 7)).isAdjacent(negInfInterval));
+ assert(!NegInfInterval!Date(Date(2012, 1, 8)).isAdjacent(negInfInterval));
+
+ assert(!negInfInterval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 3))));
+ assert(!negInfInterval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 4))));
+ assert(!negInfInterval.isAdjacent(PosInfInterval!Date(Date(2010, 7, 5))));
+ assert(!negInfInterval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 6))));
+ assert(negInfInterval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 7))));
+ assert(!negInfInterval.isAdjacent(PosInfInterval!Date(Date(2012, 1, 8))));
+
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, negInfInterval.isAdjacent(interval)));
+ static assert(__traits(compiles, negInfInterval.isAdjacent(cInterval)));
+ static assert(__traits(compiles, negInfInterval.isAdjacent(iInterval)));
+ static assert(__traits(compiles, negInfInterval.isAdjacent(posInfInterval)));
+ static assert(__traits(compiles, negInfInterval.isAdjacent(cPosInfInterval)));
+ static assert(__traits(compiles, negInfInterval.isAdjacent(iPosInfInterval)));
+ static assert(__traits(compiles, negInfInterval.isAdjacent(negInfInterval)));
+ static assert(__traits(compiles, negInfInterval.isAdjacent(cNegInfInterval)));
+ static assert(__traits(compiles, negInfInterval.isAdjacent(iNegInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isAdjacent(interval)));
+ static assert(__traits(compiles, cNegInfInterval.isAdjacent(cInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isAdjacent(iInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isAdjacent(posInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isAdjacent(cPosInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isAdjacent(iPosInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isAdjacent(negInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isAdjacent(cNegInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.isAdjacent(iNegInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isAdjacent(interval)));
+ static assert(__traits(compiles, iNegInfInterval.isAdjacent(cInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isAdjacent(iInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isAdjacent(posInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isAdjacent(cPosInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isAdjacent(iPosInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isAdjacent(negInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isAdjacent(cNegInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.isAdjacent(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))));
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(1999, 1, 12), Date(2012, 3, 1))));
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(2012, 3, 1), Date(2019, 2, 2))));
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(Interval!Date(Date(2022, 10, 19), Date(2027, 6, 3))));
+
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(PosInfInterval!Date(Date(1999, 5, 4))));
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(PosInfInterval!Date(Date(2012, 3, 1))));
+
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(NegInfInterval!Date(Date(1996, 5, 4))));
+ assert(!NegInfInterval!Date(Date(2012, 3, 1)).isAdjacent(NegInfInterval!Date(Date(2012, 3, 1))));
+}
+
+//Test NegInfInterval's merge().
+unittest
+{
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+
+ static void testInterval(I, J)(in I interval1, in J interval2)
+ {
+ interval1.merge(interval2);
+ }
+
+ assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))));
+
+ assertPred!"=="(negInfInterval.merge(negInfInterval),
+ negInfInterval);
+ assertPred!"=="(negInfInterval.merge(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.merge(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))),
+ NegInfInterval!Date(Date(2013, 7, 3)));
+ assertPred!"=="(negInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))),
+ NegInfInterval!Date(Date(2012, 1, 8)));
+ assertPred!"=="(negInfInterval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))),
+ NegInfInterval!Date(Date(2012, 1, 8)));
+ assertPred!"=="(negInfInterval.merge(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))),
+ NegInfInterval!Date(Date(2012, 1, 8)));
+
+ assertPred!"=="(negInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 3))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 4))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 5))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 6))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 7))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 8))),
+ NegInfInterval!Date(Date(2012, 1, 8)));
+
+ assertPred!"=="(NegInfInterval!Date(Date(2010, 7, 3)).merge(negInfInterval),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(NegInfInterval!Date(Date(2010, 7, 4)).merge(negInfInterval),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(NegInfInterval!Date(Date(2010, 7, 5)).merge(negInfInterval),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(NegInfInterval!Date(Date(2012, 1, 6)).merge(negInfInterval),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(NegInfInterval!Date(Date(2012, 1, 7)).merge(negInfInterval),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(NegInfInterval!Date(Date(2012, 1, 8)).merge(negInfInterval),
+ NegInfInterval!Date(Date(2012, 1, 8)));
+
+ static assert(!__traits(compiles, negInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 3)))));
+ static assert(!__traits(compiles, negInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 4)))));
+ static assert(!__traits(compiles, negInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 5)))));
+ static assert(!__traits(compiles, negInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 6)))));
+ static assert(!__traits(compiles, negInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 7)))));
+ static assert(!__traits(compiles, negInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 8)))));
+
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, negInfInterval.merge(interval)));
+ static assert(__traits(compiles, negInfInterval.merge(cInterval)));
+ static assert(__traits(compiles, negInfInterval.merge(iInterval)));
+ static assert(!__traits(compiles, negInfInterval.merge(posInfInterval)));
+ static assert(!__traits(compiles, negInfInterval.merge(cPosInfInterval)));
+ static assert(!__traits(compiles, negInfInterval.merge(iPosInfInterval)));
+ static assert(__traits(compiles, negInfInterval.merge(negInfInterval)));
+ static assert(__traits(compiles, negInfInterval.merge(cNegInfInterval)));
+ static assert(__traits(compiles, negInfInterval.merge(iNegInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.merge(interval)));
+ static assert(__traits(compiles, cNegInfInterval.merge(cInterval)));
+ static assert(__traits(compiles, cNegInfInterval.merge(iInterval)));
+ static assert(!__traits(compiles, cNegInfInterval.merge(posInfInterval)));
+ static assert(!__traits(compiles, cNegInfInterval.merge(cPosInfInterval)));
+ static assert(!__traits(compiles, cNegInfInterval.merge(iPosInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.merge(negInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.merge(cNegInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.merge(iNegInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.merge(interval)));
+ static assert(__traits(compiles, iNegInfInterval.merge(cInterval)));
+ static assert(__traits(compiles, iNegInfInterval.merge(iInterval)));
+ static assert(!__traits(compiles, iNegInfInterval.merge(posInfInterval)));
+ static assert(!__traits(compiles, iNegInfInterval.merge(cPosInfInterval)));
+ static assert(!__traits(compiles, iNegInfInterval.merge(iPosInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.merge(negInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.merge(cNegInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.merge(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == NegInfInterval!Date(Date(2012, 3 , 1)));
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(Interval!Date(Date(1999, 1, 12), Date(2015, 9, 2))) == NegInfInterval!Date(Date(2015, 9 , 2)));
+
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(NegInfInterval!Date(Date(1999, 7, 6))) == NegInfInterval!Date(Date(2012, 3 , 1)));
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).merge(NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2013, 1 , 12)));
+}
+
+//Test NegInfInterval's span().
+unittest
+{
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+
+ static void testInterval(I, J)(in I interval1, in J interval2)
+ {
+ interval1.span(interval2);
+ }
+
+ assertThrown!DateTimeException(testInterval(negInfInterval, Interval!Date(Date(2010, 7, 4), dur!"days"(0))));
+
+ assertPred!"=="(negInfInterval.span(negInfInterval),
+ negInfInterval);
+ assertPred!"=="(negInfInterval.span(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.span(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))),
+ NegInfInterval!Date(Date(2013, 7, 3)));
+ assertPred!"=="(negInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))),
+ NegInfInterval!Date(Date(2012, 1, 8)));
+ assertPred!"=="(negInfInterval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))),
+ NegInfInterval!Date(Date(2012, 1, 8)));
+ assertPred!"=="(negInfInterval.span(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))),
+ NegInfInterval!Date(Date(2012, 1, 8)));
+ assertPred!"=="(negInfInterval.span(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))),
+ NegInfInterval!Date(Date(2012, 1, 9)));
+
+ assertPred!"=="(negInfInterval.span(NegInfInterval!Date(Date(2010, 7, 3))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.span(NegInfInterval!Date(Date(2010, 7, 4))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.span(NegInfInterval!Date(Date(2010, 7, 5))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.span(NegInfInterval!Date(Date(2012, 1, 6))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.span(NegInfInterval!Date(Date(2012, 1, 7))),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(negInfInterval.span(NegInfInterval!Date(Date(2012, 1, 8))),
+ NegInfInterval!Date(Date(2012, 1, 8)));
+
+ assertPred!"=="(NegInfInterval!Date(Date(2010, 7, 3)).span(negInfInterval),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(NegInfInterval!Date(Date(2010, 7, 4)).span(negInfInterval),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(NegInfInterval!Date(Date(2010, 7, 5)).span(negInfInterval),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(NegInfInterval!Date(Date(2012, 1, 6)).span(negInfInterval),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(NegInfInterval!Date(Date(2012, 1, 7)).span(negInfInterval),
+ NegInfInterval!Date(Date(2012, 1, 7)));
+ assertPred!"=="(NegInfInterval!Date(Date(2012, 1, 8)).span(negInfInterval),
+ NegInfInterval!Date(Date(2012, 1, 8)));
+
+ static assert(!__traits(compiles, negInfInterval.span(PosInfInterval!Date(Date(2010, 7, 3)))));
+ static assert(!__traits(compiles, negInfInterval.span(PosInfInterval!Date(Date(2010, 7, 4)))));
+ static assert(!__traits(compiles, negInfInterval.span(PosInfInterval!Date(Date(2010, 7, 5)))));
+ static assert(!__traits(compiles, negInfInterval.span(PosInfInterval!Date(Date(2012, 1, 6)))));
+ static assert(!__traits(compiles, negInfInterval.span(PosInfInterval!Date(Date(2012, 1, 7)))));
+ static assert(!__traits(compiles, negInfInterval.span(PosInfInterval!Date(Date(2012, 1, 8)))));
+
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ const cInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ immutable iInterval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ immutable iPosInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, negInfInterval.span(interval)));
+ static assert(__traits(compiles, negInfInterval.span(cInterval)));
+ static assert(__traits(compiles, negInfInterval.span(iInterval)));
+ static assert(!__traits(compiles, negInfInterval.span(posInfInterval)));
+ static assert(!__traits(compiles, negInfInterval.span(cPosInfInterval)));
+ static assert(!__traits(compiles, negInfInterval.span(iPosInfInterval)));
+ static assert(__traits(compiles, negInfInterval.span(negInfInterval)));
+ static assert(__traits(compiles, negInfInterval.span(cNegInfInterval)));
+ static assert(__traits(compiles, negInfInterval.span(iNegInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.span(interval)));
+ static assert(__traits(compiles, cNegInfInterval.span(cInterval)));
+ static assert(__traits(compiles, cNegInfInterval.span(iInterval)));
+ static assert(!__traits(compiles, cNegInfInterval.span(posInfInterval)));
+ static assert(!__traits(compiles, cNegInfInterval.span(cPosInfInterval)));
+ static assert(!__traits(compiles, cNegInfInterval.span(iPosInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.span(negInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.span(cNegInfInterval)));
+ static assert(__traits(compiles, cNegInfInterval.span(iNegInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.span(interval)));
+ static assert(__traits(compiles, iNegInfInterval.span(cInterval)));
+ static assert(__traits(compiles, iNegInfInterval.span(iInterval)));
+ static assert(!__traits(compiles, iNegInfInterval.span(posInfInterval)));
+ static assert(!__traits(compiles, iNegInfInterval.span(cPosInfInterval)));
+ static assert(!__traits(compiles, iNegInfInterval.span(iPosInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.span(negInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.span(cNegInfInterval)));
+ static assert(__traits(compiles, iNegInfInterval.span(iNegInfInterval)));
+
+ //Verify Examples.
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).span(Interval!Date(Date(1990, 7, 6), Date(2000, 8, 2))) == NegInfInterval!Date(Date(2012, 3 , 1)));
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).span(Interval!Date(Date(1999, 1, 12), Date(2015, 9, 2))) == NegInfInterval!Date(Date(2015, 9 , 2)));
+ assert(NegInfInterval!Date(Date(1600, 1, 7)).span(Interval!Date(Date(2012, 3, 11), Date(2017, 7, 1))) == NegInfInterval!Date(Date(2017, 7 , 1)));
+
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).span(NegInfInterval!Date(Date(1999, 7, 6))) == NegInfInterval!Date(Date(2012, 3 , 1)));
+ assert(NegInfInterval!Date(Date(2012, 3, 1)).span(NegInfInterval!Date(Date(2013, 1, 12))) == NegInfInterval!Date(Date(2013, 1 , 12)));
+}
+
+//Test NegInfInterval's shift().
+unittest
+{
+ auto interval = NegInfInterval!Date(Date(2012, 1, 7));
+
+ static void testInterval(I)(I interval, in Duration duration, in I expected, size_t line = __LINE__)
+ {
+ interval.shift(duration);
+ assertPred!"=="(interval, expected, "", __FILE__, line);
+ }
+
+ testInterval(interval, dur!"days"(22), NegInfInterval!Date(Date(2012, 1, 29)));
+ testInterval(interval, dur!"days"(-22), NegInfInterval!Date(Date(2011, 12, 16)));
+
+ const cInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(!__traits(compiles, cInterval.shift(dur!"days"(5))));
+ static assert(!__traits(compiles, iInterval.shift(dur!"days"(5))));
+
+ //Verify Examples.
+ auto interval1 = NegInfInterval!Date(Date(2012, 4, 5));
+ auto interval2 = NegInfInterval!Date(Date(2012, 4, 5));
+
+ interval1.shift(dur!"days"(50));
+ assert(interval1 == NegInfInterval!Date(Date(2012, 5, 25)));
+
+ interval2.shift(dur!"days"(-50));
+ assert(interval2 == NegInfInterval!Date( Date(2012, 2, 15)));
+}
+
+//Test NegInfInterval's shift(int, int, AllowDayOverflow).
+unittest
+{
+ {
+ auto interval = NegInfInterval!Date(Date(2012, 1, 7));
+
+ static void testIntervalFail(I)(I interval, int years, int months)
+ {
+ interval.shift(years, months);
+ }
+
+ static void testInterval(I)(I interval, int years, int months, AllowDayOverflow allow, in I expected, size_t line = __LINE__)
+ {
+ interval.shift(years, months, allow);
+ assertPred!"=="(interval, expected, "", __FILE__, line);
+ }
+
+ testInterval(interval, 5, 0, AllowDayOverflow.yes, NegInfInterval!Date(Date(2017, 1, 7)));
+ testInterval(interval, -5, 0, AllowDayOverflow.yes, NegInfInterval!Date(Date(2007, 1, 7)));
+
+ auto interval2 = NegInfInterval!Date(Date(2010, 5, 31));
+
+ testInterval(interval2, 1, 1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2011, 7, 1)));
+ testInterval(interval2, 1, -1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2011, 5, 1)));
+ testInterval(interval2, -1, -1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2009, 5, 1)));
+ testInterval(interval2, -1, 1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2009, 7, 1)));
+
+ testInterval(interval2, 1, 1, AllowDayOverflow.no, NegInfInterval!Date(Date(2011, 6, 30)));
+ testInterval(interval2, 1, -1, AllowDayOverflow.no, NegInfInterval!Date(Date(2011, 4, 30)));
+ testInterval(interval2, -1, -1, AllowDayOverflow.no, NegInfInterval!Date(Date(2009, 4, 30)));
+ testInterval(interval2, -1, 1, AllowDayOverflow.no, NegInfInterval!Date(Date(2009, 6, 30)));
+ }
+
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(!__traits(compiles, cNegInfInterval.shift(1)));
+ static assert(!__traits(compiles, iNegInfInterval.shift(1)));
+
+ //Verify Examples.
+ auto interval1 = NegInfInterval!Date(Date(2012, 3, 1));
+ auto interval2 = NegInfInterval!Date(Date(2012, 3, 1));
+
+ interval1.shift(2);
+ assert(interval1 == NegInfInterval!Date(Date(2014, 3, 1)));
+
+ interval2.shift(-2);
+ assert(interval2 == NegInfInterval!Date(Date(2010, 3, 1)));
+}
+
+//Test NegInfInterval's expand().
+unittest
+{
+ auto interval = NegInfInterval!Date(Date(2012, 1, 7));
+
+ static void testInterval(I)(I interval, in Duration duration, in I expected, size_t line = __LINE__)
+ {
+ interval.expand(duration);
+ assertPred!"=="(interval, expected, "", __FILE__, line);
+ }
+
+ testInterval(interval, dur!"days"(22), NegInfInterval!Date(Date(2012, 1, 29)));
+ testInterval(interval, dur!"days"(-22), NegInfInterval!Date(Date(2011, 12, 16)));
+
+ const cInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(!__traits(compiles, cInterval.expand(dur!"days"(5))));
+ static assert(!__traits(compiles, iInterval.expand(dur!"days"(5))));
+
+ //Verify Examples.
+ auto interval1 = NegInfInterval!Date(Date(2012, 3, 1));
+ auto interval2 = NegInfInterval!Date(Date(2012, 3, 1));
+
+ interval1.expand(dur!"days"(2));
+ assert(interval1 == NegInfInterval!Date(Date(2012, 3, 3)));
+
+ interval2.expand(dur!"days"(-2));
+ assert(interval2 == NegInfInterval!Date(Date(2012, 2, 28)));
+}
+
+//Test NegInfInterval's expand(int, int, AllowDayOverflow).
+unittest
+{
+ {
+ auto interval = NegInfInterval!Date(Date(2012, 1, 7));
+
+ static void testInterval(I)(I interval, int years, int months, AllowDayOverflow allow, in I expected, size_t line = __LINE__)
+ {
+ interval.expand(years, months, allow);
+ assertPred!"=="(interval, expected, "", __FILE__, line);
+ }
+
+ testInterval(interval, 5, 0, AllowDayOverflow.yes, NegInfInterval!Date(Date(2017, 1, 7)));
+ testInterval(interval, -5, 0, AllowDayOverflow.yes, NegInfInterval!Date(Date(2007, 1, 7)));
+
+ auto interval2 = NegInfInterval!Date(Date(2010, 5, 31));
+
+ testInterval(interval2, 1, 1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2011, 7, 1)));
+ testInterval(interval2, 1, -1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2011, 5, 1)));
+ testInterval(interval2, -1, -1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2009, 5, 1)));
+ testInterval(interval2, -1, 1, AllowDayOverflow.yes, NegInfInterval!Date(Date(2009, 7, 1)));
+
+ testInterval(interval2, 1, 1, AllowDayOverflow.no, NegInfInterval!Date(Date(2011, 6, 30)));
+ testInterval(interval2, 1, -1, AllowDayOverflow.no, NegInfInterval!Date(Date(2011, 4, 30)));
+ testInterval(interval2, -1, -1, AllowDayOverflow.no, NegInfInterval!Date(Date(2009, 4, 30)));
+ testInterval(interval2, -1, 1, AllowDayOverflow.no, NegInfInterval!Date( Date(2009, 6, 30)));
+ }
+
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(!__traits(compiles, cNegInfInterval.expand(1)));
+ static assert(!__traits(compiles, iNegInfInterval.expand(1)));
+
+ //Verify Examples.
+ auto interval1 = NegInfInterval!Date(Date(2012, 3, 1));
+ auto interval2 = NegInfInterval!Date(Date(2012, 3, 1));
+
+ interval1.expand(2);
+ assert(interval1 == NegInfInterval!Date(Date(2014, 3, 1)));
+
+ interval2.expand(-2);
+ assert(interval2 == NegInfInterval!Date(Date(2010, 3, 1)));
+}
+
+//Test NegInfInterval's bwdRange().
+unittest
+{
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+
+ static void testInterval(NegInfInterval!Date negInfInterval)
+ {
+ negInfInterval.bwdRange(everyDayOfWeek!(Date, Direction.fwd)(DayOfWeek.fri)).popFront();
+ }
+
+ assertThrown!DateTimeException(testInterval(negInfInterval));
+
+ assertPred!"=="(NegInfInterval!Date(Date(2010, 10, 1)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).front,
+ Date(2010, 10, 1));
+
+ assertPred!"=="(NegInfInterval!Date(Date(2010, 10, 1)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri), PopFirst.yes).front,
+ Date(2010, 9, 24));
+
+ //Verify Examples.
+ auto interval = NegInfInterval!Date(Date(2010, 9, 9));
+ auto func = (in Date date)
+ {
+ if((date.day & 1) == 0)
+ return date - dur!"days"(2);
+
+ return date - dur!"days"(1);
+ };
+ auto range = interval.bwdRange(func);
+
+ assert(range.front == Date(2010, 9, 9)); //An odd day. Using PopFirst.yes would have made this Date(2010, 9, 8).
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 8));
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 6));
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 4));
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 2));
+
+ range.popFront();
+ assert(!range.empty);
+
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, cNegInfInterval.bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri))));
+ static assert(__traits(compiles, iNegInfInterval.bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri))));
+}
+
+//Test NegInfInterval's toString().
+unittest
+{
+ assertPred!"=="(NegInfInterval!Date(Date(2012, 1, 7)).toString(), "[-∞ - 2012-Jan-07)");
+
+ const cNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ immutable iNegInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+ static assert(__traits(compiles, cNegInfInterval.toString()));
+ static assert(__traits(compiles, iNegInfInterval.toString()));
+}
+
+
+/++
+ Generates a range-generating function for intervals.
+
+ Returns a delegate which returns the next time point with the given
+ DayOfWeek in a range.
+
+ Using this delegate allows you to iterate over successive time points
+ which are all the same day of the week. e.g. passing DayOfWeek.mon
+ to $(D everyDayOfWeek()) would result in a delegate which could be used
+ to iterate over all of the Mondays in a range.
+
+ Params:
+ dir = The direction to iterate in. If passing the return value
+ to $(D fwdRange()), use $(D Direction.fwd). If passing
+ it to $(D bwdRange()), use $(D Direction.bwd).
+ dayOfWeek = The week that each time point in the range will be.
+
+ Examples:
+--------------------
+auto interval = Interval!Date(Date(2010, 9, 2), Date(2010, 9, 27));
+auto func = everyDayOfWeek!Date(DayOfWeek.mon);
+auto range = interval.fwdRange(func);
+
+assert(range.front == Date(2010, 9, 2)); //A Thursday. Using PopFirst.yes would have made this Date(2010, 9, 6).
+
+range.popFront();
+assert(range.front == Date(2010, 9, 6));
+
+range.popFront();
+assert(range.front == Date(2010, 9, 13));
+
+range.popFront();
+assert(range.front == Date(2010, 9, 20));
+
+range.popFront();
+assert(range.empty);
+--------------------
+ +/
+static TP delegate(in TP) everyDayOfWeek(TP, Direction dir = Direction.fwd)(DayOfWeek dayOfWeek) nothrow
+ if(isTimePoint!TP &&
+ (dir == Direction.fwd || dir == Direction.bwd) &&
+ __traits(hasMember, TP, "dayOfWeek") &&
+ !__traits(isStaticFunction, TP.dayOfWeek) &&
+ is(ReturnType!(TP.dayOfWeek) == DayOfWeek) &&
+ (functionAttributes!(TP.dayOfWeek) & FunctionAttribute.PROPERTY) &&
+ (functionAttributes!(TP.dayOfWeek) & FunctionAttribute.NOTHROW))
+{
+ TP func(in TP tp)
+ {
+ TP retval = cast(TP)tp;
+ immutable days = daysToDayOfWeek(retval.dayOfWeek, dayOfWeek);
+
+ static if(dir == Direction.fwd)
+ immutable adjustedDays = days == 0 ? 7 : days;
+ else
+ immutable adjustedDays = days == 0 ? -7 : days - 7;
+
+ return retval += dur!"days"(adjustedDays);
+ }
+
+ return &func;
+}
+
+unittest
+{
+ auto funcFwd = everyDayOfWeek!Date(DayOfWeek.mon);
+ auto funcBwd = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.mon);
+
+ assertPred!"=="(funcFwd(Date(2010, 8, 28)), Date(2010, 8, 30));
+ assertPred!"=="(funcFwd(Date(2010, 8, 29)), Date(2010, 8, 30));
+ assertPred!"=="(funcFwd(Date(2010, 8, 30)), Date(2010, 9, 6));
+ assertPred!"=="(funcFwd(Date(2010, 8, 31)), Date(2010, 9, 6));
+ assertPred!"=="(funcFwd(Date(2010, 9, 1)), Date(2010, 9, 6));
+ assertPred!"=="(funcFwd(Date(2010, 9, 2)), Date(2010, 9, 6));
+ assertPred!"=="(funcFwd(Date(2010, 9, 3)), Date(2010, 9, 6));
+ assertPred!"=="(funcFwd(Date(2010, 9, 4)), Date(2010, 9, 6));
+ assertPred!"=="(funcFwd(Date(2010, 9, 5)), Date(2010, 9, 6));
+ assertPred!"=="(funcFwd(Date(2010, 9, 6)), Date(2010, 9, 13));
+ assertPred!"=="(funcFwd(Date(2010, 9, 7)), Date(2010, 9, 13));
+
+ assertPred!"=="(funcBwd(Date(2010, 8, 28)), Date(2010, 8, 23));
+ assertPred!"=="(funcBwd(Date(2010, 8, 29)), Date(2010, 8, 23));
+ assertPred!"=="(funcBwd(Date(2010, 8, 30)), Date(2010, 8, 23));
+ assertPred!"=="(funcBwd(Date(2010, 8, 31)), Date(2010, 8, 30));
+ assertPred!"=="(funcBwd(Date(2010, 9, 1)), Date(2010, 8, 30));
+ assertPred!"=="(funcBwd(Date(2010, 9, 2)), Date(2010, 8, 30));
+ assertPred!"=="(funcBwd(Date(2010, 9, 3)), Date(2010, 8, 30));
+ assertPred!"=="(funcBwd(Date(2010, 9, 4)), Date(2010, 8, 30));
+ assertPred!"=="(funcBwd(Date(2010, 9, 5)), Date(2010, 8, 30));
+ assertPred!"=="(funcBwd(Date(2010, 9, 6)), Date(2010, 8, 30));
+ assertPred!"=="(funcBwd(Date(2010, 9, 7)), Date(2010, 9, 6));
+
+ static assert(!__traits(compiles, everyDayOfWeek!(TimeOfDay)(DayOfWeek.mon)));
+ static assert(__traits(compiles, everyDayOfWeek!(DateTime)(DayOfWeek.mon)));
+ static assert(__traits(compiles, everyDayOfWeek!(SysTime)(DayOfWeek.mon)));
+
+ //Verify Examples.
+ auto interval = Interval!Date(Date(2010, 9, 2), Date(2010, 9, 27));
+ auto func = everyDayOfWeek!Date(DayOfWeek.mon);
+ auto range = interval.fwdRange(func);
+
+ assert(range.front == Date(2010, 9, 2)); //A Thursday. Using PopFirst.yes would have made this Date(2010, 9, 6).
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 6));
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 13));
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 20));
+
+ range.popFront();
+ assert(range.empty);
+}
+
+
+/++
+ Generates a range-generating function for intervals.
+
+ Returns a delegate which returns the next time point with the given
+ month which would be reached by adding months to the given time
+ point.
+
+ So, using this delegate allows you to iterate over successive time
+ points which are in the same month but different years. For example,
+ you could iterate over each successive December 25th in an interval
+ by starting with a date which had the 25th as its day and passed
+ $(D Month.dec) to $(D everyMonth()) to create the delegate.
+
+ Since it wouldn't really make sense to be iterating over a specific
+ month and end up with some of the time points in the succeeding month
+ or two years after the previous time point, $(D AllowDayOverflow.no)
+ is always used when calculating the next time point.
+
+ Params:
+ dir = The direction to iterate in. If passing the return value
+ to $(D fwdRange()), use $(D Direction.fwd). If passing
+ it to $(D bwdRange()), use $(D Direction.bwd).
+ month = The month that each time point in the range will be in.
+
+ Examples:
+--------------------
+auto interval = Interval!Date(Date(2000, 1, 30), Date(2004, 8, 5));
+auto func = everyMonth!(Date)(Month.feb);
+auto range = interval.fwdRange(func);
+
+assert(range.front == Date(2000, 1, 30)); //Using PopFirst.yes would have made this Date(2010, 2, 29).
+
+range.popFront();
+assert(range.front == Date(2000, 2, 29));
+
+range.popFront();
+assert(range.front == Date(2001, 2, 28));
+
+range.popFront();
+assert(range.front == Date(2002, 2, 28));
+
+range.popFront();
+assert(range.front == Date(2003, 2, 28));
+
+range.popFront();
+assert(range.front == Date(2004, 2, 28));
+
+range.popFront();
+assert(range.empty);
+--------------------
+ +/
+static TP delegate(in TP) everyMonth(TP, Direction dir = Direction.fwd)(int month)
+ if(isTimePoint!TP &&
+ (dir == Direction.fwd || dir == Direction.bwd) &&
+ __traits(hasMember, TP, "month") &&
+ !__traits(isStaticFunction, TP.month) &&
+ is(ReturnType!(TP.month) == Month) &&
+ (functionAttributes!(TP.month) & FunctionAttribute.PROPERTY) &&
+ (functionAttributes!(TP.month) & FunctionAttribute.NOTHROW))
+{
+ enforceValid!"months"(month);
+
+ TP func(in TP tp)
+ {
+ TP retval = cast(TP)tp;
+ immutable months = monthsToMonth(retval.month, month);
+
+ static if(dir == Direction.fwd)
+ immutable adjustedMonths = months == 0 ? 12 : months;
+ else
+ immutable adjustedMonths = months == 0 ? -12 : months - 12;
+
+ retval.add!"months"(adjustedMonths, AllowDayOverflow.no);
+
+ if(retval.month != month)
+ {
+ retval.add!"months"(-1);
+ assert(retval.month == month);
+ }
+
+ return retval;
+ }
+
+ return &func;
+}
+
+unittest
+{
+ auto funcFwd = everyMonth!Date(Month.jun);
+ auto funcBwd = everyMonth!(Date, Direction.bwd)(Month.jun);
+
+ assertPred!"=="(funcFwd(Date(2010, 5, 31)), Date(2010, 6, 30));
+ assertPred!"=="(funcFwd(Date(2010, 6, 30)), Date(2011, 6, 30));
+ assertPred!"=="(funcFwd(Date(2010, 7, 31)), Date(2011, 6, 30));
+ assertPred!"=="(funcFwd(Date(2010, 8, 31)), Date(2011, 6, 30));
+ assertPred!"=="(funcFwd(Date(2010, 9, 30)), Date(2011, 6, 30));
+ assertPred!"=="(funcFwd(Date(2010, 10, 31)), Date(2011, 6, 30));
+ assertPred!"=="(funcFwd(Date(2010, 11, 30)), Date(2011, 6, 30));
+ assertPred!"=="(funcFwd(Date(2010, 12, 31)), Date(2011, 6, 30));
+ assertPred!"=="(funcFwd(Date(2011, 1, 31)), Date(2011, 6, 30));
+ assertPred!"=="(funcFwd(Date(2011, 2, 28)), Date(2011, 6, 28));
+ assertPred!"=="(funcFwd(Date(2011, 3, 31)), Date(2011, 6, 30));
+ assertPred!"=="(funcFwd(Date(2011, 4, 30)), Date(2011, 6, 30));
+ assertPred!"=="(funcFwd(Date(2011, 5, 31)), Date(2011, 6, 30));
+ assertPred!"=="(funcFwd(Date(2011, 6, 30)), Date(2012, 6, 30));
+ assertPred!"=="(funcFwd(Date(2011, 7, 31)), Date(2012, 6, 30));
+
+ assertPred!"=="(funcBwd(Date(2010, 5, 31)), Date(2009, 6, 30));
+ assertPred!"=="(funcBwd(Date(2010, 6, 30)), Date(2009, 6, 30));
+ assertPred!"=="(funcBwd(Date(2010, 7, 31)), Date(2010, 6, 30));
+ assertPred!"=="(funcBwd(Date(2010, 8, 31)), Date(2010, 6, 30));
+ assertPred!"=="(funcBwd(Date(2010, 9, 30)), Date(2010, 6, 30));
+ assertPred!"=="(funcBwd(Date(2010, 10, 31)), Date(2010, 6, 30));
+ assertPred!"=="(funcBwd(Date(2010, 11, 30)), Date(2010, 6, 30));
+ assertPred!"=="(funcBwd(Date(2010, 12, 31)), Date(2010, 6, 30));
+ assertPred!"=="(funcBwd(Date(2011, 1, 31)), Date(2010, 6, 30));
+ assertPred!"=="(funcBwd(Date(2011, 2, 28)), Date(2010, 6, 28));
+ assertPred!"=="(funcBwd(Date(2011, 3, 31)), Date(2010, 6, 30));
+ assertPred!"=="(funcBwd(Date(2011, 4, 30)), Date(2010, 6, 30));
+ assertPred!"=="(funcBwd(Date(2011, 5, 31)), Date(2010, 6, 30));
+ assertPred!"=="(funcBwd(Date(2011, 6, 30)), Date(2010, 6, 30));
+ assertPred!"=="(funcBwd(Date(2011, 7, 30)), Date(2011, 6, 30));
+
+ static assert(!__traits(compiles, everyMonth!(TimeOfDay)(Month.jan)));
+ static assert(__traits(compiles, everyMonth!(DateTime)(Month.jan)));
+ static assert(__traits(compiles, everyMonth!(SysTime)(Month.jan)));
+
+ //Verify Examples.
+ auto interval = Interval!Date(Date(2000, 1, 30), Date(2004, 8, 5));
+ auto func = everyMonth!(Date)(Month.feb);
+ auto range = interval.fwdRange(func);
+
+ assert(range.front == Date(2000, 1, 30)); //Using PopFirst.yes would have made this Date(2010, 2, 29).
+
+ range.popFront();
+ assert(range.front == Date(2000, 2, 29));
+
+ range.popFront();
+ assert(range.front == Date(2001, 2, 28));
+
+ range.popFront();
+ assert(range.front == Date(2002, 2, 28));
+
+ range.popFront();
+ assert(range.front == Date(2003, 2, 28));
+
+ range.popFront();
+ assert(range.front == Date(2004, 2, 28));
+
+ range.popFront();
+ assert(range.empty);
+}
+
+
+/++
+ Generates a range-generating function for intervals.
+
+ Returns a delegate which returns the next time point which is the given
+ duration later.
+
+ Using this delegate allows you to iterate over successive time points
+ which are apart by the given duration e.g. passing $(D dur!"days"(3)) to
+ $(D everyDuration()) would result in a delegate which could be
+ used to iterate over a range of days which are each 3 days apart.
+
+ Params:
+ dir = The direction to iterate in. If passing the return value
+ to $(D fwdRange()), use $(D Direction.fwd). If passing it
+ to $(D bwdRange()), use $(D Direction.bwd).
+ duration = The duration which separates each successive time point
+ in the range.
+
+ Examples:
+--------------------
+auto interval = Interval!Date(Date(2010, 9, 2), Date(2010, 9, 27));
+auto func = everyDuration!Date(dur!"days"(8));
+auto range = interval.fwdRange(func);
+
+assert(range.front == Date(2010, 9, 2)); //Using PopFirst.yes would have made this Date(2010, 9, 10).
+
+range.popFront();
+assert(range.front == Date(2010, 9, 10));
+
+range.popFront();
+assert(range.front == Date(2010, 9, 18));
+
+range.popFront();
+assert(range.front == Date(2010, 9, 26));
+
+range.popFront();
+assert(range.empty);
+--------------------
+ +/
+static TP delegate(in TP) everyDuration(TP, Direction dir = Direction.fwd, D)
+ (D duration) nothrow
+ if(isTimePoint!TP &&
+ __traits(compiles, TP.init + duration) &&
+ (dir == Direction.fwd || dir == Direction.bwd))
+{
+ TP func(in TP tp)
+ {
+ static if(dir == Direction.fwd)
+ return tp + duration;
+ else
+ return tp - duration;
+ }
+
+ return &func;
+}
+
+unittest
+{
+ auto funcFwd = everyDuration!Date(dur!"days"(27));
+ auto funcBwd = everyDuration!(Date, Direction.bwd)(dur!"days"(27));
+
+ assertPred!"=="(funcFwd(Date(2009, 12, 25)), Date(2010, 1, 21));
+ assertPred!"=="(funcFwd(Date(2009, 12, 26)), Date(2010, 1, 22));
+ assertPred!"=="(funcFwd(Date(2009, 12, 27)), Date(2010, 1, 23));
+ assertPred!"=="(funcFwd(Date(2009, 12, 28)), Date(2010, 1, 24));
+
+ assertPred!"=="(funcBwd(Date(2010, 1, 21)), Date(2009, 12, 25));
+ assertPred!"=="(funcBwd(Date(2010, 1, 22)), Date(2009, 12, 26));
+ assertPred!"=="(funcBwd(Date(2010, 1, 23)), Date(2009, 12, 27));
+ assertPred!"=="(funcBwd(Date(2010, 1, 24)), Date(2009, 12, 28));
+
+ static assert(__traits(compiles, everyDuration!Date(dur!"hnsecs"(1))));
+ static assert(__traits(compiles, everyDuration!TimeOfDay(dur!"hnsecs"(1))));
+ static assert(__traits(compiles, everyDuration!DateTime(dur!"hnsecs"(1))));
+ static assert(__traits(compiles, everyDuration!SysTime(dur!"hnsecs"(1))));
+
+ //Verify Examples.
+ auto interval = Interval!Date(Date(2010, 9, 2), Date(2010, 9, 27));
+ auto func = everyDuration!Date(dur!"days"(8));
+ auto range = interval.fwdRange(func);
+
+ assert(range.front == Date(2010, 9, 2)); //Using PopFirst.yes would have made this Date(2010, 9, 10).
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 10));
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 18));
+
+ range.popFront();
+ assert(range.front == Date(2010, 9, 26));
+
+ range.popFront();
+ assert(range.empty);
+}
+
+
+/++
+ Generates a range-generating function for intervals.
+
+ Returns a delegate which returns the next time point which is the given
+ number of years, month, and duration later.
+
+ The difference between this version of $(D everyDuration()) and the
+ version which just takes a $(D Duration) is that this one also takes the
+ number of years and months (along with an AllowDayOverflow to indicate
+ whether adding years and months should allow the days to overflow).
+
+ Note that if iterating forward, $(D add!"years"()) is called on the given
+ time point, then $(D add!"months"()), and finally the duration is added
+ to it. However, if iterating backwards, the duration is added first, then
+ $(D add!"months"()) is called, and finally $(D add!"years"()) is called.
+ That way, going backwards generates close to the same time points that
+ iterating forward does, but since adding years and months is not entirely
+ reversible (due to possible day overflow, regardless of whether
+ AllowDayOverflow.yes or AllowDayOverflow.no is used), it can't be
+ guaranteed that iterating backwards will give you the same time points as
+ iterating forward would have (even assuming that the end of the range is a
+ time point which would be returned by the delegate when iterating forward
+ from begin).
+
+ Params:
+ dir = The direction to iterate in. If passing the return
+ value to $(D fwdRange()), use $(D Direction.fwd).
+ If passing it to $(D bwdRange()), use $(D Direction.bwd).
+ years = The number of years to add to the time point passed
+ to the delegate.
+ months = The number of months to add to the time point passed to
+ the delegate.
+ allowOverflow = Whether the days should be allowed to overflow on begin
+ and end, causing their month to increment.
+ duration = The duration to add to the time point passed to the
+ delegate.
+
+ Examples:
+--------------------
+auto interval = Interval!Date(Date(2010, 9, 2), Date(2025, 9, 27));
+auto func = everyDuration!Date(4, 1, AllowDayOverflow.yes, dur!"days"(2));
+auto range = interval.fwdRange(func);
+
+assert(range.front == Date(2010, 9, 2)); //Using PopFirst.yes would have made this Date(2014, 10, 12).
+
+range.popFront();
+assert(range.front == Date(2014, 10, 4));
+
+range.popFront();
+assert(range.front == Date(2018, 11, 6));
+
+range.popFront();
+assert(range.front == Date(2022, 12, 8));
+
+range.popFront();
+assert(range.empty);
+--------------------
+ +/
+static TP delegate(in TP) everyDuration(TP, Direction dir = Direction.fwd, D)
+ (int years,
+ int months = 0,
+ AllowDayOverflow allowOverflow = AllowDayOverflow.yes,
+ D duration = dur!"days"(0)) nothrow
+ if(isTimePoint!TP &&
+ __traits(compiles, TP.init + duration) &&
+ __traits(compiles, TP.init.add!"years"(years)) &&
+ __traits(compiles, TP.init.add!"months"(months)) &&
+ (dir == Direction.fwd || dir == Direction.bwd))
+{
+ TP func(in TP tp)
+ {
+ static if(dir == Direction.fwd)
+ {
+ TP retval = cast(TP)tp;
+
+ retval.add!"years"(years, allowOverflow);
+ retval.add!"months"(months, allowOverflow);
+
+ return retval + duration;
+ }
+ else
+ {
+ TP retval = tp - duration;
+
+ retval.add!"months"(-months, allowOverflow);
+ retval.add!"years"(-years, allowOverflow);
+
+ return retval;
+ }
+ }
+
+ return &func;
+}
+
+unittest
+{
+ {
+ auto funcFwd = everyDuration!Date(1, 2, AllowDayOverflow.yes, dur!"days"(3));
+ auto funcBwd = everyDuration!(Date, Direction.bwd)(1, 2, AllowDayOverflow.yes, dur!"days"(3));
+
+ assertPred!"=="(funcFwd(Date(2009, 12, 25)), Date(2011, 2, 28));
+ assertPred!"=="(funcFwd(Date(2009, 12, 26)), Date(2011, 3, 1));
+ assertPred!"=="(funcFwd(Date(2009, 12, 27)), Date(2011, 3, 2));
+ assertPred!"=="(funcFwd(Date(2009, 12, 28)), Date(2011, 3, 3));
+ assertPred!"=="(funcFwd(Date(2009, 12, 29)), Date(2011, 3, 4));
+
+ assertPred!"=="(funcBwd(Date(2011, 2, 28)), Date(2009, 12, 25));
+ assertPred!"=="(funcBwd(Date(2011, 3, 1)), Date(2009, 12, 26));
+ assertPred!"=="(funcBwd(Date(2011, 3, 2)), Date(2009, 12, 27));
+ assertPred!"=="(funcBwd(Date(2011, 3, 3)), Date(2009, 12, 28));
+ assertPred!"=="(funcBwd(Date(2011, 3, 4)), Date(2010, 1, 1));
+ }
+
+ {
+ auto funcFwd = everyDuration!Date(1, 2, AllowDayOverflow.no, dur!"days"(3));
+ auto funcBwd = everyDuration!(Date, Direction.bwd)(1, 2, AllowDayOverflow.yes, dur!"days"(3));
+
+ assertPred!"=="(funcFwd(Date(2009, 12, 25)), Date(2011, 2, 28));
+ assertPred!"=="(funcFwd(Date(2009, 12, 26)), Date(2011, 3, 1));
+ assertPred!"=="(funcFwd(Date(2009, 12, 27)), Date(2011, 3, 2));
+ assertPred!"=="(funcFwd(Date(2009, 12, 28)), Date(2011, 3, 3));
+ assertPred!"=="(funcFwd(Date(2009, 12, 29)), Date(2011, 3, 3));
+
+ assertPred!"=="(funcBwd(Date(2011, 2, 28)), Date(2009, 12, 25));
+ assertPred!"=="(funcBwd(Date(2011, 3, 1)), Date(2009, 12, 26));
+ assertPred!"=="(funcBwd(Date(2011, 3, 2)), Date(2009, 12, 27));
+ assertPred!"=="(funcBwd(Date(2011, 3, 3)), Date(2009, 12, 28));
+ assertPred!"=="(funcBwd(Date(2011, 3, 4)), Date(2010, 1, 1));
+ }
+
+ static assert(__traits(compiles, everyDuration!Date(1, 2, AllowDayOverflow.yes, dur!"hnsecs"(1))));
+ static assert(!__traits(compiles, everyDuration!TimeOfDay(1, 2, AllowDayOverflow.yes, dur!"hnsecs"(1))));
+ static assert(__traits(compiles, everyDuration!DateTime(1, 2, AllowDayOverflow.yes, dur!"hnsecs"(1))));
+ static assert(__traits(compiles, everyDuration!SysTime(1, 2, AllowDayOverflow.yes, dur!"hnsecs"(1))));
+
+ //Verify Examples.
+ auto interval = Interval!Date(Date(2010, 9, 2), Date(2025, 9, 27));
+ auto func = everyDuration!Date(4, 1, AllowDayOverflow.yes, dur!"days"(2));
+ auto range = interval.fwdRange(func);
+
+ assert(range.front == Date(2010, 9, 2)); //Using PopFirst.yes would have made this Date(2014, 10, 12).
+
+ range.popFront();
+ assert(range.front == Date(2014, 10, 4));
+
+ range.popFront();
+ assert(range.front == Date(2018, 11, 6));
+
+ range.popFront();
+ assert(range.front == Date(2022, 12, 8));
+
+ range.popFront();
+ assert(range.empty);
+}
+
+
+//TODO Add function to create a range generating function based on a date recurrence pattern string.
+// This may or may not involve creating a date recurrence pattern class of some sort - probably
+// yes if we want to make it easy to build them. However, there is a standard recurrence
+// pattern string format which we'd want to support with a range generator (though if we have
+// the class/struct, we'd probably want a version of the range generating function which took
+// that rather than a string).
+
+
+//==============================================================================
+// Section with ranges.
+//==============================================================================
+
+
+/++
+ A range over an $(D Interval).
+
+ $(D IntervalRange) is only ever constructed by $(D Interval). However, when
+ it is constructed, it is given a function, $(D func), which is used to generate
+ the time points which are iterated over. $(D func()) takes a time point and
+ returns a time point of the same type. So, for instance, if you had an
+ $(D Interval!Date), and you wanted to iterate over all of the days in that
+ interval, you would pass a function to $(D Interval)'s $(D fwdRange()) where
+ that function took a $(D Date) and returned a $(D Date) which was one day
+ later. That function would then be used by $(D IntervalRange)'s $(D popFront())
+ to iterate over the $(D Date)s in the interval.
+
+ If $(D dir == Direction.fwd), then a range iterates forward in time, while if
+ $(D dir == Direction.bwd), then it iterates backwards in time. So, if
+ $(D dir == Direction.fwd) then $(D front == interval.begin), while if
+ $(D dir == Direction.bwd) then $(D front == interval.end). $(D func) must generate
+ a time point going in the proper direction of iteration, or a
+ $(D DateTimeException) will be thrown. So, if you're iterating forward in time,
+ the time point that func generates must be later in time than the one passed
+ to it. If it's either identical or earlier in time, then a $(D DateTimeException)
+ will be thrown. If you're iterating backwards, then the generated time point
+ must be before the time point which was passed in.
+
+ If the generated time point is ever passed the edge of the range in the proper
+ direction, then the edge of that range will be used instead. So, if iterating
+ forward, and the generated time point is past the interval's end, then front
+ becomes end. If iterating backwards, and the generated time point is before
+ begin, then front becomes begin. In either case, the range would then be empty.
+
+ Also note that while normally the begin of an interval is included in it and
+ its end is excluded from it, if $(D dir == Direction.bwd), then begin is
+ treated as excluded and end is treated as included. This allows for the same
+ behavior in both directions. This works because none of $(D Interval)'s functions
+ which care about whether begin or end is included or excluded are ever called
+ by $(D IntervalRange). $(D interval) returns a normal interval, regardless of
+ whether $(D dir == Direction.fwd) or if $(D dir == Direction.bwd), so any
+ $(D Interval) functions which are called on it which care about whether begin
+ or end are included or excluded will treat begin as included and end as excluded.
+ +/
+struct IntervalRange(TP, Direction dir)
+ if(isTimePoint!TP && dir != Direction.both)
+{
+public:
+
+ /++
+ Params:
+ rhs = The IntervalRange to assign to this one.
+ +/
+ /+ref+/ IntervalRange opAssign(ref IntervalRange rhs) pure nothrow
+ {
+ _interval = rhs._interval;
+ _func = rhs._func;
+
+ return this;
+ }
+
+
+ /++
+ Whether this IntervalRange is empty.
+ +/
+ @property bool empty() const pure nothrow
+ {
+ return _interval.empty;
+ }
+
+
+ /++
+ The first time point in the range.
+
+ Throws:
+ DateTimeException if empty is true.
+ +/
+ @property TP front() const pure
+ {
+ _enforceNotEmpty();
+
+ static if(dir == Direction.fwd)
+ return _interval.begin;
+ else
+ return _interval.end;
+ }
+
+
+ /++
+ Pops front from the range, using $(D func()) to generate the next time
+ point in the range. If the generated time point is beyond the edge of
+ the range, then front is set to that edge, end the range is then empty.
+ So, if iterating forwards, and the generated time point is greater
+ than the interval's end, then front is set to end. If iterating
+ backwards, and the generated time point is less than the interval's
+ begin, then front is set to begin.
+
+ Throws:
+ DateTimeException if empty is true or if the generated time point is
+ in the wrong direction (i.e. if you're iterating forward and the
+ generated time point is before front, or if you're iterating
+ backwards, and the generated time point is after front).
+ +/
+ void popFront()
+ {
+ _enforceNotEmpty();
+
+ static if(dir == Direction.fwd)
+ {
+ auto begin = _func(_interval.begin);
+
+ if(begin > _interval.end)
+ begin = _interval.end;
+
+ _enforceCorrectDirection(begin);
+
+ _interval.begin = begin;
+ }
+ else
+ {
+ auto end = _func(_interval.end);
+
+ if(end < _interval.begin)
+ end = _interval.begin;
+
+ _enforceCorrectDirection(end);
+
+ _interval.end = end;
+ }
+ }
+
+
+ /++
+ Returns a copy of $(D this).
+ +/
+ @property IntervalRange save() pure nothrow
+ {
+ return this;
+ }
+
+
+ /++
+ The interval that this IntervalRange currently covers.
+ +/
+ @property Interval!TP interval() const pure nothrow
+ {
+ return cast(Interval!TP)_interval;
+ }
+
+
+ /++
+ The function used to generate the next time point in the range.
+ +/
+ TP delegate(in TP) func() pure nothrow @property
+ {
+ return _func;
+ }
+
+
+ /++
+ The Direction that this range iterates in.
+ +/
+ @property Direction direction() const pure nothrow
+ {
+ return dir;
+ }
+
+
+private:
+
+ /+
+ Params:
+ interval = The interval that this range covers.
+ func = The function used to generate the time points which are iterated over.
+ +/
+ this(in Interval!TP interval, TP delegate(in TP) func) pure nothrow
+ {
+ _func = func;
+ _interval = interval;
+ }
+
+
+ /++
+ Throws:
+ DateTimeException if empty is true.
+ +/
+ void _enforceNotEmpty(size_t line = __LINE__) const pure
+ {
+ if(empty)
+ throw new DateTimeException("Invalid operation for an empty IntervalRange.", __FILE__, line);
+ }
+
+
+ /++
+ Throws:
+ DateTimeException if newTP is in the wrong direction.
+ +/
+ void _enforceCorrectDirection(in TP newTP, size_t line = __LINE__) const
+ {
+ static if(dir == Direction.fwd)
+ {
+ enforce(newTP > _interval._begin,
+ new DateTimeException(format("Generated time point is before previous begin: prev [%s] new [%s]",
+ interval._begin,
+ newTP),
+ __FILE__,
+ line));
+ }
+ else
+ {
+ enforce(newTP < _interval._end,
+ new DateTimeException(format("Generated time point is after previous end: prev [%s] new [%s]",
+ interval._end,
+ newTP),
+ __FILE__,
+ line));
+ }
+ }
+
+
+ Interval!TP _interval;
+ TP delegate(in TP) _func;
+}
+
+//Test that IntervalRange satisfies the range predicates that it's supposed to satisfy.
+unittest
+{
+ static assert(isInputRange!(IntervalRange!(Date, Direction.fwd)));
+ static assert(isForwardRange!(IntervalRange!(Date, Direction.fwd)));
+
+ //Commented out due to bug http://d.puremagic.com/issues/show_bug.cgi?id=4895
+ //static assert(!isOutputRange!(IntervalRange!(Date, Direction.fwd), Date));
+
+ static assert(!isBidirectionalRange!(IntervalRange!(Date, Direction.fwd)));
+ static assert(!isRandomAccessRange!(IntervalRange!(Date, Direction.fwd)));
+ static assert(!hasSwappableElements!(IntervalRange!(Date, Direction.fwd)));
+ static assert(!hasAssignableElements!(IntervalRange!(Date, Direction.fwd)));
+ static assert(!hasLength!(IntervalRange!(Date, Direction.fwd)));
+ static assert(!isInfinite!(IntervalRange!(Date, Direction.fwd)));
+ static assert(!hasSlicing!(IntervalRange!(Date, Direction.fwd)));
+
+ static assert(is(ElementType!(IntervalRange!(Date, Direction.fwd)) == Date));
+ static assert(is(ElementType!(IntervalRange!(TimeOfDay, Direction.fwd)) == TimeOfDay));
+ static assert(is(ElementType!(IntervalRange!(DateTime, Direction.fwd)) == DateTime));
+ static assert(is(ElementType!(IntervalRange!(SysTime, Direction.fwd)) == SysTime));
+}
+
+//Test construction of IntervalRange.
+unittest
+{
+ {
+ Date dateFunc(in Date date)
+ {
+ return date;
+ }
+
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+
+ auto ir = IntervalRange!(Date, Direction.fwd)(interval, &dateFunc);
+ }
+
+ {
+ TimeOfDay todFunc(in TimeOfDay tod)
+ {
+ return tod;
+ }
+
+ auto interval = Interval!TimeOfDay(TimeOfDay(12, 1, 7), TimeOfDay(14, 0, 0));
+
+ auto ir = IntervalRange!(TimeOfDay, Direction.fwd)(interval, &todFunc);
+ }
+
+ {
+ DateTime dtFunc(in DateTime dt)
+ {
+ return dt;
+ }
+
+ auto interval = Interval!DateTime(DateTime(2010, 7, 4, 12, 1, 7), DateTime(2012, 1, 7, 14, 0, 0));
+
+ auto ir = IntervalRange!(DateTime, Direction.fwd)(interval, &dtFunc);
+ }
+
+ {
+ SysTime stFunc(in SysTime st)
+ {
+ return cast(SysTime)st;
+ }
+
+ auto interval = Interval!SysTime(SysTime(DateTime(2010, 7, 4, 12, 1, 7)), SysTime(DateTime(2012, 1, 7, 14, 0, 0)));
+
+ auto ir = IntervalRange!(SysTime, Direction.fwd)(interval, &stFunc);
+ }
+}
+
+//Test IntervalRange's empty().
+unittest
+{
+ //fwd
+ {
+ auto range = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 21)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri));
+
+ assert(!range.empty);
+ range.popFront();
+ assert(range.empty);
+
+ const cRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri));
+ static assert(__traits(compiles, cRange.empty));
+
+ //Apparently, creating an immutable IntervalRange!Date doesn't work, so we can't test if
+ //empty works with it. However, since an immutable range is pretty useless, it's no great loss.
+ }
+
+ //bwd
+ {
+ auto range = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 21)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri));
+
+ assert(!range.empty);
+ range.popFront();
+ assert(range.empty);
+
+ const cRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri));
+ static assert(__traits(compiles, cRange.empty));
+
+ //Apparently, creating an immutable IntervalRange!Date doesn't work, so we can't test if
+ //empty works with it. However, since an immutable range is pretty useless, it's no great loss.
+ }
+}
+
+//Test IntervalRange's front.
+unittest
+{
+ //fwd
+ {
+ auto emptyRange = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 20)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes);
+ assertThrown!DateTimeException((in IntervalRange!(Date, Direction.fwd) range){range.front;}(emptyRange));
+
+ auto range = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed));
+ assertPred!"=="(range.front, Date(2010, 7, 4));
+
+ auto poppedRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes);
+ assertPred!"=="(poppedRange.front, Date(2010, 7, 7));
+
+ const cRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri));
+ static assert(__traits(compiles, cRange.front));
+ }
+
+ //bwd
+ {
+ auto emptyRange = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 20)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed), PopFirst.yes);
+ assertThrown!DateTimeException((in IntervalRange!(Date, Direction.bwd) range){range.front;}(emptyRange));
+
+ auto range = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed));
+ assertPred!"=="(range.front, Date(2012, 1, 7));
+
+ auto poppedRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed), PopFirst.yes);
+ assertPred!"=="(poppedRange.front, Date(2012, 1, 4));
+
+ const cRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri));
+ static assert(__traits(compiles, cRange.front));
+ }
+}
+
+//Test IntervalRange's popFront().
+unittest
+{
+ //fwd
+ {
+ auto emptyRange = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 20)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes);
+ assertThrown!DateTimeException((IntervalRange!(Date, Direction.fwd) range){range.popFront();}(emptyRange));
+
+ auto range = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes);
+ auto expected = range.front;
+
+ foreach(date; range)
+ {
+ assertPred!"=="(date, expected);
+ expected += dur!"days"(7);
+ }
+
+ assertPred!"=="(walkLength(range), 79);
+
+ const cRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri));
+ static assert(__traits(compiles, cRange.front));
+ }
+
+ //bwd
+ {
+ auto emptyRange = Interval!Date(Date(2010, 9, 19), Date(2010, 9, 20)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed), PopFirst.yes);
+ assertThrown!DateTimeException((IntervalRange!(Date, Direction.bwd) range){range.popFront();}(emptyRange));
+
+ auto range = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed), PopFirst.yes);
+ auto expected = range.front;
+
+ foreach(date; range)
+ {
+ assertPred!"=="(date, expected);
+ expected += dur!"days"(-7);
+ }
+
+ assertPred!"=="(walkLength(range), 79);
+
+ const cRange = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri));
+ static assert(!__traits(compiles, cRange.popFront()));
+ }
+}
+
+//Test IntervalRange's save.
+unittest
+{
+ //fwd
+ {
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto func = everyDayOfWeek!Date(DayOfWeek.fri);
+ auto range = interval.fwdRange(func);
+
+ assert(range.save == range);
+ }
+
+ //bwd
+ {
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri);
+ auto range = interval.bwdRange(func);
+
+ assert(range.save == range);
+ }
+}
+
+//Test IntervalRange's interval.
+unittest
+{
+ //fwd
+ {
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto func = everyDayOfWeek!Date(DayOfWeek.fri);
+ auto range = interval.fwdRange(func);
+
+ assert(range.interval == interval);
+
+ const cRange = range;
+ static assert(__traits(compiles, cRange.interval));
+ }
+
+ //bwd
+ {
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri);
+ auto range = interval.bwdRange(func);
+
+ assert(range.interval == interval);
+
+ const cRange = range;
+ static assert(__traits(compiles, cRange.interval));
+ }
+}
+
+//Test IntervalRange's func.
+unittest
+{
+ //fwd
+ {
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto func = everyDayOfWeek!Date(DayOfWeek.fri);
+ auto range = interval.fwdRange(func);
+
+ assert(range.func == func);
+ }
+
+ //bwd
+ {
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri);
+ auto range = interval.bwdRange(func);
+
+ assert(range.func == func);
+ }
+}
+
+//Test IntervalRange's direction.
+unittest
+{
+ //fwd
+ {
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto func = everyDayOfWeek!Date(DayOfWeek.fri);
+ auto range = interval.fwdRange(func);
+
+ assert(range.direction == Direction.fwd);
+
+ const cRange = range;
+ static assert(__traits(compiles, cRange.direction));
+ }
+
+ //bwd
+ {
+ auto interval = Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7));
+ auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri);
+ auto range = interval.bwdRange(func);
+
+ assert(range.direction == Direction.bwd);
+
+ const cRange = range;
+ static assert(__traits(compiles, cRange.direction));
+ }
+}
+
+
+/++
+ A range over a $(D PosInfInterval). It is an infinite range.
+
+ $(D PosInfIntervalRange) is only ever constructed by $(D PosInfInterval).
+ However, when it is constructed, it is given a function, $(D func()), which
+ is used to generate the time points which are iterated over. $(D func())
+ takes a time point and returns a time point of the same type. So, for instance,
+ if you had a $(D PosInfInterval!Date), and you wanted to iterate over all
+ of the days in that interval, you would pass a function to $(D PosInfInterval)'s
+ $(D fwdRange()) where that function took a $(D Date) and returned a $(D Date)
+ which was one day later. That function would then be used by
+ $(D PosInfIntervalRange)'s $(D popFront()) to iterate over the $(D Date)s in
+ the interval. Though obviously, since the range is infinite, you would use a
+ function such as $(D std.range.take()) with it rather than iterating over
+ *all* of the dates.
+
+ As the interval goes to positive infinity, the range is always iterated over
+ forwards, never backwards. $(D func()) must generate a time point going in
+ the proper direction of iteration, or a $(D DateTimeException) will be thrown.
+ So, the time points that $(D func()) generates must be later in time than
+ the one passed to it. If it's either identical or earlier in time, then a
+ $(D DateTimeException) will be thrown.
+ +/
+struct PosInfIntervalRange(TP)
+ if(isTimePoint!TP)
+{
+public:
+
+ /++
+ Params:
+ rhs = The PosInfIntervalRange to assign to this one.
+ +/
+ /+ref+/ PosInfIntervalRange opAssign(ref PosInfIntervalRange rhs) pure nothrow
+ {
+ _interval = rhs._interval;
+ _func = rhs._func;
+
+ return this;
+ }
+
+
+ /++
+ This is an infinite range, so it is never empty.
+ +/
+ enum bool empty = false;
+
+
+ /++
+ The first time point in the range.
+ +/
+ @property TP front() const pure nothrow
+ {
+ return _interval.begin;
+ }
+
+
+ /++
+ Pops front from the range, using func to generate the next time point
+ in the range.
+
+ Throws:
+ DateTimeException if the generated time point is less than than
+ front.
+ +/
+ void popFront()
+ {
+ auto begin = _func(_interval.begin);
+
+ _enforceCorrectDirection(begin);
+
+ _interval.begin = begin;
+ }
+
+
+ /++
+ Returns a copy of $(D this).
+ +/
+ @property PosInfIntervalRange save() pure nothrow
+ {
+ return this;
+ }
+
+
+ /++
+ The interval that this range currently covers.
+ +/
+ @property PosInfInterval!TP interval() const pure nothrow
+ {
+ return cast(PosInfInterval!TP)_interval;
+ }
+
+
+ /++
+ The function used to generate the next time point in the range.
+ +/
+ TP delegate(in TP) func() pure nothrow @property
+ {
+ return _func;
+ }
+
+
+private:
+
+ /++
+ Params:
+ interval = The interval that this range covers.
+ func = The function used to generate the time points which are
+ iterated over.
+ +/
+ this(in PosInfInterval!TP interval, TP delegate(in TP) func) pure nothrow
+ {
+ _func = func;
+ _interval = interval;
+ }
+
+
+ /++
+ Throws:
+ DateTimeException if newTP is in the wrong direction.
+ +/
+ void _enforceCorrectDirection(in TP newTP, size_t line = __LINE__) const
+ {
+ enforce(newTP > _interval._begin,
+ new DateTimeException(format("Generated time point is before previous begin: prev [%s] new [%s]",
+ interval._begin,
+ newTP),
+ __FILE__,
+ line));
+ }
+
+
+ PosInfInterval!TP _interval;
+ TP delegate(in TP) _func;
+}
+
+//Test that PosInfIntervalRange satisfies the range predicates that it's supposed to satisfy.
+unittest
+{
+ static assert(isInputRange!(PosInfIntervalRange!Date));
+ static assert(isForwardRange!(PosInfIntervalRange!Date));
+ static assert(isInfinite!(PosInfIntervalRange!Date));
+
+ //Commented out due to bug http://d.puremagic.com/issues/show_bug.cgi?id=4895
+ //static assert(!isOutputRange!(PosInfIntervalRange!Date, Date));
+ static assert(!isBidirectionalRange!(PosInfIntervalRange!Date));
+ static assert(!isRandomAccessRange!(PosInfIntervalRange!Date));
+ static assert(!hasSwappableElements!(PosInfIntervalRange!Date));
+ static assert(!hasAssignableElements!(PosInfIntervalRange!Date));
+ static assert(!hasLength!(PosInfIntervalRange!Date));
+ static assert(!hasSlicing!(PosInfIntervalRange!Date));
+
+ static assert(is(ElementType!(PosInfIntervalRange!Date) == Date));
+ static assert(is(ElementType!(PosInfIntervalRange!TimeOfDay) == TimeOfDay));
+ static assert(is(ElementType!(PosInfIntervalRange!DateTime) == DateTime));
+ static assert(is(ElementType!(PosInfIntervalRange!SysTime) == SysTime));
+}
+
+//Test construction of PosInfIntervalRange.
+unittest
+{
+ {
+ Date dateFunc(in Date date)
+ {
+ return date;
+ }
+
+ auto posInfInterval = PosInfInterval!Date(Date(2010, 7, 4));
+
+ auto ir = PosInfIntervalRange!Date(posInfInterval, &dateFunc);
+ }
+
+ {
+ TimeOfDay todFunc(in TimeOfDay tod)
+ {
+ return tod;
+ }
+
+ auto posInfInterval = PosInfInterval!TimeOfDay(TimeOfDay(12, 1, 7));
+
+ auto ir = PosInfIntervalRange!(TimeOfDay)(posInfInterval, &todFunc);
+ }
+
+ {
+ DateTime dtFunc(in DateTime dt)
+ {
+ return dt;
+ }
+
+ auto posInfInterval = PosInfInterval!DateTime(DateTime(2010, 7, 4, 12, 1, 7));
+
+ auto ir = PosInfIntervalRange!(DateTime)(posInfInterval, &dtFunc);
+ }
+
+ {
+ SysTime stFunc(in SysTime st)
+ {
+ return cast(SysTime)st;
+ }
+
+ auto posInfInterval = PosInfInterval!SysTime(SysTime(DateTime(2010, 7, 4, 12, 1, 7)));
+
+ auto ir = PosInfIntervalRange!(SysTime)(posInfInterval, &stFunc);
+ }
+}
+
+//Test PosInfIntervalRange's front.
+unittest
+{
+ auto range = PosInfInterval!Date(Date(2010, 7, 4)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed));
+ assertPred!"=="(range.front, Date(2010, 7, 4));
+
+ auto poppedRange = PosInfInterval!Date(Date(2010, 7, 4)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes);
+ assertPred!"=="(poppedRange.front, Date(2010, 7, 7));
+
+ const cRange = PosInfInterval!Date(Date(2010, 7, 4)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri));
+ static assert(__traits(compiles, cRange.front));
+}
+
+//Test PosInfIntervalRange's popFront().
+unittest
+{
+ auto range = PosInfInterval!Date(Date(2010, 7, 4)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes);
+ auto expected = range.front;
+
+ foreach(date; take(range, 79))
+ {
+ assertPred!"=="(date, expected);
+ expected += dur!"days"(7);
+ }
+
+ const cRange = PosInfInterval!Date(Date(2010, 7, 4)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri));
+ static assert(!__traits(compiles, cRange.popFront()));
+}
+
+//Test PosInfIntervalRange's save.
+unittest
+{
+ auto interval = PosInfInterval!Date(Date(2010, 7, 4));
+ auto func = everyDayOfWeek!Date(DayOfWeek.fri);
+ auto range = interval.fwdRange(func);
+
+ assert(range.save == range);
+}
+
+//Test PosInfIntervalRange's interval.
+unittest
+{
+ auto interval = PosInfInterval!Date(Date(2010, 7, 4));
+ auto func = everyDayOfWeek!Date(DayOfWeek.fri);
+ auto range = interval.fwdRange(func);
+
+ assert(range.interval == interval);
+
+ const cRange = range;
+ static assert(__traits(compiles, cRange.interval));
+}
+
+//Test PosInfIntervalRange's func.
+unittest
+{
+ auto interval = PosInfInterval!Date(Date(2010, 7, 4));
+ auto func = everyDayOfWeek!Date(DayOfWeek.fri);
+ auto range = interval.fwdRange(func);
+
+ assert(range.func == func);
+}
+
+
+/++
+ A range over a $(D NegInfInterval). It is an infinite range.
+
+ $(D NegInfIntervalRange) is only ever constructed by $(D NegInfInterval).
+ However, when it is constructed, it is given a function, $(D func()), which
+ is used to generate the time points which are iterated over. $(D func())
+ takes a time point and returns a time point of the same type. So, for instance,
+ if you had a $(D NegInfInterval!Date), and you wanted to iterate over all
+ of the days in that interval, you would pass a function to $(D NegInfInterval)'s
+ $(D bwdRange()) where that function took a $(D Date) and returned a $(D Date)
+ which was one day earlier. That function would then be used by
+ $(D NegInfIntervalRange)'s $(D popFront()) to iterate over the $(D Date)s in
+ the interval. Though obviously, since the range is infinite, you would use a
+ function such as $(D std.range.take()) with it rather than iterating over
+ *all* of the dates.
+
+ As the interval goes to negative infinity, the range is always iterated over
+ backwards, never forwards. $(D func()) must generate a time point going in
+ the proper direction of iteration, or a $(D DateTimeException) will be thrown.
+ So, the time points that $(D func()) generates must be earlier in time than
+ the one passed to it. If it's either identical or later in time, then a
+ $(D DateTimeException) will be thrown.
+
+ Also note that while normally the end of an interval is excluded from it,
+ $(D NegInfIntervalRange) treats it as if it were included. This allows for
+ the same behavior as you get with $(D PosInfIntervalRange). This works
+ because none of $(D NegInfInterval)'s functions which care about whether
+ end is included or excluded are ever called by $(D NegInfIntervalRange).
+ $(D interval) returns a normal interval, so any $(D NegInfInterval)
+ functions which are called on it which care about whether end is included
+ or excluded will treat end as excluded.
+ +/
+struct NegInfIntervalRange(TP)
+ if(isTimePoint!TP)
+{
+public:
+
+ /++
+ Params:
+ rhs = The NegInfIntervalRange to assign to this one.
+ +/
+ /+ref+/ NegInfIntervalRange opAssign(ref NegInfIntervalRange rhs) pure nothrow
+ {
+ _interval = rhs._interval;
+ _func = rhs._func;
+
+ return this;
+ }
+
+
+ /++
+ This is an infinite range, so it is never empty.
+ +/
+ enum bool empty = false;
+
+
+ /++
+ The first time point in the range.
+ +/
+ @property TP front() const pure nothrow
+ {
+ return _interval.end;
+ }
+
+
+ /++
+ Pops front from the range, using func to generate the next time point
+ in the range.
+
+ Throws:
+ DateTimeException if the generated time point is greater than than
+ front.
+ +/
+ void popFront()
+ {
+ auto end = _func(_interval.end);
+
+ _enforceCorrectDirection(end);
+
+ _interval.end = end;
+ }
+
+
+ /++
+ Returns a copy of $(D this).
+ +/
+ @property NegInfIntervalRange save() pure nothrow
+ {
+ return this;
+ }
+
+
+ /++
+ The interval that this range currently covers.
+ +/
+ @property NegInfInterval!TP interval() const pure nothrow
+ {
+ return cast(NegInfInterval!TP)_interval;
+ }
+
+
+ /++
+ The function used to generate the next time point in the range.
+ +/
+ TP delegate(in TP) func() pure nothrow @property
+ {
+ return _func;
+ }
+
+
+private:
+
+ /+
+ Params:
+ interval = The interval that this range covers.
+ func = The function used to generate the time points which are
+ iterated over.
+ +/
+ this(in NegInfInterval!TP interval, TP delegate(in TP) func) pure nothrow
+ {
+ _func = func;
+ _interval = interval;
+ }
+
+
+ /+
+ Throws:
+ DateTimeException if newTP is in the wrong direction.
+ +/
+ void _enforceCorrectDirection(in TP newTP, size_t line = __LINE__) const
+ {
+ enforce(newTP < _interval._end,
+ new DateTimeException(format("Generated time point is before previous end: prev [%s] new [%s]",
+ interval._end,
+ newTP),
+ __FILE__,
+ line));
+ }
+
+
+ NegInfInterval!TP _interval;
+ TP delegate(in TP) _func;
+}
+
+//Test that NegInfIntervalRange satisfies the range predicates that it's supposed to satisfy.
+unittest
+{
+ static assert(isInputRange!(NegInfIntervalRange!Date));
+ static assert(isForwardRange!(NegInfIntervalRange!Date));
+ static assert(isInfinite!(NegInfIntervalRange!Date));
+
+ //Commented out due to bug http://d.puremagic.com/issues/show_bug.cgi?id=4895
+ //static assert(!isOutputRange!(NegInfIntervalRange!Date, Date));
+ static assert(!isBidirectionalRange!(NegInfIntervalRange!Date));
+ static assert(!isRandomAccessRange!(NegInfIntervalRange!Date));
+ static assert(!hasSwappableElements!(NegInfIntervalRange!Date));
+ static assert(!hasAssignableElements!(NegInfIntervalRange!Date));
+ static assert(!hasLength!(NegInfIntervalRange!Date));
+ static assert(!hasSlicing!(NegInfIntervalRange!Date));
+
+ static assert(is(ElementType!(NegInfIntervalRange!Date) == Date));
+ static assert(is(ElementType!(NegInfIntervalRange!TimeOfDay) == TimeOfDay));
+ static assert(is(ElementType!(NegInfIntervalRange!DateTime) == DateTime));
+}
+
+//Test construction of NegInfIntervalRange.
+unittest
+{
+ {
+ Date dateFunc(in Date date)
+ {
+ return date;
+ }
+
+ auto negInfInterval = NegInfInterval!Date(Date(2012, 1, 7));
+
+ auto ir = NegInfIntervalRange!Date(negInfInterval, &dateFunc);
+ }
+
+ {
+ TimeOfDay todFunc(in TimeOfDay tod)
+ {
+ return tod;
+ }
+
+ auto negInfInterval = NegInfInterval!TimeOfDay(TimeOfDay(14, 0, 0));
+
+ auto ir = NegInfIntervalRange!(TimeOfDay)(negInfInterval, &todFunc);
+ }
+
+ {
+ DateTime dtFunc(in DateTime dt)
+ {
+ return dt;
+ }
+
+ auto negInfInterval = NegInfInterval!DateTime(DateTime(2012, 1, 7, 14, 0, 0));
+
+ auto ir = NegInfIntervalRange!(DateTime)(negInfInterval, &dtFunc);
+ }
+
+ {
+ SysTime stFunc(in SysTime st)
+ {
+ return cast(SysTime)(st);
+ }
+
+ auto negInfInterval = NegInfInterval!SysTime(SysTime(DateTime(2012, 1, 7, 14, 0, 0)));
+
+ auto ir = NegInfIntervalRange!(SysTime)(negInfInterval, &stFunc);
+ }
+}
+
+//Test NegInfIntervalRange's front.
+unittest
+{
+ auto range = NegInfInterval!Date(Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed));
+ assertPred!"=="(range.front, Date(2012, 1, 7));
+
+ auto poppedRange = NegInfInterval!Date(Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed), PopFirst.yes);
+ assertPred!"=="(poppedRange.front, Date(2012, 1, 4));
+
+ const cRange = NegInfInterval!Date(Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri));
+ static assert(__traits(compiles, cRange.front));
+}
+
+//Test NegInfIntervalRange's popFront().
+unittest
+{
+ auto range = NegInfInterval!Date(Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed), PopFirst.yes);
+ auto expected = range.front;
+
+ foreach(date; take(range, 79))
+ {
+ assertPred!"=="(date, expected);
+ expected += dur!"days"(-7);
+ }
+
+ const cRange = NegInfInterval!Date(Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri));
+ static assert(!__traits(compiles, cRange.popFront()));
+}
+
+//Test NegInfIntervalRange's save.
+unittest
+{
+ auto interval = NegInfInterval!Date(Date(2012, 1, 7));
+ auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri);
+ auto range = interval.bwdRange(func);
+
+ assert(range.save == range);
+}
+
+//Test NegInfIntervalRange's interval.
+unittest
+{
+ auto interval = NegInfInterval!Date(Date(2012, 1, 7));
+ auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri);
+ auto range = interval.bwdRange(func);
+
+ assert(range.interval == interval);
+
+ const cRange = range;
+ static assert(__traits(compiles, cRange.interval));
+}
+
+//Test NegInfIntervalRange's func.
+unittest
+{
+ auto interval = NegInfInterval!Date(Date(2012, 1, 7));
+ auto func = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri);
+ auto range = interval.bwdRange(func);
+
+ assert(range.func == func);
+}
+
+
+//==============================================================================
+// Section with time zones.
+//==============================================================================
+
+/++
+ Represents a time zone. It is used with SysTime to indicate the time zone of
+ a SysTime.
+ +/
+abstract class TimeZone
+{
+public:
+
+ /++
+ The name of the time zone per the TZ database. This is the name used to
+ get a TimeZone by name with TimeZone.getTimeZone().
+
+ See_Also:
+ Wikipedia entry on TZ database
+ List of Time Zones
+ +/
+ @property string name() const nothrow
+ {
+ return _name;
+ }
+
+
+ /++
+ Typically, the abbreviation (generally 3 or 4 letters) for the time zone
+ when DST is $(I not) in effect (e.g. PST). It is not necessarily unique.
+
+ However, on Windows, it may be the unabbreviated name (e.g. Pacific
+ Standard Time). Regardless, it is not the same as name.
+ +/
+ @property string stdName() const nothrow
+ {
+ return _stdName;
+ }
+
+
+ /++
+ Typically, the abbreviation (generally 3 or 4 letters) for the time zone
+ when DST $(I is) in effect (e.g. PDT). It is not necessarily unique.
+
+ However, on Windows, it may be the unabbreviated name (e.g. Pacific
+ Daylight Time). Regardless, it is not the same as name.
+ +/
+ @property string dstName() const nothrow
+ {
+ return _dstName;
+ }
+
+
+ /++
+ Whether this time zone has Daylight Savings Time at any point in time.
+ Note that for some time zone types it may not have DST for current dates
+ but will still return true for hasDST because the time zone did at some
+ point have DST.
+ +/
+ @property abstract bool hasDST() const nothrow;
+
+
+ /++
+ Takes the number of hecto-nanoseconds (100 ns) since midnight, January 1st,
+ 1 A.D. in UTC time (i.e. std time) and returns whether DST is effect in
+ this time zone at the given point in time.
+
+ Params:
+ stdTime = The UTC time that needs to be checked for DST in this time zone.
+ +/
+ abstract bool dstInEffect(long stdTime) const nothrow;
+
+
+ /++
+ Takes the number of hecto-nanoseconds (100 ns) since midnight, January 1st,
+ 1 A.D. in UTC time (i.e. std time) and converts it to this time zone's time.
+
+ Params:
+ stdTime = The UTC time that needs to be adjusted to this time zone's
+ time.
+ +/
+ abstract long utcToTZ(long stdTime) const nothrow;
+
+
+ /++
+ Takes the number of hecto-nanoseconds (100 ns) since midnight, January 1st,
+ 1 A.D. in this time zone's time and converts it to UTC (i.e. std time).
+
+ Params:
+ adjTime = The time in this time zone that needs to be adjusted to
+ UTC time.
+ +/
+ abstract long tzToUTC(long adjTime) const nothrow;
+
+
+ /++
+ Returns a TimeZone with the give name per the TZ database.
+
+ This returns a PosixTimeZone on Posix systems and a WindowsTimeZone on
+ Windows systems. If you want a PosixTimeZone on Windows, then call
+ $(D PosixTimeZone.getTimeZone()) directly and give it the location of
+ the TZ database time zone files on disk.
+
+ See_Also:
+ Wikipedia entry on TZ database
+ List of Time Zones
+
+ Params:
+ name = The TZ database name of the time zone that you're looking for.
+
+ Throws:
+ DateTimeException if the given time zone could not be found.
+
+ Examples:
+--------------------
+auto tz = TimeZone.getTimeZone("America/Los_Angeles");
+--------------------
+ +/
+ static immutable(TimeZone) getTimeZone(string name)
+ {
+ version(Posix)
+ return PosixTimeZone.getTimeZone(name);
+ else version(Windows)
+ return WindowsTimeZone.getTimeZone(name);
+ }
+
+ unittest
+ {
+ //Verify Example.
+ auto tz = TimeZone.getTimeZone("America/Los_Angeles");
+ }
+
+
+ /++
+ Returns a list of the names of the time zones installed on the system.
+
+ You can provide a sub-name to narrow down the list of time zones (which
+ will likely be in the thousands if you get them all). For example,
+ if you pass in "America" as the sub-name, then only the time zones which
+ begin with "America" will be returned.
+
+ Params:
+ subname = The first part of the time zones that you want.
+
+ Throws:
+ FileException on Posix systems if it fails to read from disk.
+ DateTimeException on Windows systems if it fails to read the registry.
+ +/
+ static string[] getInstalledTZNames(string subname = "")
+ {
+ version(Posix)
+ return PosixTimeZone.getInstalledTZNames(subname);
+ else version(Windows)
+ return WindowsTimeZone.getInstalledTZNames(subname);
+ }
+
+
+private:
+
+ /++
+ Params:
+ name = The TZ database name for the time zone.
+ stdName = The abbreviation for the time zone during std time.
+ dstName = The abbreviation for the time zone during DST.
+ +/
+ this(string name, string stdName, string dstName) immutable pure
+ {
+ _name = name;
+ _stdName = stdName;
+ _dstName = dstName;
+ }
+
+
+ immutable string _name;
+ immutable string _stdName;
+ immutable string _dstName;
+}
+
+
+version(Posix)
+{
+//This should be in core.stdc.time, but it isn't, so
+//we're declaring it here.
+extern(C)
+{
+ extern __gshared char* tzname[2];
+ extern __gshared int daylight;
+}
+}
+
+
+/++
+ A TimeZone which represents the current local time zone on
+ the system running your program.
+
+ This uses the underlying C calls to adjust the time rather
+ than using specific D code based off of system settings to calculate
+ the time such as PosixTimeZone and WindowsTimeZone do. That also
+ means that it will use whatever the current time zone is on the system,
+ even if the system's time zone changes while the program is running.
+ +/
+final class LocalTime : TimeZone
+{
+public:
+
+ /++
+ LocalTime is a singleton class. $(D LocalTime()) returns its only instance.
+ +/
+ static immutable(LocalTime) opCall() pure nothrow
+ {
+ return _localTime;
+ }
+
+
+ version(D_Ddoc)
+ {
+ /++
+ The name of the time zone per the TZ database. This is the name used to
+ get a TimeZone by name with $(D TimeZone.getTimeZone()).
+
+ Note that this always returns the empty string. This is because time
+ zones cannot be uniquely identified by the attributes given by the OS
+ (such as the stdName and dstName), and neither Posix systems nor
+ Windows systems provide an easy way to get the TZ database name of
+ the local time zone.
+
+ See_Also:
+ Wikipedia entry on TZ database
+ List of Time Zones
+ +/
+ @property override string name() const nothrow
+ {
+ return super.name;
+ }
+ }
+
+
+ /++
+ Typically, the abbreviation (generally 3 or 4 letters) for the time zone
+ when DST is $(I not) in effect (e.g. PST). It is not necessarily unique.
+
+ However, on Windows, it may be the unabbreviated name (e.g. Pacific
+ Standard Time). Regardless, it is not the same as name.
+
+ This property is overridden because the local time of the system could
+ change while the program is running and we need to determine it dynamically
+ rather than it being fixed like it would be with most time zones.
+ +/
+ @property override string stdName() const nothrow
+ {
+ version(Posix)
+ {
+ try
+ return to!string(tzname[0]);
+ catch(Exception e)
+ assert(0, "to!string(tzname[0]) failed.");
+ }
+ else version(Windows)
+ {
+ try
+ {
+ TIME_ZONE_INFORMATION tzInfo;
+ GetTimeZoneInformation(&tzInfo);
+
+ //Cannot use to!string() like this should, probably due to bug http://d.puremagic.com/issues/show_bug.cgi?id=5016
+ //return to!string(tzInfo.StandardName);
+
+ wchar[32] str;
+
+ foreach(i, ref wchar c; str)
+ c = tzInfo.StandardName[i];
+
+ string retval;
+
+ foreach(dchar c; str)
+ {
+ if(c == '\0')
+ break;
+
+ retval ~= c;
+ }
+
+ return retval;
+ }
+ catch(Exception e)
+ assert(0, "GetTimeZoneInformation() threw.");
+ }
+ }
+
+ unittest
+ {
+ assert(LocalTime().stdName !is null);
+
+ version(Posix)
+ {
+ scope(exit) clearTZEnvVar();
+
+ setTZEnvVar("America/Los_Angeles");
+ assertPred!"=="(LocalTime().stdName, "PST");
+
+ setTZEnvVar("America/New_York");
+ assertPred!"=="(LocalTime().stdName, "EST");
+ }
+ }
+
+
+ /++
+ Typically, the abbreviation (generally 3 or 4 letters) for the time zone
+ when DST $(I is) in effect (e.g. PDT). It is not necessarily unique.
+
+ However, on Windows, it may be the unabbreviated name (e.g. Pacific
+ Daylight Time). Regardless, it is not the same as name.
+
+ This property is overridden because the local time of the system could
+ change while the program is running and we need to determine it
+ dynamically rather than it being fixed like it would be with most time
+ zones.
+ +/
+ @property override string dstName() const nothrow
+ {
+ version(Posix)
+ {
+ try
+ return to!string(tzname[1]);
+ catch(Exception e)
+ assert(0, "to!string(tzname[0]) failed.");
+ }
+ else version(Windows)
+ {
+ try
+ {
+ TIME_ZONE_INFORMATION tzInfo;
+ GetTimeZoneInformation(&tzInfo);
+
+ //Cannot use to!string() like this should, probably due to bug http://d.puremagic.com/issues/show_bug.cgi?id=5016
+ //return to!string(tzInfo.DaylightName);
+
+ wchar[32] str;
+
+ foreach(i, ref wchar c; str)
+ c = tzInfo.DaylightName[i];
+
+ string retval;
+
+ foreach(dchar c; str)
+ {
+ if(c == '\0')
+ break;
+
+ retval ~= c;
+ }
+
+ return retval;
+ }
+ catch(Exception e)
+ assert(0, "GetTimeZoneInformation() threw.");
+ }
+ }
+
+ unittest
+ {
+ assert(LocalTime().dstName !is null);
+
+ version(Posix)
+ {
+ scope(exit) clearTZEnvVar();
+
+ setTZEnvVar("America/Los_Angeles");
+ assertPred!"=="(LocalTime().dstName, "PDT");
+
+ setTZEnvVar("America/New_York");
+ assertPred!"=="(LocalTime().dstName, "EDT");
+ }
+ }
+
+
+ /++
+ Whether this time zone has Daylight Savings Time at any point in time.
+ Note that for some time zone types it may not have DST for current
+ dates but will still return true for hasDST because the time zone did
+ at some point have DST.
+ +/
+ @property override bool hasDST() const nothrow
+ {
+ version(Posix)
+ return cast(bool)(daylight);
+ else version(Windows)
+ {
+ try
+ {
+ TIME_ZONE_INFORMATION tzInfo;
+ GetTimeZoneInformation(&tzInfo);
+
+ return tzInfo.DaylightDate.wMonth != 0;
+ }
+ catch(Exception e)
+ assert(0, "GetTimeZoneInformation() threw.");
+ }
+ }
+
+ unittest
+ {
+ LocalTime().hasDST;
+
+ version(Posix)
+ {
+ scope(exit) clearTZEnvVar();
+
+ setTZEnvVar("America/Los_Angeles");
+ assert(LocalTime().hasDST);
+
+ setTZEnvVar("America/New_York");
+ assert(LocalTime().hasDST);
+ }
+ }
+
+
+ /++
+ Takes the number of hecto-nanoseconds (100 ns) since midnight, January
+ 1st, 1 A.D. in UTC time (i.e. std time) and returns whether DST is in
+ effect in this time zone at the given point in time.
+
+ Params:
+ stdTime = The UTC time that needs to be checked for DST in this time zone.
+ +/
+ override bool dstInEffect(long stdTime) const nothrow
+ {
+ time_t unixTime = stdTimeToUnixTime(stdTime);
+
+ version(Posix)
+ {
+ tm* timeInfo = localtime(&unixTime);
+
+ return cast(bool)(timeInfo.tm_isdst);
+ }
+ else version(Windows)
+ {
+ //Apparently Windows isn't smart enough to deal with negative time_t.
+ if(unixTime >= 0)
+ {
+ tm* timeInfo = localtime(&unixTime);
+
+ if(timeInfo)
+ return cast(bool)(timeInfo.tm_isdst);
+ }
+
+ TIME_ZONE_INFORMATION tzInfo;
+
+ try
+ GetTimeZoneInformation(&tzInfo);
+ catch(Exception e)
+ assert(0, "The impossible happened. GetTimeZoneInformation() threw.");
+
+ return WindowsTimeZone._dstInEffect(&tzInfo, stdTime);
+ }
+ }
+
+ unittest
+ {
+ auto currTime = Clock.currStdTime;
+ LocalTime().dstInEffect(currTime);
+
+ version(Posix)
+ {
+ scope(exit) clearTZEnvVar();
+ auto std = SysTime(DateTime(2010, 1, 1, 12, 0, 0), LocalTime());
+ auto dst = SysTime(DateTime(2010, 7, 1, 12, 0, 0), LocalTime());
+
+ setTZEnvVar("America/Los_Angeles");
+ assert(!LocalTime().dstInEffect(std.stdTime));
+ assert(LocalTime().dstInEffect(dst.stdTime));
+ assert(!std.dstInEffect);
+ assert(dst.dstInEffect);
+
+ setTZEnvVar("America/New_York");
+ assert(!LocalTime().dstInEffect(std.stdTime));
+ assert(LocalTime().dstInEffect(dst.stdTime));
+ assert(!std.dstInEffect);
+ assert(dst.dstInEffect);
+ }
+ }
+
+
+ /++
+ Returns hnsecs in the local time zone using the standard C function calls
+ on Posix systems and the standard Windows system calls on Windows systems
+ to adjust the time to the appropriate time zone from std time.
+
+ Params:
+ stdTime = The UTC time that needs to be adjusted to this time zone's
+ time.
+
+ See_Also:
+ TimeZone.utcToTZ()
+ +/
+ override long utcToTZ(long stdTime) const nothrow
+ {
+ version(Posix)
+ {
+ time_t unixTime = stdTimeToUnixTime(stdTime);
+ tm* timeInfo = localtime(&unixTime);
+
+ return stdTime + convert!("seconds", "hnsecs")(timeInfo.tm_gmtoff);
+ }
+ else version(Windows)
+ {
+ TIME_ZONE_INFORMATION tzInfo;
+
+ try
+ GetTimeZoneInformation(&tzInfo);
+ catch(Exception e)
+ assert(0, "GetTimeZoneInformation() threw.");
+
+ return WindowsTimeZone._utcToTZ(&tzInfo, stdTime, hasDST);
+ }
+ }
+
+ unittest
+ {
+ LocalTime().utcToTZ(0);
+
+ version(Posix)
+ {
+ scope(exit) clearTZEnvVar();
+
+ {
+ setTZEnvVar("America/Los_Angeles");
+ auto std = SysTime(Date(2010, 1, 1));
+ auto dst = SysTime(Date(2010, 7, 1));
+ assertPred!"=="(LocalTime().utcToTZ(std.stdTime), SysTime(DateTime(2009, 12, 31, 16, 0, 0)).stdTime);
+ assertPred!"=="(LocalTime().utcToTZ(dst.stdTime), SysTime(DateTime(2010, 6, 30, 17, 0, 0)).stdTime);
+ }
+
+ {
+ setTZEnvVar("America/New_York");
+ auto std = SysTime(Date(2010, 1, 1));
+ auto dst = SysTime(Date(2010, 7, 1));
+ assertPred!"=="(LocalTime().utcToTZ(std.stdTime), SysTime(DateTime(2009, 12, 31, 19, 0, 0)).stdTime);
+ assertPred!"=="(LocalTime().utcToTZ(dst.stdTime), SysTime(DateTime(2010, 6, 30, 20, 0, 0)).stdTime);
+ }
+ }
+ }
+
+
+ /++
+ Returns std time using the standard C function calls on Posix systems
+ and the standard Windows system calls on Windows systems to adjust the
+ time to UTC from the appropriate time zone.
+
+ See_Also:
+ TimeZone.tzToUTC()
+
+ Params:
+ adjTime = The time in this time zone that needs to be adjusted to
+ UTC time.
+ +/
+ override long tzToUTC(long adjTime) const nothrow
+ {
+ version(Posix)
+ {
+ time_t unixTime = stdTimeToUnixTime(adjTime);
+ tm* timeInfo = localtime(&unixTime);
+
+ return adjTime - convert!("seconds", "hnsecs")(timeInfo.tm_gmtoff);
+ }
+ else version(Windows)
+ {
+ TIME_ZONE_INFORMATION tzInfo;
+
+ try
+ GetTimeZoneInformation(&tzInfo);
+ catch(Exception e)
+ assert(0, "GetTimeZoneInformation() threw.");
+
+ return WindowsTimeZone._tzToUTC(&tzInfo, adjTime, hasDST);
+ }
+ }
+
+ unittest
+ {
+ LocalTime().tzToUTC(0);
+ assertPred!"=="(LocalTime().tzToUTC(LocalTime().utcToTZ(0)), 0);
+ assertPred!"=="(LocalTime().utcToTZ(LocalTime().tzToUTC(0)), 0);
+
+ version(Posix)
+ {
+ scope(exit) clearTZEnvVar();
+
+ {
+ setTZEnvVar("America/Los_Angeles");
+ auto std = SysTime(DateTime(2009, 12, 31, 16, 0, 0));
+ auto dst = SysTime(DateTime(2010, 6, 30, 17, 0, 0));
+ assertPred!"=="(LocalTime().tzToUTC(std.stdTime), SysTime(Date(2010, 1, 1)).stdTime);
+ assertPred!"=="(LocalTime().tzToUTC(dst.stdTime), SysTime(Date(2010, 7, 1)).stdTime);
+ }
+
+ {
+ setTZEnvVar("America/New_York");
+ auto std = SysTime(DateTime(2009, 12, 31, 19, 0, 0));
+ auto dst = SysTime(DateTime(2010, 6, 30, 20, 0, 0));
+ assertPred!"=="(LocalTime().tzToUTC(std.stdTime), SysTime(Date(2010, 1, 1)).stdTime);
+ assertPred!"=="(LocalTime().tzToUTC(dst.stdTime), SysTime(Date(2010, 7, 1)).stdTime);
+ }
+ }
+ }
+
+
+private:
+
+ this() immutable pure
+ {
+ super("", "", "");
+ }
+
+
+ static immutable LocalTime _localTime;
+
+
+ static this()
+ {
+ tzset();
+
+ _localTime = new immutable(LocalTime)();
+ }
+}
+
+
+/++
+ A TimeZone which represents UTC.
+ +/
+final class UTC : TimeZone
+{
+public:
+
+ /++
+ UTC is a singleton class. $(D UTC()) returns its only instance.
+ +/
+ static immutable(UTC) opCall() pure nothrow
+ {
+ return _utc;
+ }
+
+
+ /++
+ Always returns false.
+ +/
+ @property override bool hasDST() const nothrow
+ {
+ return false;
+ }
+
+
+ /++
+ Always returns false.
+ +/
+ override bool dstInEffect(long stdTime) const nothrow
+ {
+ return false;
+ }
+
+
+ /++
+ Returns the given hnsecs without changing them at all.
+
+ Params:
+ stdTime = The UTC time that needs to be adjusted to this time zone's
+ time.
+
+ See_Also:
+ TimeZone.utcToTZ()
+ +/
+ override long utcToTZ(long stdTime) const nothrow
+ {
+ return stdTime;
+ }
+
+ unittest
+ {
+ assertPred!"=="(UTC().utcToTZ(0), 0);
+
+ version(Posix)
+ {
+ scope(exit) clearTZEnvVar();
+
+ setTZEnvVar("UTC");
+ auto std = SysTime(Date(2010, 1, 1));
+ auto dst = SysTime(Date(2010, 7, 1));
+ assertPred!"=="(UTC().utcToTZ(std.stdTime), std.stdTime);
+ assertPred!"=="(UTC().utcToTZ(dst.stdTime), dst.stdTime);
+ }
+ }
+
+
+ /++
+ Returns the given hnsecs without changing them at all.
+
+ See_Also:
+ TimeZone.tzToUTC()
+
+ Params:
+ adjTime = The time in this time zone that needs to be adjusted to
+ UTC time.
+ +/
+ override long tzToUTC(long adjTime) const nothrow
+ {
+ return adjTime;
+ }
+
+ unittest
+ {
+ assertPred!"=="(UTC().tzToUTC(0), 0);
+
+ version(Posix)
+ {
+ scope(exit) clearTZEnvVar();
+
+ setTZEnvVar("UTC");
+ auto std = SysTime(Date(2010, 1, 1));
+ auto dst = SysTime(Date(2010, 7, 1));
+ assertPred!"=="(UTC().tzToUTC(std.stdTime), std.stdTime);
+ assertPred!"=="(UTC().tzToUTC(dst.stdTime), dst.stdTime);
+ }
+ }
+
+
+private:
+
+ this() immutable pure
+ {
+ super("UTC", "UTC", "UTC");
+ }
+
+
+ static immutable UTC _utc;
+
+
+ static this()
+ {
+ _utc = new immutable(UTC)();
+ }
+}
+
+
+/++
+ Represents a time zone with an offset (in minutes, west is negative) from
+ UTC but no DST.
+
+ It's primarily used as the time zone in the result of $(D SysTime)'s
+ $(D fromISOString()), $(D fromISOExtendedString()), and
+ $(D fromSimpleString()).
+
+ $(D name) and $(D dstName) are always the empty string since this time zone
+ has no DST and while it may be meant to represent a time zone which is in
+ the TZ database, obviously it's not likely to be following the exact rules
+ of any of the time zones in the TZ database, so it makes no sense to set it.
+ +/
+final class SimpleTimeZone : TimeZone
+{
+public:
+
+ /++
+ Always returns false.
+ +/
+ @property override bool hasDST() const nothrow
+ {
+ return false;
+ }
+
+
+ /++
+ Always returns false.
+ +/
+ override bool dstInEffect(long stdTime) const nothrow
+ {
+ return false;
+ }
+
+
+ /++
+ Takes the number of hecto-nanoseconds (100 ns) since midnight, January
+ 1st, 1 A.D. in UTC time (i.e. std time) and converts it to this time
+ zone's time.
+
+ Params:
+ stdTime = The UTC time that needs to be adjusted to this time
+ zone's time.
+ +/
+ override long utcToTZ(long stdTime) const nothrow
+ {
+ return stdTime + convert!("minutes", "hnsecs")(utcOffset);
+ }
+
+ unittest
+ {
+ assertPred!"=="((new SimpleTimeZone(-8 * 60)).utcToTZ(0), -288_000_000_000L);
+ assertPred!"=="((new SimpleTimeZone(8 * 60)).utcToTZ(0), 288_000_000_000L);
+ assertPred!"=="((new SimpleTimeZone(-8 * 60)).utcToTZ(54_321_234_567_890L), 54_033_234_567_890L);
+ auto stz = new SimpleTimeZone(-8 * 60);
+ const cstz = new SimpleTimeZone(-8 * 60);
+ static assert(__traits(compiles, stz.utcToTZ(50002)));
+ static assert(__traits(compiles, cstz.utcToTZ(50002)));
+ }
+
+
+ /++
+ Takes the number of hecto-nanoseconds (100 ns) since midnight, January
+ 1st, 1 A.D. in this time zone's time and converts it to UTC
+ (i.e. std time).
+
+ Params:
+ adjTime = The time in this time zone that needs to be adjusted to
+ UTC time.
+ +/
+ override long tzToUTC(long adjTime) const nothrow
+ {
+ return adjTime - convert!("minutes", "hnsecs")(utcOffset);
+ }
+
+ unittest
+ {
+ assertPred!"=="((new SimpleTimeZone(-8 * 60)).tzToUTC(-288_000_000_000L), 0);
+ assertPred!"=="((new SimpleTimeZone(8 * 60)).tzToUTC(288_000_000_000L), 0);
+ assertPred!"=="((new SimpleTimeZone(-8 * 60)).tzToUTC(54_033_234_567_890L), 54_321_234_567_890L);
+
+ auto stz = new SimpleTimeZone(-8 * 60);
+ const cstz = new SimpleTimeZone(-8 * 60);
+ static assert(__traits(compiles, stz.tzToUTC(20005)));
+ static assert(__traits(compiles, cstz.tzToUTC(20005)));
+ }
+
+
+ /++
+ Params:
+ utcOffset = This time zone's offset from UTC in minutes with west
+ of UTC being negative (it is added to UTC to get the
+ adjusted time).
+ stdName = The stdName for this time zone.
+ +/
+ this(int utcOffset, string stdName = "") immutable
+ {
+ enforce(abs(utcOffset) < 1440, new DateTimeException("Offset from UTC must be within range (-24:00 - 24:00)."));
+
+ super("", stdName, "");
+
+ this.utcOffset = utcOffset;
+ }
+
+ unittest
+ {
+ auto stz = new SimpleTimeZone(-8 * 60, "PST");
+
+ assertPred!"=="(stz.name, "");
+ assertPred!"=="(stz.stdName, "PST");
+ assertPred!"=="(stz.dstName, "");
+ assertPred!"=="(stz.utcOffset, -8 * 60);
+ }
+
+
+ /++
+ The number of minutes the offset from UTC is (negative is west of UTC,
+ positive is east).
+ +/
+ immutable int utcOffset;
+
+private:
+
+ /++
+ Returns a time zone as a string with an offset from UTC.
+
+ Time zone offsets will be in the form +HH:MM or -HH:MM.
+
+ Params:
+ utcOffset = The number of minutes offset from UTC (negative means
+ west).
+ +/
+ static string toISOString(int utcOffset)
+ {
+ immutable absOffset = abs(utcOffset);
+ enforce(absOffset < 1440, new DateTimeException("Offset from UTC must be within range (-24:00 - 24:00)."));
+
+ immutable hours = convert!("minutes", "hours")(absOffset);
+ immutable minutes = absOffset - convert!("hours", "minutes")(hours);
+
+ if(utcOffset < 0)
+ return format("-%02d:%02d", hours, minutes);
+
+ return format("+%02d:%02d", hours, minutes);
+ }
+
+ unittest
+ {
+ static string testSTZInvalid(int offset)
+ {
+ return SimpleTimeZone.toISOString(offset);
+ }
+
+ assertThrown!DateTimeException(testSTZInvalid(1440));
+ assertThrown!DateTimeException(testSTZInvalid(-1440));
+
+ assertPred!"=="(toISOString(0), "+00:00");
+ assertPred!"=="(toISOString(1), "+00:01");
+ assertPred!"=="(toISOString(10), "+00:10");
+ assertPred!"=="(toISOString(59), "+00:59");
+ assertPred!"=="(toISOString(60), "+01:00");
+ assertPred!"=="(toISOString(90), "+01:30");
+ assertPred!"=="(toISOString(120), "+02:00");
+ assertPred!"=="(toISOString(480), "+08:00");
+ assertPred!"=="(toISOString(1439), "+23:59");
+
+ assertPred!"=="(toISOString(-1), "-00:01");
+ assertPred!"=="(toISOString(-10), "-00:10");
+ assertPred!"=="(toISOString(-59), "-00:59");
+ assertPred!"=="(toISOString(-60), "-01:00");
+ assertPred!"=="(toISOString(-90), "-01:30");
+ assertPred!"=="(toISOString(-120), "-02:00");
+ assertPred!"=="(toISOString(-480), "-08:00");
+ assertPred!"=="(toISOString(-1439), "-23:59");
+ }
+
+
+ /++
+ Takes a time zone as a string with an offset from UTC and returns a
+ $(D SimpleTimeZone) which matches.
+
+ The accepted formats for time zone offsets are +H, -H, +HH, -HH, +H:MM,
+ -H:MM, +HH:MM, and -HH:MM.
+
+ Params:
+ isoString = A string which represents a time zone in the ISO format.
+ +/
+ static immutable(SimpleTimeZone) fromISOString(S)(S isoString)
+ if(isSomeString!(S))
+ {
+ auto dstr = to!dstring(strip(isoString));
+
+ enforce(dstr.startsWith("-") || dstr.startsWith("+"), new DateTimeException("Invalid ISO String"));
+
+ auto sign = dstr.startsWith("-") ? -1 : 1;
+
+ dstr.popFront();
+ enforce(!dstr.empty, new DateTimeException("Invalid ISO String"));
+
+ immutable colon = dstr.indexOf(":");
+
+ dstring hoursStr;
+ dstring minutesStr;
+
+ if(colon != -1)
+ {
+ hoursStr = dstr[0 .. colon];
+ minutesStr = dstr[colon + 1 .. $];
+ enforce(minutesStr.length == 2, new DateTimeException(format("Invalid ISO String: %s", dstr)));
+ }
+ else
+ hoursStr = dstr;
+
+ enforce(!canFind!((dchar c){return !isdigit(c);})(hoursStr), new DateTimeException(format("Invalid ISO String: %s", dstr)));
+ enforce(!canFind!((dchar c){return !isdigit(c);})(minutesStr), new DateTimeException(format("Invalid ISO String: %s", dstr)));
+
+ immutable hours = to!int(hoursStr);
+ immutable minutes = minutesStr.empty ? 0 : to!int(minutesStr);
+
+ return new SimpleTimeZone(sign * cast(int)(convert!("hours", "minutes")(hours) + minutes));
+ }
+
+ unittest
+ {
+ assertThrown!DateTimeException(SimpleTimeZone.fromISOString(""));
+ assertThrown!DateTimeException(SimpleTimeZone.fromISOString("Z"));
+ assertThrown!DateTimeException(SimpleTimeZone.fromISOString("-"));
+ assertThrown!DateTimeException(SimpleTimeZone.fromISOString("+"));
+ assertThrown!DateTimeException(SimpleTimeZone.fromISOString("-:"));
+ assertThrown!DateTimeException(SimpleTimeZone.fromISOString("+:"));
+ assertThrown!DateTimeException(SimpleTimeZone.fromISOString("-1:"));
+ assertThrown!DateTimeException(SimpleTimeZone.fromISOString("+1:"));
+ assertThrown!DateTimeException(SimpleTimeZone.fromISOString("1"));
+ assertThrown!DateTimeException(SimpleTimeZone.fromISOString("-24:00"));
+ assertThrown!DateTimeException(SimpleTimeZone.fromISOString("+24:00"));
+ assertThrown!DateTimeException(SimpleTimeZone.fromISOString("+1:0"));
+
+ assertPred!"=="(SimpleTimeZone.fromISOString("+00:00").utcOffset, (new SimpleTimeZone(0)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("+00:01").utcOffset, (new SimpleTimeZone(1)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("+00:10").utcOffset, (new SimpleTimeZone(10)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("+00:59").utcOffset, (new SimpleTimeZone(59)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("+01:00").utcOffset, (new SimpleTimeZone(60)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("+01:30").utcOffset, (new SimpleTimeZone(90)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("+02:00").utcOffset, (new SimpleTimeZone(120)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("+08:00").utcOffset, (new SimpleTimeZone(480)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("+23:59").utcOffset, (new SimpleTimeZone(1439)).utcOffset);
+
+ assertPred!"=="(SimpleTimeZone.fromISOString("-00:01").utcOffset, (new SimpleTimeZone(-1)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("-00:10").utcOffset, (new SimpleTimeZone(-10)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("-00:59").utcOffset, (new SimpleTimeZone(-59)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("-01:00").utcOffset, (new SimpleTimeZone(-60)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("-01:30").utcOffset, (new SimpleTimeZone(-90)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("-02:00").utcOffset, (new SimpleTimeZone(-120)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("-08:00").utcOffset, (new SimpleTimeZone(-480)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("-23:59").utcOffset, (new SimpleTimeZone(-1439)).utcOffset);
+
+ assertPred!"=="(SimpleTimeZone.fromISOString("+0").utcOffset, (new SimpleTimeZone(0)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("+1").utcOffset, (new SimpleTimeZone(60)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("+2").utcOffset, (new SimpleTimeZone(120)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("+23").utcOffset, (new SimpleTimeZone(1380)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("+2").utcOffset, (new SimpleTimeZone(120)).utcOffset);
+
+ assertPred!"=="(SimpleTimeZone.fromISOString("+0").utcOffset, (new SimpleTimeZone(0)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("+1").utcOffset, (new SimpleTimeZone(60)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("+2").utcOffset, (new SimpleTimeZone(120)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("+23").utcOffset, (new SimpleTimeZone(1380)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("+1:00").utcOffset, (new SimpleTimeZone(60)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("+1:01").utcOffset, (new SimpleTimeZone(61)).utcOffset);
+
+ assertPred!"=="(SimpleTimeZone.fromISOString("-0").utcOffset, (new SimpleTimeZone(0)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("-1").utcOffset, (new SimpleTimeZone(-60)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("-2").utcOffset, (new SimpleTimeZone(-120)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("-23").utcOffset, (new SimpleTimeZone(-1380)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("-1:00").utcOffset, (new SimpleTimeZone(-60)).utcOffset);
+ assertPred!"=="(SimpleTimeZone.fromISOString("-1:01").utcOffset, (new SimpleTimeZone(-61)).utcOffset);
+ }
+
+ //Test that converting from an ISO string to a SimpleTimeZone to an ISO String works properly.
+ unittest
+ {
+ static void testSTZ(in string isoString, int expectedOffset, size_t line = __LINE__)
+ {
+ auto stz = SimpleTimeZone.fromISOString(isoString);
+ assertPred!"=="(stz.utcOffset, expectedOffset, "", __FILE__, line);
+
+ auto result = SimpleTimeZone.toISOString(stz.utcOffset);
+ assertPred!"=="(result, isoString, "", __FILE__, line);
+ }
+
+ testSTZ("+00:00", 0);
+ testSTZ("+00:01", 1);
+ testSTZ("+00:10", 10);
+ testSTZ("+00:59", 59);
+ testSTZ("+01:00", 60);
+ testSTZ("+01:30", 90);
+ testSTZ("+02:00", 120);
+ testSTZ("+08:00", 480);
+ testSTZ("+08:00", 480);
+ testSTZ("+23:59", 1439);
+
+ testSTZ("-00:01", -1);
+ testSTZ("-00:10", -10);
+ testSTZ("-00:59", -59);
+ testSTZ("-01:00", -60);
+ testSTZ("-01:30", -90);
+ testSTZ("-02:00", -120);
+ testSTZ("-08:00", -480);
+ testSTZ("-08:00", -480);
+ testSTZ("-23:59", -1439);
+ }
+}
+
+
+/++
+ Represents a time zone from a TZ database time zone file. Files from the TZ
+ database are how Posix systems hold their time zone information. Unfortunately,
+ Windows does not use the TZ database, though it does name its time zones
+ using the TZ database names. You can, however, use PosixTimeZone (which reads
+ its information from the TZ database files on disk) on Windows if you provide
+ the TZ database files
+ ( Repository with the TZ database files (tzdata) )
+ yourself and tell $(D PosixTimeZone.getTimeZone()) where the directory holding
+ them is.
+
+ TZ database files hold DST transitions for a large interval of the time
+ covered by time_t. So, barring errors in the information in the TZ database
+ files, it will use the correct DST rules for any date. Windows, on the other
+ hand, maintains only the current DST rules, so historical dates will use the
+ current DST rules (and therefore potentially be incorrect). So, if you want
+ the DST rules that you use to be more accurate, or if you're looking for your
+ program to act consistently on both Posix and Windows systems, then, as
+ mentioned above, you'll need to include the TZ database files with your program
+ and give $(D PosixTimeZone.getTimeZone()) the directory on disk where they
+ are located.
+
+ To get a PosixTimeZone, either call $(D PosixTimeZone.getTimeZone()) (which
+ will allow you to specify the location the time zone files) or call
+ $(D TimeZone.getTimeZone()) (which will give you a PosixTimeZone on Posix
+ systems and a WindowsTimeZone on Windows systems).
+
+ Note:
+ Unless your system's local time zone deals with leap seconds (which is
+ highly unlikely), then only way that you will get a time zone which takes
+ leap seconds into account is if you use PosixTimeZone with a time zone
+ whose name starts with "right/". Those time zone files do include leap
+ seconds, and PosixTimeZone will take them into account (though posix
+ systems which use a "right/" time zone as their local time zone will
+ *not* take leap seconds into account even though they're in the file).
+
+ See_Also:
+ Wikipedia entry on TZ database
+ List of Time Zones
+ +/
+final class PosixTimeZone : TimeZone
+{
+public:
+
+ /++
+ Whether this time zone has Daylight Savings Time at any point in time.
+ Note that for some time zone types it may not have DST for current
+ dates but will still return true for hasDST because the time zone did
+ at some point have DST.
+ +/
+ @property override bool hasDST() const nothrow
+ {
+ return _hasDST;
+ }
+
+
+ /++
+ Takes the number of hecto-nanoseconds (100 ns) since midnight, January
+ 1st, 1 A.D. in UTC time (i.e. std time) and returns whether DST is in
+ effect in this time zone at the given point in time.
+
+ Params:
+ stdTime = The UTC time that needs to be checked for DST in this time zone.
+ +/
+ override bool dstInEffect(long stdTime) const nothrow
+ {
+ assert(!_transitions.empty);
+
+ try
+ {
+ immutable unixTime = stdTimeToUnixTime(stdTime);
+
+ if(_transitions.front.timeT >= unixTime)
+ return _transitions.front.ttInfo.isDST;
+
+ //Okay, casting is a hack, but indexOf shouldn't be changing it, and it would be
+ //too inefficient to have to keep duping it every time we have to calculate the time.
+ //Hopefully, indexOf will properly support immutable ranges at some point.
+ auto found = std.algorithm.indexOf!"b < a.timeT"(cast(Transition[])_transitions, unixTime);
+
+ if(found == -1)
+ return _transitions.back.ttInfo.isDST;
+
+ auto transition = found == 0 ? _transitions[0] : _transitions[found - 1];
+
+ return transition.ttInfo.isDST;
+ }
+ catch(Exception e)
+ assert(0, format("Nothing in calculateLeapSeconds() should be throwing. Caught Exception: %s", e));
+ }
+
+
+ /++
+ Takes the number of hecto-nanoseconds (100 ns) since midnight, January 1st,
+ 1 A.D. in UTC time (i.e. std time) and converts it to this time zone's time.
+
+ Params:
+ stdTime = The UTC time that needs to be adjusted to this time zone's time.
+ +/
+ override long utcToTZ(long stdTime) const nothrow
+ {
+ assert(!_transitions.empty);
+
+ try
+ {
+ immutable leapSecs = calculateLeapSeconds(stdTime);
+ immutable unixTime = stdTimeToUnixTime(stdTime);
+
+ if(_transitions.front.timeT >= unixTime)
+ return stdTime + convert!("seconds", "hnsecs")(_transitions.front.ttInfo.utcOffset + leapSecs);
+
+ //Okay, casting is a hack, but indexOf shouldn't be changing it, and it would be
+ //too inefficient to have to keep duping it every time we have to calculate the time.
+ //Hopefully, indexOf will properly support immutable ranges at some point.
+ auto found = std.algorithm.indexOf!"b < a.timeT"(cast(Transition[])_transitions, unixTime);
+
+ if(found == -1)
+ return stdTime + convert!("seconds", "hnsecs")(_transitions.back.ttInfo.utcOffset + leapSecs);
+
+ auto transition = found == 0 ? _transitions[0] : _transitions[found - 1];
+
+ return stdTime + convert!("seconds", "hnsecs")(transition.ttInfo.utcOffset + leapSecs);
+ }
+ catch(Exception e)
+ assert(0, format("Nothing in calculateLeapSeconds() should be throwing. Caught Exception: %s", e));
+ }
+
+
+ /++
+ Takes the number of hecto-nanoseconds (100 ns) since midnight, January
+ 1st, 1 A.D. in this time zone's time and converts it to UTC
+ (i.e. std time).
+
+ Params:
+ adjTime = The time in this time zone that needs to be adjusted to UTC time.
+ +/
+ override long tzToUTC(long adjTime) const nothrow
+ {
+ assert(!_transitions.empty);
+
+ try
+ {
+ immutable leapSecs = calculateLeapSeconds(adjTime);
+ immutable unixTime = stdTimeToUnixTime(adjTime);
+
+ if(_transitions.front.timeT >= unixTime)
+ return adjTime - convert!("seconds", "hnsecs")(_transitions.front.ttInfo.utcOffset + leapSecs);
+
+ //Okay, casting is a hack, but indexOf shouldn't be changing it, and it would be
+ //too inefficient to have to keep duping it every time we have to calculate the time.
+ //Hopefully, indexOf will properly support immutable ranges at some point.
+ auto found = std.algorithm.indexOf!"b < a.timeT"(cast(Transition[])_transitions, unixTime);
+
+ if(found == -1)
+ return adjTime - convert!("seconds", "hnsecs")(_transitions.back.ttInfo.utcOffset + leapSecs);
+
+ auto transition = found == 0 ? _transitions[0] : _transitions[found - 1];
+
+ return adjTime - convert!("seconds", "hnsecs")(transition.ttInfo.utcOffset + leapSecs);
+ }
+ catch(Exception e)
+ assert(0, format("Nothing in calculateLeapSeconds() should be throwing. Caught Exception: %s", e));
+ }
+
+
+ version(Posix)
+ /// The default directory where the TZ database files are. It's empty for Windows, since Windows doesn't have them.
+ enum defaultTZDatabaseDir = "/usr/share/zoneinfo/";
+ else version(Windows)
+ /// The default directory where the TZ database files are. It's empty for Windows, since Windows doesn't have them.
+ enum defaultTZDatabaseDir = "";
+
+
+ /++
+ Returns a TimeZone with the give name per the TZ database. The time zone
+ information is fetched from the TZ database time zone files in the given
+ directory.
+
+ See_Also:
+ Wikipedia entry on TZ database
+ List of Time Zones
+
+ Params:
+ name = The TZ database name of the time zone that you're
+ looking for.
+ tzDatabaseDir = The directory where the TZ database files are located.
+ Because these files are not located on Windows systems,
+ you will need to provide them yourself and give their
+ location here if you wish to use PosixTimeZones.
+
+ Throws:
+ DateTimeException if the given time zone could not be found or
+ FileException if the TZ database file could not be opened.
+
+ Examples:
+--------------------
+auto tz = PosixTimeZone.getTimeZone("America/Los_Angeles");
+
+assert(tz.name == "America/Los_Angeles");
+assert(tz.stdName == "PST");
+assert(tz.dstName == "PDT");
+--------------------
+ +/
+ //TODO make it possible for tzDatabaseDir to be gzipped tar file rather than an uncompressed
+ // directory.
+ static immutable(PosixTimeZone) getTimeZone(string name, string tzDatabaseDir = defaultTZDatabaseDir)
+ {
+ name = strip(name);
+
+ enforce(tzDatabaseDir.exists, new DateTimeException(format("Directory %s does not exist.", tzDatabaseDir)));
+ enforce(tzDatabaseDir.isdir, new DateTimeException(format("%s is not a directory.", tzDatabaseDir)));
+
+ version(Posix)
+ auto file = tzDatabaseDir ~ sep ~ name;
+ else version(Windows)
+ auto file = tzDatabaseDir ~ sep ~ replace(strip(name), "/", sep);
+
+ enforce(file.exists, new DateTimeException(format("File %s does not exist.", file)));
+ enforce(file.isfile, new DateTimeException(format("%s is not a file.", file)));
+
+ auto tzFile = File(file);
+ immutable gmtZone = file.canFind("GMT");
+
+ try
+ {
+ _enforceValidTZFile(readVal!(char[])(tzFile, 4) == "TZif");
+
+ immutable char tzFileVersion = readVal!char(tzFile);
+ _enforceValidTZFile(tzFileVersion == '\0' || tzFileVersion == '2');
+
+ {
+ auto zeroBlock = readVal!(ubyte[])(tzFile, 15);
+ bool allZeroes = true;
+
+ foreach(val; zeroBlock)
+ {
+ if(val != 0)
+ {
+ allZeroes = false;
+ break;
+ }
+ }
+
+ _enforceValidTZFile(allZeroes);
+ }
+
+
+ //The number of UTC/local indicators stored in the file.
+ auto tzh_ttisgmtcnt = readVal!int(tzFile);
+
+ //The number of standard/wall indicators stored in the file.
+ auto tzh_ttisstdcnt = readVal!int(tzFile);
+
+ //The number of leap seconds for which data is stored in the file.
+ auto tzh_leapcnt = readVal!int(tzFile);
+
+ //The number of "transition times" for which data is stored in the file.
+ auto tzh_timecnt = readVal!int(tzFile);
+
+ //The number of "local time types" for which data is stored in the file (must not be zero).
+ auto tzh_typecnt = readVal!int(tzFile);
+ _enforceValidTZFile(tzh_typecnt != 0);
+
+ //The number of characters of "timezone abbreviation strings" stored in the file.
+ auto tzh_charcnt = readVal!int(tzFile);
+
+ //time_ts where DST transitions occur.
+ auto transitionTimeTs = new long[](tzh_timecnt);
+ foreach(ref transition; transitionTimeTs)
+ transition = readVal!int(tzFile);
+
+ //Indices into ttinfo structs indicating the changes
+ //to be made at the corresponding DST transition.
+ auto ttInfoIndices = new ubyte[](tzh_timecnt);
+ foreach(ref ttInfoIndex; ttInfoIndices)
+ ttInfoIndex = readVal!ubyte(tzFile);
+
+ //ttinfos which give info on DST transitions.
+ auto tempTTInfos = new TempTTInfo[](tzh_typecnt);
+ foreach(ref ttInfo; tempTTInfos)
+ ttInfo = readVal!TempTTInfo(tzFile);
+
+ //The array of time zone abbreviation characters.
+ auto tzAbbrevChars = readVal!(char[])(tzFile, tzh_charcnt);
+
+ auto leapSeconds = new LeapSecond[](tzh_leapcnt);
+ foreach(ref leapSecond; leapSeconds)
+ {
+ //The time_t when the leap second occurs.
+ auto timeT = readVal!int(tzFile);
+
+ //The total number of leap seconds to be applied after
+ //the corresponding leap second.
+ auto total = readVal!int(tzFile);
+
+ leapSecond = LeapSecond(timeT, total);
+ }
+
+ //Indicate whether each corresponding DST transition were specified
+ //in standard time or wall clock time.
+ auto transitionIsStd = new bool[](tzh_ttisstdcnt);
+ foreach(ref isStd; transitionIsStd)
+ isStd = readVal!bool(tzFile);
+
+ //Indicate whether each corresponding DST transition associated with
+ //local time types are specified in UTC or local time.
+ auto transitionInUTC = new bool[](tzh_ttisgmtcnt);
+ foreach(ref inUTC; transitionInUTC)
+ inUTC = readVal!bool(tzFile);
+
+ _enforceValidTZFile(!tzFile.eof());
+
+ //If version 2, the information is duplicated in 64-bit.
+ if(tzFileVersion == '2')
+ {
+ _enforceValidTZFile(readVal!(char[])(tzFile, 4) == "TZif");
+
+ _enforceValidTZFile(readVal!(char)(tzFile) == '2');
+
+ {
+ auto zeroBlock = readVal!(ubyte[])(tzFile, 15);
+ bool allZeroes = true;
+
+ foreach(val; zeroBlock)
+ {
+ if(val != 0)
+ {
+ allZeroes = false;
+ break;
+ }
+ }
+
+ _enforceValidTZFile(allZeroes);
+ }
+
+
+ //The number of UTC/local indicators stored in the file.
+ tzh_ttisgmtcnt = readVal!int(tzFile);
+
+ //The number of standard/wall indicators stored in the file.
+ tzh_ttisstdcnt = readVal!int(tzFile);
+
+ //The number of leap seconds for which data is stored in the file.
+ tzh_leapcnt = readVal!int(tzFile);
+
+ //The number of "transition times" for which data is stored in the file.
+ tzh_timecnt = readVal!int(tzFile);
+
+ //The number of "local time types" for which data is stored in the file (must not be zero).
+ tzh_typecnt = readVal!int(tzFile);
+ _enforceValidTZFile(tzh_typecnt != 0);
+
+ //The number of characters of "timezone abbreviation strings" stored in the file.
+ tzh_charcnt = readVal!int(tzFile);
+
+ //time_ts where DST transitions occur.
+ transitionTimeTs = new long[](tzh_timecnt);
+ foreach(ref transition; transitionTimeTs)
+ transition = readVal!long(tzFile);
+
+ //Indices into ttinfo structs indicating the changes
+ //to be made at the corresponding DST transition.
+ ttInfoIndices = new ubyte[](tzh_timecnt);
+ foreach(ref ttInfoIndex; ttInfoIndices)
+ ttInfoIndex = readVal!ubyte(tzFile);
+
+ //ttinfos which give info on DST transitions.
+ tempTTInfos = new TempTTInfo[](tzh_typecnt);
+ foreach(ref ttInfo; tempTTInfos)
+ ttInfo = readVal!TempTTInfo(tzFile);
+
+ //The array of time zone abbreviation characters.
+ tzAbbrevChars = readVal!(char[])(tzFile, tzh_charcnt);
+
+ leapSeconds = new LeapSecond[](tzh_leapcnt);
+ foreach(ref leapSecond; leapSeconds)
+ {
+ //The time_t when the leap second occurs.
+ auto timeT = readVal!long(tzFile);
+
+ //The total number of leap seconds to be applied after
+ //the corresponding leap second.
+ auto total = readVal!int(tzFile);
+
+ leapSecond = LeapSecond(timeT, total);
+ }
+
+ //Indicate whether each corresponding DST transition were specified
+ //in standard time or wall clock time.
+ transitionIsStd = new bool[](tzh_ttisstdcnt);
+ foreach(ref isStd; transitionIsStd)
+ isStd = readVal!bool(tzFile);
+
+ //Indicate whether each corresponding DST transition associated with
+ //local time types are specified in UTC or local time.
+ transitionInUTC = new bool[](tzh_ttisgmtcnt);
+ foreach(ref inUTC; transitionInUTC)
+ inUTC = readVal!bool(tzFile);
+ }
+
+ _enforceValidTZFile(tzFile.readln().strip().empty());
+
+ auto posixEnvStr = tzFile.readln().strip();
+
+ _enforceValidTZFile(tzFile.readln().strip().empty());
+ _enforceValidTZFile(tzFile.eof());
+
+
+ auto transitionTypes = new TransitionType*[](tempTTInfos.length);
+
+ foreach(i, ref ttype; transitionTypes)
+ {
+ bool isStd = false;
+
+ if(i < transitionIsStd.length && !transitionIsStd.empty)
+ isStd = transitionIsStd[i];
+
+ bool inUTC = false;
+
+ if(i < transitionInUTC.length && !transitionInUTC.empty)
+ inUTC = transitionInUTC[i];
+
+ ttype = new TransitionType(isStd, inUTC);
+ }
+
+ auto ttInfos = new immutable(TTInfo)*[](tempTTInfos.length);
+ foreach(i, ref ttInfo; ttInfos)
+ {
+ auto tempTTInfo = tempTTInfos[i];
+
+ if(gmtZone)
+ tempTTInfo.tt_gmtoff = -tempTTInfo.tt_gmtoff;
+
+ auto abbrevChars = tzAbbrevChars[tempTTInfo.tt_abbrind .. $];
+ string abbrev = abbrevChars[0 .. std.string.indexOf(abbrevChars, "\0")].idup;
+
+ ttInfo = new immutable(TTInfo)(tempTTInfos[i], abbrev);
+ }
+
+ auto tempTransitions = new TempTransition[](transitionTimeTs.length);
+ foreach(i, ref tempTransition; tempTransitions)
+ {
+ immutable ttiIndex = ttInfoIndices[i];
+ auto transitionTimeT = transitionTimeTs[i];
+ auto ttype = transitionTypes[ttiIndex];
+ auto ttInfo = ttInfos[ttiIndex];
+
+ tempTransition = TempTransition(transitionTimeT, ttInfo, ttype);
+ }
+
+ if(tempTransitions.empty)
+ {
+ _enforceValidTZFile(ttInfos.length == 1 && transitionTypes.length == 1);
+ tempTransitions ~= TempTransition(0, ttInfos[0], transitionTypes[0]);
+ }
+
+ sort!"a.timeT < b.timeT"(tempTransitions);
+ sort!"a.timeT < b.timeT"(leapSeconds);
+
+ auto transitions = new Transition[](tempTransitions.length);
+ foreach(i, ref transition; transitions)
+ {
+ auto tempTransition = tempTransitions[i];
+ auto transitionTimeT = tempTransition.timeT;
+ auto ttInfo = tempTransition.ttInfo;
+ auto ttype = tempTransition.ttype;
+
+ _enforceValidTZFile(i == 0 || transitionTimeT > tempTransitions[i - 1].timeT);
+
+ transition = Transition(transitionTimeT, ttInfo);
+ }
+
+ string stdName;
+ string dstName;
+ bool hasDST = false;
+
+ foreach(transition; retro(transitions))
+ {
+ auto ttInfo = transition.ttInfo;
+
+ if(ttInfo.isDST)
+ {
+ if(dstName.empty)
+ dstName = ttInfo.abbrev;
+
+ hasDST = true;
+ }
+ else
+ {
+ if(stdName.empty)
+ stdName = ttInfo.abbrev;
+ }
+
+ if(!stdName.empty && !dstName.empty)
+ break;
+ }
+
+ return new PosixTimeZone(transitions.idup, leapSeconds.idup, name, stdName, dstName, hasDST);
+ }
+ catch(DateTimeException dte)
+ throw dte;
+ catch(Exception e)
+ throw new DateTimeException("Not a valid TZ data file", __FILE__, __LINE__, e);
+ }
+
+
+ //Since reading in the time zone files could be expensive, most unit tests
+ //are consolidated into this one unittest block which minimizes how often it
+ //reads a time zone file.
+ unittest
+ {
+ version(Posix)
+ {
+ scope(exit) clearTZEnvVar();
+
+ //Test for "America/Los_Angeles".
+ {
+ //Verify Example for getTimeZone().
+ auto tz = PosixTimeZone.getTimeZone("America/Los_Angeles");
+
+ assert(tz.name == "America/Los_Angeles");
+ assert(tz.stdName == "PST");
+ assert(tz.dstName == "PDT");
+ assert(tz.hasDST);
+
+ //Continue testing passed example.
+ auto std = SysTime(DateTime(2010, 1, 1, 12, 0, 0), tz);
+ auto dst = SysTime(DateTime(2010, 7, 1, 12, 0, 0), tz);
+
+ assert(!std.dstInEffect);
+ assert(dst.dstInEffect);
+
+ setTZEnvVar("America/Los_Angeles");
+ {
+ time_t unixTime = std.toUnixTime();
+ tm* osTimeInfo = localtime(&unixTime);
+ tm ourTimeInfo = std.toTM();
+
+ assertPred!"=="(ourTimeInfo.tm_sec, osTimeInfo.tm_sec);
+ assertPred!"=="(ourTimeInfo.tm_min, osTimeInfo.tm_min);
+ assertPred!"=="(ourTimeInfo.tm_hour, osTimeInfo.tm_hour);
+ assertPred!"=="(ourTimeInfo.tm_min, osTimeInfo.tm_min);
+ assertPred!"=="(ourTimeInfo.tm_mday, osTimeInfo.tm_mday);
+ assertPred!"=="(ourTimeInfo.tm_mon, osTimeInfo.tm_mon);
+ assertPred!"=="(ourTimeInfo.tm_year, osTimeInfo.tm_year);
+ assertPred!"=="(ourTimeInfo.tm_wday, osTimeInfo.tm_wday);
+ assertPred!"=="(ourTimeInfo.tm_yday, osTimeInfo.tm_yday);
+ assertPred!"=="(ourTimeInfo.tm_isdst, osTimeInfo.tm_isdst);
+ assertPred!"=="(ourTimeInfo.tm_gmtoff, osTimeInfo.tm_gmtoff);
+ assertPred!"=="(to!string(ourTimeInfo.tm_zone), to!string(osTimeInfo.tm_zone));
+ }
+
+ {
+ time_t unixTime = dst.toUnixTime();
+ tm* osTimeInfo = localtime(&unixTime);
+ tm ourTimeInfo = dst.toTM();
+
+ assertPred!"=="(ourTimeInfo.tm_sec, osTimeInfo.tm_sec);
+ assertPred!"=="(ourTimeInfo.tm_min, osTimeInfo.tm_min);
+ assertPred!"=="(ourTimeInfo.tm_hour, osTimeInfo.tm_hour);
+ assertPred!"=="(ourTimeInfo.tm_min, osTimeInfo.tm_min);
+ assertPred!"=="(ourTimeInfo.tm_mday, osTimeInfo.tm_mday);
+ assertPred!"=="(ourTimeInfo.tm_mon, osTimeInfo.tm_mon);
+ assertPred!"=="(ourTimeInfo.tm_year, osTimeInfo.tm_year);
+ assertPred!"=="(ourTimeInfo.tm_wday, osTimeInfo.tm_wday);
+ assertPred!"=="(ourTimeInfo.tm_yday, osTimeInfo.tm_yday);
+ assertPred!"=="(ourTimeInfo.tm_isdst, osTimeInfo.tm_isdst);
+ assertPred!"=="(ourTimeInfo.tm_gmtoff, osTimeInfo.tm_gmtoff);
+ assertPred!"=="(to!string(ourTimeInfo.tm_zone), to!string(osTimeInfo.tm_zone));
+ }
+
+ auto leapTZ = PosixTimeZone.getTimeZone("right/America/Los_Angeles");
+
+ assert(leapTZ.name == "right/America/Los_Angeles");
+ assert(leapTZ.stdName == "PST");
+ assert(leapTZ.dstName == "PDT");
+ assert(leapTZ.hasDST);
+
+ auto leapSTD = SysTime(std.stdTime, leapTZ);
+ auto leapDST = SysTime(dst.stdTime, leapTZ);
+
+ assert(!leapSTD.dstInEffect);
+ assert(leapDST.dstInEffect);
+
+ assertPred!"=="(leapSTD.stdTime, std.stdTime);
+ assertPred!"=="(leapDST.stdTime, dst.stdTime);
+
+ assertPred!"=="(leapSTD.adjTime - convert!("seconds", "hnsecs")(24), std.adjTime);
+ assertPred!"=="(leapDST.adjTime - convert!("seconds", "hnsecs")(24), dst.adjTime);
+ }
+
+ //Test for "Europe/Paris".
+ {
+ auto tz = PosixTimeZone.getTimeZone("Europe/Paris");
+
+ assertPred!"=="(tz.name, "Europe/Paris");
+ assertPred!"=="(tz.stdName, "CET");
+ assertPred!"=="(tz.dstName, "CEST");
+ assertPred!"=="(tz.hasDST, true);
+
+ auto std = SysTime(DateTime(2010, 1, 1, 12, 0, 0), tz);
+ auto dst = SysTime(DateTime(2010, 7, 1, 12, 0, 0), tz);
+
+ assert(!std.dstInEffect);
+ assert(dst.dstInEffect);
+
+ setTZEnvVar("Europe/Paris");
+ {
+ time_t unixTime = std.toUnixTime();
+ tm* osTimeInfo = localtime(&unixTime);
+ tm ourTimeInfo = std.toTM();
+
+ assertPred!"=="(ourTimeInfo.tm_sec, osTimeInfo.tm_sec);
+ assertPred!"=="(ourTimeInfo.tm_min, osTimeInfo.tm_min);
+ assertPred!"=="(ourTimeInfo.tm_hour, osTimeInfo.tm_hour);
+ assertPred!"=="(ourTimeInfo.tm_min, osTimeInfo.tm_min);
+ assertPred!"=="(ourTimeInfo.tm_mday, osTimeInfo.tm_mday);
+ assertPred!"=="(ourTimeInfo.tm_mon, osTimeInfo.tm_mon);
+ assertPred!"=="(ourTimeInfo.tm_year, osTimeInfo.tm_year);
+ assertPred!"=="(ourTimeInfo.tm_wday, osTimeInfo.tm_wday);
+ assertPred!"=="(ourTimeInfo.tm_yday, osTimeInfo.tm_yday);
+ assertPred!"=="(ourTimeInfo.tm_isdst, osTimeInfo.tm_isdst);
+ assertPred!"=="(ourTimeInfo.tm_gmtoff, osTimeInfo.tm_gmtoff);
+ assertPred!"=="(to!string(ourTimeInfo.tm_zone), to!string(osTimeInfo.tm_zone));
+ }
+
+ {
+ time_t unixTime = dst.toUnixTime();
+ tm* osTimeInfo = localtime(&unixTime);
+ tm ourTimeInfo = dst.toTM();
+
+ assertPred!"=="(ourTimeInfo.tm_sec, osTimeInfo.tm_sec);
+ assertPred!"=="(ourTimeInfo.tm_min, osTimeInfo.tm_min);
+ assertPred!"=="(ourTimeInfo.tm_hour, osTimeInfo.tm_hour);
+ assertPred!"=="(ourTimeInfo.tm_min, osTimeInfo.tm_min);
+ assertPred!"=="(ourTimeInfo.tm_mday, osTimeInfo.tm_mday);
+ assertPred!"=="(ourTimeInfo.tm_mon, osTimeInfo.tm_mon);
+ assertPred!"=="(ourTimeInfo.tm_year, osTimeInfo.tm_year);
+ assertPred!"=="(ourTimeInfo.tm_wday, osTimeInfo.tm_wday);
+ assertPred!"=="(ourTimeInfo.tm_yday, osTimeInfo.tm_yday);
+ assertPred!"=="(ourTimeInfo.tm_isdst, osTimeInfo.tm_isdst);
+ assertPred!"=="(ourTimeInfo.tm_gmtoff, osTimeInfo.tm_gmtoff);
+ assertPred!"=="(to!string(ourTimeInfo.tm_zone), to!string(osTimeInfo.tm_zone));
+ }
+
+ auto leapTZ = PosixTimeZone.getTimeZone("right/Europe/Paris");
+
+ assert(leapTZ.name == "right/Europe/Paris");
+ assert(leapTZ.stdName == "CET");
+ assert(leapTZ.dstName == "CEST");
+ assert(leapTZ.hasDST);
+
+ auto leapSTD = SysTime(std.stdTime, leapTZ);
+ auto leapDST = SysTime(dst.stdTime, leapTZ);
+
+ assert(!leapSTD.dstInEffect);
+ assert(leapDST.dstInEffect);
+
+ assertPred!"=="(leapSTD.stdTime, std.stdTime);
+ assertPred!"=="(leapDST.stdTime, dst.stdTime);
+
+ assertPred!"=="(leapSTD.adjTime - convert!("seconds", "hnsecs")(24), std.adjTime);
+ assertPred!"=="(leapDST.adjTime - convert!("seconds", "hnsecs")(24), dst.adjTime);
+ }
+
+ //Test for "UTC".
+ {
+ auto tz = PosixTimeZone.getTimeZone("UTC");
+
+ assertPred!"=="(tz.name, "UTC");
+ assertPred!"=="(tz.stdName, "UTC");
+ assertPred!"=="(tz.dstName, "UTC");
+ assertPred!"=="(tz.hasDST, false);
+
+ auto std = SysTime(DateTime(2010, 1, 1, 12, 0, 0), tz);
+ auto dst = SysTime(DateTime(2010, 7, 1, 12, 0, 0), tz);
+
+ assert(!std.dstInEffect);
+ assert(!dst.dstInEffect);
+
+ setTZEnvVar("UTC");
+ {
+ time_t unixTime = std.toUnixTime();
+ tm* osTimeInfo = localtime(&unixTime);
+ tm ourTimeInfo = std.toTM();
+
+ assertPred!"=="(ourTimeInfo.tm_sec, osTimeInfo.tm_sec);
+ assertPred!"=="(ourTimeInfo.tm_min, osTimeInfo.tm_min);
+ assertPred!"=="(ourTimeInfo.tm_hour, osTimeInfo.tm_hour);
+ assertPred!"=="(ourTimeInfo.tm_min, osTimeInfo.tm_min);
+ assertPred!"=="(ourTimeInfo.tm_mday, osTimeInfo.tm_mday);
+ assertPred!"=="(ourTimeInfo.tm_mon, osTimeInfo.tm_mon);
+ assertPred!"=="(ourTimeInfo.tm_year, osTimeInfo.tm_year);
+ assertPred!"=="(ourTimeInfo.tm_wday, osTimeInfo.tm_wday);
+ assertPred!"=="(ourTimeInfo.tm_yday, osTimeInfo.tm_yday);
+ assertPred!"=="(ourTimeInfo.tm_isdst, osTimeInfo.tm_isdst);
+ assertPred!"=="(ourTimeInfo.tm_gmtoff, osTimeInfo.tm_gmtoff);
+ assertPred!"=="(to!string(ourTimeInfo.tm_zone), to!string(osTimeInfo.tm_zone));
+ }
+
+ {
+ time_t unixTime = dst.toUnixTime();
+ tm* osTimeInfo = localtime(&unixTime);
+ tm ourTimeInfo = dst.toTM();
+
+ assertPred!"=="(ourTimeInfo.tm_sec, osTimeInfo.tm_sec);
+ assertPred!"=="(ourTimeInfo.tm_min, osTimeInfo.tm_min);
+ assertPred!"=="(ourTimeInfo.tm_hour, osTimeInfo.tm_hour);
+ assertPred!"=="(ourTimeInfo.tm_min, osTimeInfo.tm_min);
+ assertPred!"=="(ourTimeInfo.tm_mday, osTimeInfo.tm_mday);
+ assertPred!"=="(ourTimeInfo.tm_mon, osTimeInfo.tm_mon);
+ assertPred!"=="(ourTimeInfo.tm_year, osTimeInfo.tm_year);
+ assertPred!"=="(ourTimeInfo.tm_wday, osTimeInfo.tm_wday);
+ assertPred!"=="(ourTimeInfo.tm_yday, osTimeInfo.tm_yday);
+ assertPred!"=="(ourTimeInfo.tm_isdst, osTimeInfo.tm_isdst);
+ assertPred!"=="(ourTimeInfo.tm_gmtoff, osTimeInfo.tm_gmtoff);
+ assertPred!"=="(to!string(ourTimeInfo.tm_zone), to!string(osTimeInfo.tm_zone));
+ }
+
+ auto leapTZ = PosixTimeZone.getTimeZone("right/UTC");
+
+ assert(leapTZ.name == "right/UTC");
+ assert(leapTZ.stdName == "UTC");
+ assert(leapTZ.dstName == "UTC");
+ assert(!leapTZ.hasDST);
+
+ auto leapSTD = SysTime(std.stdTime, leapTZ);
+ auto leapDST = SysTime(dst.stdTime, leapTZ);
+
+ assert(!leapSTD.dstInEffect);
+ assert(!leapDST.dstInEffect);
+
+ assertPred!"=="(leapSTD.stdTime, std.stdTime);
+ assertPred!"=="(leapDST.stdTime, dst.stdTime);
+
+ assertPred!"=="(leapSTD.adjTime - convert!("seconds", "hnsecs")(24), std.adjTime);
+ assertPred!"=="(leapDST.adjTime - convert!("seconds", "hnsecs")(24), dst.adjTime);
+ }
+ }
+ }
+
+
+ /++
+ Returns a list of the names of the time zones installed on the system.
+
+ You can provide a sub-name to narrow down the list of time zones (which
+ will likely be in the thousands if you get them all). For example,
+ if you pass in "America" as the sub-name, then only the time zones which
+ begin with "America" will be returned.
+
+ Params:
+ subname = The first part of the time zones that you want.
+
+ Throws:
+ FileException if it fails to read from disk.
+ +/
+ static string[] getInstalledTZNames(string subname = "", string tzDatabaseDir = defaultTZDatabaseDir)
+ {
+ version(Posix)
+ subname = strip(subname);
+ else version(Windows)
+ subname = replace(strip(subname), "/", sep);
+
+ if(!tzDatabaseDir.endsWith(sep))
+ tzDatabaseDir ~= sep;
+
+ enforce(tzDatabaseDir.exists, new DateTimeException(format("Directory %s does not exist.", tzDatabaseDir)));
+ enforce(tzDatabaseDir.isdir, new DateTimeException(format("%s is not a directory.", tzDatabaseDir)));
+
+ auto timezones = appender!(string[])();
+
+ foreach(DirEntry dentry; dirEntries(tzDatabaseDir, SpanMode.depth))
+ {
+ if(dentry.isfile)
+ {
+ auto tzName = dentry.name[tzDatabaseDir.length .. $];
+
+ if(!tzName.getExt().empty())
+ continue;
+
+ if(!tzName.startsWith(subname))
+ continue;
+
+ timezones.put(tzName);
+ }
+ }
+
+ sort(timezones.data);
+
+ return timezones.data;
+ }
+
+ unittest
+ {
+ version(Posix)
+ {
+ static void testPTZSuccess(string tzName)
+ {
+ scope(failure) writefln("TZName which threw: %s", tzName);
+
+ PosixTimeZone.getTimeZone(tzName);
+ }
+
+ static void testPTZFailure(string tzName)
+ {
+ scope(success) writefln("TZName which was supposed to throw: %s", tzName);
+
+ PosixTimeZone.getTimeZone(tzName);
+ }
+
+ auto tzNames = getInstalledTZNames();
+
+ foreach(tzName; tzNames)
+ assertNotThrown!DateTimeException(testPTZSuccess(tzName));
+
+ foreach(DirEntry dentry; dirEntries(defaultTZDatabaseDir, SpanMode.depth))
+ {
+ if(dentry.isfile)
+ {
+ auto tzName = dentry.name[defaultTZDatabaseDir.length .. $];
+
+ if(!canFind(tzNames, tzName))
+ assertThrown!DateTimeException(testPTZFailure(tzName));
+ }
+ }
+ }
+ }
+
+
+private:
+
+ /++
+ Holds information on when a time transition occures (usually a
+ transition to or from DST) as well as a pointer to the
+ TTInfo which holds information on the utc offset passed the
+ transition.
+ +/
+ struct Transition
+ {
+ this(long timeT, immutable (TTInfo)* ttInfo)
+ {
+ this.timeT = timeT;
+ this.ttInfo = ttInfo;
+ }
+
+ long timeT;
+ immutable (TTInfo)* ttInfo;
+ }
+
+
+ /++
+ Holds information on when a leap second occurs.
+ +/
+ struct LeapSecond
+ {
+ this(long timeT, int total)
+ {
+ this.timeT = timeT;
+ this.total = total;
+ }
+
+ long timeT;
+ int total;
+ }
+
+ /++
+ Holds information on the utc offset after a transition as well as
+ whether DST is in effect after that transition.
+ +/
+ struct TTInfo
+ {
+ this(in TempTTInfo tempTTInfo, string abbrev) immutable
+ {
+ utcOffset = tempTTInfo.tt_gmtoff;
+ isDST = tempTTInfo.tt_isdst;
+ this.abbrev = abbrev;
+ }
+
+ immutable int utcOffset; /// Offset from UTC.
+ immutable bool isDST; /// Whether DST is in effect.
+ immutable string abbrev; /// The current abbreviation for the time zone.
+ }
+
+
+ /++
+ Struct used to hold information relating to TTInfo while organizing
+ the time zone information prior to putting it in its final form.
+ +/
+ struct TempTTInfo
+ {
+ this(int gmtOff, bool isDST, ubyte abbrInd)
+ {
+ tt_gmtoff = gmtOff;
+ tt_isdst = isDST;
+ tt_abbrind = abbrInd;
+ }
+
+ int tt_gmtoff;
+ bool tt_isdst;
+ ubyte tt_abbrind;
+ }
+
+
+ /++
+ Struct used to hold information relating to Transition while organizing
+ the time zone information prior to putting it in its final form.
+ +/
+ struct TempTransition
+ {
+ this(long timeT, immutable (TTInfo)* ttInfo, TransitionType* ttype)
+ {
+ this.timeT = timeT;
+ this.ttInfo = ttInfo;
+ this.ttype = ttype;
+ }
+
+ long timeT;
+ immutable (TTInfo)* ttInfo;
+ TransitionType* ttype;
+ }
+
+
+ /++
+ Struct used to hold information relating to Transition and TTInfo while
+ organizing the time zone information prior to putting it in its final form.
+ +/
+ struct TransitionType
+ {
+ this(bool isStd, bool inUTC)
+ {
+ this.isStd = isStd;
+ this.inUTC = inUTC;
+ }
+
+ bool isStd; /// Whether the transition is in std time (as opposed to wall clock time).
+ bool inUTC; /// Whether the transition is in UTC (as opposed to local time).
+ }
+
+
+ /++
+ Reads an int from a TZ file.
+ +/
+ static T readVal(T)(ref File tzFile)
+ if(is(T == int))
+ {
+ T[1] buff;
+
+ _enforceValidTZFile(!tzFile.eof());
+ tzFile.rawRead(buff);
+
+ return cast(int)ntohl(buff[0]);
+ }
+
+
+ /++
+ Reads a long from a TZ file.
+ +/
+ static T readVal(T)(ref File tzFile)
+ if(is(T == long))
+ {
+ T[1] buff;
+
+ _enforceValidTZFile(!tzFile.eof());
+ tzFile.rawRead(buff);
+
+ return cast(long)ntoh64(buff[0]);
+ }
+
+ /++
+ Reads an array of values from a TZ file.
+ +/
+ static T readVal(T)(ref File tzFile, size_t length)
+ if(isArray!T)
+ {
+ auto buff = new T(length);
+
+ _enforceValidTZFile(!tzFile.eof());
+ tzFile.rawRead(buff);
+
+ return buff;
+ }
+
+
+ /++
+ Reads a TempTTInfo from a TZ file.
+ +/
+ static T readVal(T)(ref File tzFile)
+ if(is(T == TempTTInfo))
+ {
+ return TempTTInfo(readVal!int(tzFile),
+ readVal!bool(tzFile),
+ readVal!ubyte(tzFile));
+ }
+
+
+ /++
+ Reads a value from a TZ file.
+ +/
+ static T readVal(T)(ref File tzFile)
+ if(!is(T == int) &&
+ !is(T == long) &&
+ !is(T == char[]) &&
+ !is(T == TempTTInfo))
+ {
+ T[1] buff;
+
+ _enforceValidTZFile(!tzFile.eof());
+ tzFile.rawRead(buff);
+
+ return buff[0];
+ }
+
+ /++
+ 64 bit version of ntoh. Unfortunately, for some reason, most systems
+ provide only 16 and 32 bit versions of this, so we need to provide it
+ ourselves. We really should declare a version of this in core somewhere.
+ +/
+ static ulong ntoh64(ulong val)
+ {
+ static if(endian == Endian.LittleEndian)
+ return endianSwap64(val);
+ else
+ return val;
+ }
+
+
+ /++
+ Swaps the endianness of a 64-bit value. We really should declare a
+ version of this in core somewhere.
+ +/
+ static ulong endianSwap64(ulong val)
+ {
+ return ((val & 0xff00000000000000UL) >> 56) |
+ ((val & 0x00ff000000000000UL) >> 40) |
+ ((val & 0x0000ff0000000000UL) >> 24) |
+ ((val & 0x000000ff00000000UL) >> 8) |
+ ((val & 0x00000000ff000000UL) << 8) |
+ ((val & 0x0000000000ff0000UL) << 24) |
+ ((val & 0x000000000000ff00UL) << 40) |
+ ((val & 0x00000000000000ffUL) << 56);
+ }
+
+
+ /++
+ Throws:
+ DateTimeException if $(D result) is false.
+ +/
+ static void _enforceValidTZFile(bool result, size_t line = __LINE__)
+ {
+ if(!result)
+ throw new DateTimeException("Not a valid tzdata file.", __FILE__, line);
+ }
+
+
+ int calculateLeapSeconds(long stdTime) const nothrow
+ {
+ try
+ {
+ if(_leapSeconds.empty)
+ return 0;
+
+ immutable unixTime = stdTimeToUnixTime(stdTime);
+
+ if(_leapSeconds.front.timeT >= unixTime)
+ return 0;
+
+ //Okay, casting is a hack, but indexOf shouldn't be changing it, and it would be
+ //too inefficient to have to keep duping it every time we have to calculate the time.
+ //Hopefully, indexOf will properly support immutable ranges at some point.
+ auto found = std.algorithm.indexOf!"b < a.timeT"(cast(LeapSecond[])_leapSeconds, unixTime);
+
+ if(found == -1)
+ return _leapSeconds.back.total;
+
+ auto leapSecond = found == 0 ? _leapSeconds[0] : _leapSeconds[found - 1];
+
+ return leapSecond.total;
+ }
+ catch(Exception e)
+ assert(0, format("Nothing in calculateLeapSeconds() should be throwing. Caught Exception: %s", e));
+ }
+
+
+ this(immutable Transition[] transitions,
+ immutable LeapSecond[] leapSeconds,
+ string name,
+ string stdName,
+ string dstName,
+ bool hasDST) immutable
+ {
+ if(dstName.empty && !stdName.empty)
+ dstName = stdName;
+ else if(stdName.empty && !dstName.empty)
+ stdName = dstName;
+
+ super(name, stdName, dstName);
+
+ if(!transitions.empty)
+ {
+ foreach(i, transition; transitions[0 .. $-1])
+ _enforceValidTZFile(transition.timeT < transitions[i + 1].timeT);
+ }
+
+ foreach(i, leapSecond; leapSeconds)
+ _enforceValidTZFile(i == leapSeconds.length - 1 || leapSecond.timeT < leapSeconds[i + 1].timeT);
+
+ _transitions = transitions;
+ _leapSeconds = leapSeconds;
+ _hasDST = hasDST;
+ }
+
+
+ immutable Transition[] _transitions; /// List of times when the utc offset changes.
+ immutable LeapSecond[] _leapSeconds; /// List of leap second occurrences.
+ immutable bool _hasDST; /// Whether DST is in effect for this time zone at any point in time.
+}
+
+
+
+version(Windows)
+{
+
+//Should be in core.sys.windows.windows, but for some reason it isn't.
+extern(Windows)
+{
+export LONG RegQueryValueExA(HKEY hKey, LPCSTR name, LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count);
+
+struct REG_TZI_FORMAT
+{
+ LONG Bias;
+ LONG StandardBias;
+ LONG DaylightBias;
+ SYSTEMTIME StandardDate;
+ SYSTEMTIME DaylightDate;
+}
+
+}
+
+/++
+ Represents a time zone from the Windows registry. Unfortunately, Windows
+ does not use the TZ database, though it does name its time zones using the
+ TZ database names. You can, however, use PosixTimeZone (which reads its
+ information from the TZ database files on disk) on Windows if you provide
+ the TZ database files
+ ( Repository with the TZ database files (tzdata) )
+ yourself and tell $(D PosixTimeZone.getTimeZone()) where the directory
+ holding them is.
+
+ TZ database files hold DST transitions for a large interval of the time
+ covered by time_t. So, barring errors in the information in the TZ database
+ files, it will use the correct DST rules for any date. Windows, on the other
+ hand, maintains only the current DST rules, so historical dates will use
+ the current DST rules (and therefore potentially be incorrect). So, if you
+ want the DST rules that you use to be more accurate, or if you're looking for
+ your program to act consistently on both Posix and Windows systems, then, as
+ mentioned above, you'll need to include the TZ database files with your
+ program and give $(D PosixTimeZone.getTimeZone()) the directory on disk
+ where they are located.
+
+ However, if all you care about is whether current times use the correct DST
+ rules, or if you don't care whether the DST rules are historically accurate,
+ then you can just use WindowsTimeZone on Windows. WindowsTimeZone does not
+ exist on Posix systems.
+
+ To get a WindowsTimeZone, either call $(D WindowsTimeZone.getTimeZone()) or
+ call $(D TimeZone.getTimeZone()) (which will give you a PosixTimeZone on Posix
+ systems and a WindowsTimeZone on Windows systems).
+ +/
+final class WindowsTimeZone : TimeZone
+{
+public:
+
+ /++
+ Whether this time zone has Daylight Savings Time at any point in time. Note that for some time zone types
+ it may not have DST for current dates but will still return true for hasDST because the time zone did at some
+ point have DST.
+ +/
+ @property override bool hasDST() const nothrow
+ {
+ return _tzInfo.DaylightDate.wMonth != 0;
+ }
+
+
+ /++
+ Takes the number of hecto-nanoseconds (100 ns) since midnight, January
+ 1st, 1 A.D. in UTC time (i.e. std time) and returns whether DST is in
+ effect in this time zone at the given point in time.
+
+ Params:
+ stdTime = The UTC time that needs to be checked for DST in this time
+ zone.
+ +/
+ override bool dstInEffect(long stdTime) const nothrow
+ {
+ return _dstInEffect(&_tzInfo, stdTime);
+ }
+
+
+ /++
+ Takes the number of hecto-nanoseconds (100 ns) since midnight, January
+ 1st, 1 A.D. in UTC time (i.e. std time) and converts it to this time
+ zone's time.
+
+ Params:
+ stdTime = The UTC time that needs to be adjusted to this time zone's time.
+ +/
+ override long utcToTZ(long stdTime) const nothrow
+ {
+ return _utcToTZ(&_tzInfo, stdTime, hasDST);
+ }
+
+
+ /++
+ Takes the number of hecto-nanoseconds (100 ns) since midnight, January
+ 1st, 1 A.D. in this time zone's time and converts it to UTC
+ (i.e. std time).
+
+ Params:
+ adjTime = The time in this time zone that needs to be adjusted to
+ UTC time.
+ +/
+ override long tzToUTC(long adjTime) const nothrow
+ {
+ return _tzToUTC(&_tzInfo, adjTime, hasDST);
+ }
+
+
+ /++
+ Returns a TimeZone with the give name per the TZ database. The time zone
+ information is fetched from the Windows registry.
+
+ See_Also:
+ Wikipedia entry on TZ database
+ List of Time Zones
+
+ Params:
+ name = The TZ database name of the time zone that you're looking for.
+
+ Throws:
+ DateTimeException if the given time zone could not be found.
+
+ Examples:
+--------------------
+auto tz = TimeZone.getTimeZone("America/Los_Angeles");
+--------------------
+ +/
+ static immutable(WindowsTimeZone) getTimeZone(string name)
+ {
+ auto keyStr = "Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\0";
+ HKEY baseKey;
+
+ {
+ auto result = RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyStr.ptr, 0, KEY_READ, &baseKey);
+ if(result != ERROR_SUCCESS)
+ throw new DateTimeException(format("Failed to open registry. Error: %s", result));
+ }
+ scope(exit) RegCloseKey(baseKey);
+
+ char[1024] keyName;
+ auto nameLen = keyName.length;
+ int result;
+ for(DWORD index = 0;
+ (result = RegEnumKeyExA(baseKey, index, keyName.ptr, &nameLen, null, null, null, null)) != ERROR_NO_MORE_ITEMS;
+ ++index, nameLen = keyName.length)
+ {
+ if(result == ERROR_SUCCESS)
+ {
+ HKEY tzKey;
+ if(RegOpenKeyExA(baseKey, keyName.ptr, 0, KEY_READ, &tzKey) == ERROR_SUCCESS)
+ {
+ scope(exit) RegCloseKey(tzKey);
+ char[1024] strVal;
+ auto strValLen = strVal.length;
+
+ bool queryStringValue(string name, size_t lineNum = __LINE__)
+ {
+ strValLen = strVal.length;
+
+ return RegQueryValueExA(tzKey, name.ptr, null, null, cast(ubyte*)strVal.ptr, &strValLen) == ERROR_SUCCESS;
+ }
+
+ if(queryStringValue("Display\0"))
+ {
+ auto displayName = to!string(strVal.ptr);
+
+ if(displayName == name)
+ {
+ if(queryStringValue("Std\0"))
+ {
+ //Cannot use to!wstring(char*), probably due to bug http://d.puremagic.com/issues/show_bug.cgi?id=5016
+ static wstring conv(char* cstr, size_t strValLen)
+ {
+ cstr[strValLen - 1] = '\0';
+
+ string retval;
+
+ for(;; ++cstr)
+ {
+ if(*cstr == '\0')
+ break;
+
+ retval ~= *cstr;
+ }
+
+ return to!wstring(retval);
+ }
+
+ //auto stdName = to!wstring(strVal.ptr);
+ auto stdName = conv(strVal.ptr, strValLen);
+
+ if(queryStringValue("Dlt\0"))
+ {
+ //auto dstName = to!wstring(strVal.ptr);
+ auto dstName = conv(strVal.ptr, strValLen);
+
+ enum tzi = "TZI\0";
+ REG_TZI_FORMAT binVal;
+ auto binValLen = REG_TZI_FORMAT.sizeof;
+
+ if(RegQueryValueExA(tzKey, tzi.ptr, null, null, cast(ubyte*)&binVal, &binValLen) == ERROR_SUCCESS)
+ {
+ TIME_ZONE_INFORMATION tzInfo;
+
+ auto stdNameLen = stdName.length > 32 ? 32 : stdName.length;
+ auto dstNameLen = dstName.length > 32 ? 32 : dstName.length;
+
+ tzInfo.Bias = binVal.Bias;
+ tzInfo.StandardName[0 .. stdNameLen] = stdName[0 .. stdNameLen];
+ tzInfo.StandardName[stdNameLen .. $] = '\0';
+ tzInfo.StandardDate = binVal.StandardDate;
+ tzInfo.StandardBias = binVal.StandardBias;
+ tzInfo.DaylightName[0 .. dstNameLen] = dstName[0 .. dstNameLen];
+ tzInfo.DaylightName[dstNameLen .. $] = '\0';
+ tzInfo.DaylightDate = binVal.DaylightDate;
+ tzInfo.DaylightBias = binVal.DaylightBias;
+
+ return new WindowsTimeZone(name, tzInfo);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ throw new DateTimeException(format("Failed to find time zone: %s", name));
+ }
+
+ unittest
+ {
+ //Verify Example.
+ auto tz = TimeZone.getTimeZone("America/Los_Angeles");
+ }
+
+
+ /++
+ Returns a list of the names of the time zones installed on the system.
+
+ You can provide a sub-name to narrow down the list of time zones (which
+ will likely be in the thousands if you get them all). For example,
+ if you pass in "America" as the sub-name, then only the time zones which
+ begin with "America" will be returned.
+
+ Params:
+ subname = The first part of the time zones that you want.
+
+ Throws:
+ DateTimeException if it fails to read the registry.
+ +/
+ static string[] getInstalledTZNames(string subname = "")
+ {
+ auto timezones = appender!(string[])();
+
+ auto keyStr = "Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\0";
+ HKEY baseKey;
+
+ {
+ auto result = RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyStr.ptr, 0, KEY_READ, &baseKey);
+ if(result != ERROR_SUCCESS)
+ throw new DateTimeException(format("Failed to open registry. Error: %s", result));
+ }
+ scope(exit) RegCloseKey(baseKey);
+
+ char[1024] keyName;
+ auto nameLen = keyName.length;
+ int result;
+ for(DWORD index = 0;
+ (result = RegEnumKeyExA(baseKey, index, keyName.ptr, &nameLen, null, null, null, null)) != ERROR_NO_MORE_ITEMS;
+ ++index, nameLen = keyName.length)
+ {
+ if(result == ERROR_SUCCESS)
+ {
+ HKEY tzKey;
+ if(RegOpenKeyExA(baseKey, keyName.ptr, 0, KEY_READ, &tzKey) == ERROR_SUCCESS)
+ {
+ scope(exit) RegCloseKey(tzKey);
+ char[1024] strVal;
+ auto strValLen = strVal.length;
+
+ bool queryStringValue(string name, size_t lineNum = __LINE__)
+ {
+ strValLen = strVal.length;
+
+ return RegQueryValueExA(tzKey, name.ptr, null, null, cast(ubyte*)strVal.ptr, &strValLen) == ERROR_SUCCESS;
+ }
+
+ if(queryStringValue("Display\0"))
+ {
+ auto displayName = to!string(strVal.ptr);
+
+ if(displayName.startsWith(subname))
+ timezones.put(displayName);
+ }
+ }
+ }
+ }
+
+ sort(timezones.data);
+
+ return timezones.data;
+ }
+
+ unittest
+ {
+ WindowsTimeZone.getInstalledTZNames();
+ }
+
+
+private:
+
+ static bool _dstInEffect(const TIME_ZONE_INFORMATION* tzInfo, long stdTime) nothrow
+ {
+ try
+ {
+ if(tzInfo.DaylightDate.wMonth == 0)
+ return false;
+
+ auto utcDateTime = cast(DateTime)SysTime(stdTime, UTC());
+
+ //The limits of what SystemTimeToTZSpecificLocalTime() will accept.
+ if(utcDateTime.year < 1601)
+ {
+ if(utcDateTime.month == Month.feb && utcDateTime.day == 29)
+ utcDateTime.day = 28;
+
+ utcDateTime.year = 1601;
+ }
+ else if(utcDateTime.year > 30_827)
+ {
+ if(utcDateTime.month == Month.feb && utcDateTime.day == 29)
+ utcDateTime.day = 28;
+
+ utcDateTime.year = 30_827;
+ }
+
+ //SystemTimeToTZSpecificLocalTime() doesn't act correctly at the beginning
+ //or end of the year (bleh). Unless some bizarre time zone changes
+ //DST on January 1st or December 31st, this should fix the problem.
+ if(utcDateTime.month == Month.jan)
+ {
+ if(utcDateTime.day == 1)
+ utcDateTime.day = 2;
+ }
+ else if(utcDateTime.month == Month.dec && utcDateTime.day == 31)
+ utcDateTime.day = 30;
+
+ SYSTEMTIME utcTime = void;
+ SYSTEMTIME otherTime = void;
+
+ utcTime.wYear = utcDateTime.year;
+ utcTime.wMonth = utcDateTime.month;
+ utcTime.wDay = utcDateTime.day;
+ utcTime.wHour = utcDateTime.hour;
+ utcTime.wMinute = utcDateTime.minute;
+ utcTime.wSecond = utcDateTime.second;
+
+ SystemTimeToTzSpecificLocalTime(cast(TIME_ZONE_INFORMATION*)tzInfo, &utcTime, &otherTime);
+
+ immutable otherDateTime = DateTime(otherTime.wYear,
+ otherTime.wMonth,
+ otherTime.wDay,
+ otherTime.wHour,
+ otherTime.wMinute,
+ otherTime.wSecond);
+ immutable diff = utcDateTime - otherDateTime;
+ immutable minutes = diff.total!"minutes"() - tzInfo.Bias;
+
+ if(minutes == tzInfo.DaylightBias)
+ return true;
+
+ assert(minutes == tzInfo.StandardBias);
+
+ return false;
+ }
+ catch(Exception e)
+ assert(0, e.toString());
+ //assert(0, "DateTime's constructor threw.");
+ }
+
+ unittest
+ {
+ TIME_ZONE_INFORMATION tzInfo;
+ GetTimeZoneInformation(&tzInfo);
+
+ WindowsTimeZone._dstInEffect(&tzInfo, SysTime(DateTime(1600, 1, 1)).stdTime);
+ WindowsTimeZone._dstInEffect(&tzInfo, SysTime(DateTime(1601, 1, 1)).stdTime);
+ WindowsTimeZone._dstInEffect(&tzInfo, SysTime(DateTime(30_827, 1, 1)).stdTime);
+ WindowsTimeZone._dstInEffect(&tzInfo, SysTime(DateTime(30_828, 1, 1)).stdTime);
+ }
+
+
+ static long _utcToTZ(const TIME_ZONE_INFORMATION* tzInfo, long stdTime, bool hasDST) nothrow
+ {
+ if(hasDST && WindowsTimeZone._dstInEffect(tzInfo, stdTime))
+ return stdTime - convert!("minutes", "hnsecs")(tzInfo.Bias + tzInfo.DaylightBias);
+
+ return stdTime - convert!("minutes", "hnsecs")(tzInfo.Bias + tzInfo.StandardBias);
+ }
+
+
+ static long _tzToUTC(const TIME_ZONE_INFORMATION* tzInfo, long adjTime, bool hasDST) nothrow
+ {
+ if(hasDST)
+ {
+ try
+ {
+ auto localTime = cast(DateTime)SysTime(adjTime, UTC());
+
+ DateTime getTransitionTime(const ref SYSTEMTIME transition)
+ {
+ DateTime switchDate;
+
+ if(transition.wYear == 0)
+ switchDate.year = localTime.year;
+ else
+ switchDate.year = transition.wYear;
+
+ switchDate.month = cast(Month)transition.wMonth;
+
+ DayOfWeek dow = cast(DayOfWeek)transition.wDayOfWeek;
+ int occurrence = transition.wDay;
+
+ if(occurrence < 5)
+ {
+ Date date = localTime.date;
+
+ date.day = 1;
+ date.day = cast(int)(date.day + daysToDayOfWeek(date.dayOfWeek, dow) + convert!("weeks", "days")(occurrence - 1));
+ switchDate.day = date.day;
+ }
+ else
+ {
+ Date date = localTime.date.endOfMonth;
+
+ switchDate.day = date.day - daysToDayOfWeek(dow, date.dayOfWeek);
+ }
+
+ switchDate.hour = transition.wHour;
+ switchDate.minute = transition.wMinute;
+
+ return switchDate;
+ }
+
+ auto stdSwitch = getTransitionTime(tzInfo.StandardDate);
+ auto dstSwitch = getTransitionTime(tzInfo.DaylightDate);
+
+ bool isDST = false;
+
+ if(localTime < stdSwitch)
+ isDST = localTime < dstSwitch ? stdSwitch < dstSwitch : true;
+ else
+ isDST = localTime < dstSwitch ? false : dstSwitch > stdSwitch;
+
+ if(isDST)
+ return adjTime + convert!("minutes", "hnsecs")(tzInfo.Bias + tzInfo.DaylightBias);
+ }
+ catch(Exception e)
+ assert(0, "SysTime's constructor threw.");
+ }
+
+ return adjTime + convert!("minutes", "hnsecs")(tzInfo.Bias + tzInfo.StandardBias);
+ }
+
+
+ this(string name, TIME_ZONE_INFORMATION tzInfo) immutable
+ {
+ //Cannot use to!string(wchar*), probably due to bug http://d.puremagic.com/issues/show_bug.cgi?id=5016
+ static string conv(wchar* wcstr)
+ {
+ wcstr[31] = '\0';
+ wstring retval;
+
+ for(;; ++wcstr)
+ {
+ if(*wcstr == '\0')
+ break;
+
+ retval ~= *wcstr;
+ }
+
+ return to!string(retval);
+ }
+
+ //super(name, to!string(tzInfo.StandardName.ptr), to!string(tzInfo.DaylightName.ptr));
+ super(name, conv(tzInfo.StandardName.ptr), conv(tzInfo.DaylightName.ptr));
+
+ _tzInfo = tzInfo;
+ }
+
+
+ TIME_ZONE_INFORMATION _tzInfo;
+}
+
+}
+else version(D_Ddoc)
+{
+
+/++
+ Represents a time zone from the Windows registry. Unfortunately, Windows
+ does not use the TZ database, though it does name its time zones using the
+ TZ database names. You can, however, use PosixTimeZone (which reads its
+ information from the TZ database files on disk) on Windows if you provide
+ the TZ database files
+ ( Repository with the TZ database files (tzdata) )
+ yourself and tell $(D PosixTimeZone.getTimeZone()) where the directory
+ holding them is.
+
+ TZ database files hold DST transitions for a large interval of the time
+ covered by time_t. So, barring errors in the information in the TZ database
+ files, it will use the correct DST rules for any date. Windows, on the other
+ hand, maintains only the current DST rules, so historical dates will use
+ the current DST rules (and therefore potentially be incorrect). So, if you
+ want the DST rules that you use to be more accurate, or if you're looking for
+ your program to act consistently on both Posix and Windows systems, then, as
+ mentioned above, you'll need to include the TZ database files with your
+ program and give $(D PosixTimeZone.getTimeZone()) the directory on disk
+ where they are located.
+
+ However, if all you care about is whether current times use the correct DST
+ rules, or if you don't care whether the DST rules are historically accurate,
+ then you can just use WindowsTimeZone on Windows. WindowsTimeZone does not
+ exist on Posix systems.
+
+ To get a WindowsTimeZone, either call $(D WindowsTimeZone.getTimeZone()) or
+ call $(D TimeZone.getTimeZone()) (which will give you a PosixTimeZone on Posix
+ systems and a WindowsTimeZone on Windows systems).
+ +/
+final class WindowsTimeZone : TimeZone
+{
+public:
+
+ /++
+ Whether this time zone has Daylight Savings Time at any point in time.
+ Note that for some time zone types it may not have DST for current dates
+ but will still return true for hasDST because the time zone did at some
+ point have DST.
+ +/
+ @property override bool hasDST() const nothrow
+ {
+ assert(0, "No implementation. Function exists only for DDoc generation");
+ }
+
+
+ /++
+ Takes the number of hecto-nanoseconds (100 ns) since midnight, January
+ 1st, 1 A.D. in UTC time (i.e. std time) and returns whether DST is in
+ effect in this time zone at the given point in time.
+
+ Params:
+ stdTime = The UTC time that needs to be checked for DST in this
+ time zone.
+ +/
+ override bool dstInEffect(long stdTime) const nothrow
+ {
+ assert(0, "No implementation. Function exists only for DDoc generation");
+ }
+
+
+ /++
+ Takes the number of hecto-nanoseconds (100 ns) since midnight, January
+ 1st, 1 A.D. in UTC time (i.e. std time) and converts it to this time
+ zone's time.
+
+ Params:
+ stdTime = The UTC time that needs to be adjusted to this time zone's time.
+ +/
+ override long utcToTZ(long stdTime) const nothrow
+ {
+ assert(0, "No implementation. Function exists only for DDoc generation");
+ }
+
+
+ /++
+ Takes the number of hecto-nanoseconds (100 ns) since midnight, January
+ 1st, 1 A.D. in this time zone's time and converts it to UTC
+ (i.e. std time).
+
+ Params:
+ adjTime = The time in this time zone that needs to be adjusted to UTC time.
+ +/
+ override long tzToUTC(long adjTime) const nothrow
+ {
+ assert(0, "No implementation. Function exists only for DDoc generation");
+ }
+
+
+ /++
+ Returns a TimeZone with the give name per the TZ database. The time zone
+ information is fetched from the Windows registry.
+
+ See_Also:
+ Wikipedia entry on TZ database
+ List of Time Zones
+
+ Params:
+ name = The TZ database name of the time zone that you're looking for.
+
+ Throws:
+ DateTimeException if the given time zone could not be found.
+
+ Examples:
+--------------------
+auto tz = TimeZone.getTimeZone("America/Los_Angeles");
+--------------------
+ +/
+ static immutable(WindowsTimeZone) getTimeZone(string name)
+ {
+ assert(0, "No implementation. Function exists only for DDoc generation");
+ }
+
+
+ /++
+ Returns a list of the names of the time zones installed on the system.
+
+ You can provide a sub-name to narrow down the list of time zones (which
+ will likely be in the thousands if you get them all). For example,
+ if you pass in "America" as the sub-name, then only the time zones which
+ begin with "America" will be returned.
+
+ Params:
+ subname = The first part of the time zones that you want.
+ +/
+ static string[] getInstalledTZNames(string subname = "")
+ {
+ assert(0, "No implementation. Function exists only for DDoc generation");
+ }
+
+
+private:
+
+ this() immutable pure
+ {
+ super("", "", "");
+ assert(0, "No implementation. Function exists only for DDoc generation");
+ }
+}
+
+}
+
+
+version(Posix)
+{
+ /++
+ Allows you to set the local time zone on Posix systems with the TZ
+ database name by setting the TZ environment variable.
+
+ Unfortunately, there is no way to do it on Windows using the TZ
+ database name, so this function only exists on Posix systems.
+ +/
+ void setTZEnvVar(string tzDatabaseName) nothrow
+ {
+ try
+ {
+ char[] env = to!(char[])("TZ=:" ~ PosixTimeZone.defaultTZDatabaseDir ~ tzDatabaseName ~ "\0");
+
+ putenv(env.ptr);
+ tzset();
+ }
+ catch(Exception e)
+ assert(0, "to!(char[]) threw when it shouldn't have.");
+ }
+
+
+ /++
+ Clears the TZ environment variable.
+
+ Only on Posix.
+ +/
+ void clearTZEnvVar() nothrow
+ {
+ try
+ {
+ char[] env = to!(char[])("TZ\0");
+
+ unsetenv(env.ptr);
+ tzset();
+ }
+ catch(Exception e)
+ assert(0, "to!(char[]) threw when it shouldn't have.");
+ }
+}
+else version(D_Ddoc)
+{
+ /++
+ Allows you to set the local time zone on Posix systems with the TZ
+ database name by setting the TZ environment variable.
+
+ Unfortunately, there is no way to do it on Windows using the TZ
+ database name, so this function only exists on Posix systems.
+ +/
+ void setTZEnvVar(string tzDatabaseName)
+ {
+ assert(0, "No implementation. Function exists only for DDoc generation");
+ }
+
+
+ /++
+ Clears the TZ environment variable.
+
+ Only on Posix.
+ +/
+ void clearTZEnvVar()
+ {
+ assert(0, "No implementation. Function exists only for DDoc generation");
+ }
+}
+
+
+//==============================================================================
+// Section with StopWatch and Benchmark Code.
+//==============================================================================
+
+/++
+ StopWatch's AutoStart flag
+ +/
enum autoStart = AutoStart.yes;
-/*******************************************************************************
- * StopWatch measures time highly precise as possible.
- *
- * This class uses performance counter.
- * On Windows, This uses QueryPerformanceCounter.
- * For Posix, This uses clock_gettime if available, gettimeofday otherwise.
- *
- * But this has dispersion in accuracy by environment.
- * It is impossible to remove this dispersion. This depends on multi task
- * system for example overhead from change of the context switch of the thread.
- *
- * Usage is here:
- * Example:
- *------------------------------------------------------------------------------
- *void foo() {
- * StopWatch sw;
- * static immutable N = 100;
- * Ticks[N] times;
- * Ticks last = Ticks.fromSeconds(0);
- * foreach (i; 0..N) {
- * sw.start(); // start/resume mesuring.
- * foreach (Unused; 0..1000000) bar();
- * sw.stop(); // stop/pause mesuring.
- * // Return value of peek() after having stopped are the always same.
- * writeln((i+1)*1000000, " times done, lap time: ",
- * sw.peek().msec, "[ms]");
- * times[i] = sw.peek() - last;
- * last = sw.peek();
- * }
- * real sum = 0;
- * // When you want to know the number of seconds of the fact,
- * // you can use properties of Ticks.
- * // (seconds, mseconds, useconds, interval)
- * foreach (e; times) sum += e.interval;
- * writeln("Average time: ", sum/N, "[s]");
- *}
- *------------------------------------------------------------------------------
- */
+/++
+ StopWatch measures time as precisely as possible.
+
+ This class uses a high-performance counter. On Windows systems, it uses
+ $(D QueryPerformanceCounter), and on Posix systems, it uses $(D clock_gettime())
+ if available, and $(D gettimeofday()) otherwise.
+
+ But the accuracy of StopWatch differs from system to system. It is impossible
+ to for it to be the same from system to system since the precision of the
+ system clock varies from system to system, and other system-dependent and
+ situation-dependent stuff (such as the overhead of a context switching between
+ threads) can also affect StopWatch's accuracy.
+
+ Examples:
+--------------------
+void foo() {
+ StopWatch sw;
+ static immutable N = 100;
+ TickDuration[N] times;
+ TickDuration last = TickDuration.from!"seconds"(0);
+ foreach (i; 0..N) {
+ sw.start(); // start/resume mesuring.
+ foreach (Unused; 0..1000000) bar();
+ sw.stop(); // stop/pause mesuring.
+ // Return value of peek() after having stopped are the always same.
+ writeln((i+1)*1000000, " times done, lap time: ",
+ sw.peek().msec, "[ms]");
+ times[i] = sw.peek() - last;
+ last = sw.peek();
+ }
+ real sum = 0;
+ // When you want to know the number of seconds of the fact,
+ // you can use properties of TickDuration.
+ // (seconds, mseconds, useconds, hnsecs)
+ foreach (e; times) sum += e.hnsecs;
+ writeln("Average time: ", sum/N, " hnsecs");
+}
+--------------------
+ +/
struct StopWatch
{
@safe:// @@@BUG@@@ workaround for bug 4211
@@ -505,20 +29490,20 @@ private:
bool m_FlagStarted = false;
- // Ticks at the time of StopWatch starting mesurement.
- Ticks m_TimeStart;
+ // TickDuration at the time of StopWatch starting measurement.
+ TickDuration m_TimeStart;
- // Ticks as total time of measurement.
- Ticks m_TimeMeasured;
+ // Total time that StopWatch ran.
+ TickDuration m_TimeMeasured;
public:
- /***************************************************************************
- * auto start with constructor
- */
+ /++
+ auto start with constructor
+ +/
this(AutoStart autostart)
{
if (autostart)
@@ -535,23 +29520,23 @@ public:
}
- /***************************************************************************
- * Reset the time measurement.
- */
+ /++
+ Reset the stop watch.
+ +/
@safe
void reset()
{
if (m_FlagStarted)
{
- // Set current systime if StopWatch is measuring.
- m_TimeStart = systime();
+ // Set current system time if StopWatch is measuring.
+ m_TimeStart = Clock.currSystemTick;
}
else
{
// Set zero if StopWatch is not measuring.
- m_TimeStart.value = 0;
+ m_TimeStart.length = 0;
}
- m_TimeMeasured.value = 0;
+ m_TimeMeasured.length = 0;
}
@@ -561,20 +29546,20 @@ public:
sw.start();
sw.stop();
sw.reset();
- assert(sw.peek().seconds == 0);
+ assert(sw.peek().to!("seconds", real) == 0);
}
- /***************************************************************************
- * Start the time measurement.
- */
+ /++
+ Start the stop watch.
+ +/
@safe
void start()
{
assert(!m_FlagStarted);
StopWatch sw;
m_FlagStarted = true;
- m_TimeStart = systime();
+ m_TimeStart = Clock.currSystemTick;
}
@@ -588,19 +29573,19 @@ public:
catch (Error e) doublestart = false;
assert(!doublestart);
sw.stop();
- assert((t1 - sw.peek()).seconds <= 0);
+ assert((t1 - sw.peek()).to!("seconds", real) <= 0);
}
- /***************************************************************************
- * Stop the time measurement.
- */
+ /++
+ Stop the stop watch.
+ +/
@safe
void stop()
{
assert(m_FlagStarted);
m_FlagStarted = false;
- m_TimeMeasured += systime() - m_TimeStart;
+ m_TimeMeasured += Clock.currSystemTick - m_TimeStart;
}
@@ -614,19 +29599,20 @@ public:
try sw.stop();
catch (Error e) doublestop = false;
assert(!doublestop);
- assert((t1 - sw.peek()).seconds == 0);
+ assert((t1 - sw.peek()).to!("seconds", real) == 0);
}
- /***************************************************************************
- * Peek Ticks of measured time.
- */
- @safe const
- Ticks peek()
+ /++
+ Peek at the amount of time which has passed since the stop watch was
+ started.
+ +/
+ @safe
+ TickDuration peek() const
{
if(m_FlagStarted)
{
- return systime() - m_TimeStart + m_TimeMeasured;
+ return Clock.currSystemTick - m_TimeStart + m_TimeMeasured;
}
return m_TimeMeasured;
}
@@ -646,114 +29632,44 @@ public:
}
-/*******************************************************************************
- * Ticks of system time.
- */
-@trusted
-Ticks systime()
-{
- version (Windows)
- {
- ulong ticks;
- if (QueryPerformanceCounter(cast(long*)&ticks) == 0)
- {
- throw new Exception(sysErrorString(GetLastError()));
- }
- return Ticks(ticks);
- }
- else version (Posix)
- {
- static if (is(typeof(clock_gettime)==function))
- {
- timespec ts;
- errnoEnforce(clock_gettime(CLOCK_REALTIME, &ts) == 0,
- "Failed in gettimeofday");
- return Ticks(ts.tv_sec * Ticks.ticksPerSec +
- ts.tv_nsec * Ticks.ticksPerSec / 1000 / 1000 / 1000);
- }
- else
- {
- timeval tv;
- errnoEnforce(gettimeofday(&tv, null) == 0,
- "Failed in gettimeofday");
- return Ticks(tv.tv_sec * Ticks.ticksPerSec +
- tv.tv_usec * Ticks.ticksPerSec / 1000 / 1000);
- }
- }
-}
-
-
-unittest
-{
- auto t = systime();
- assert(t.value);
-}
-
-
-/*******************************************************************************
- * Ticks when application begin running.
- */
-@safe
-Ticks apptime()
-{
- return systime() - Ticks.appOrigin;
-}
-
-
-unittest
-{
- auto a = systime();
- auto b = apptime();
- assert(a.value);
- assert(a != b);
-}
-
-
-//##############################################################################
-//##############################################################################
-//###
-//### Benchmarks
-//###
-//##############################################################################
-//##############################################################################
// workaround for bug4886
-@safe pure nothrow
-size_t lengthof(aliases...)()
+@safe
+size_t lengthof(aliases...)() pure nothrow
{
return aliases.length;
}
-/*******************************************************************************
- * Benchmarks code for speed assessment and comparison.
- *
- * Params:
- *
- * fun = aliases of callable objects (e.g. function names). Each should
- * take no arguments.
- *
- * times = The number of times each function is to be executed.
- *
- * Returns:
- *
- * An array of $(D n) $(D uint)s. Element at slot $(D i) contains the
- * number of milliseconds spent in calling the $(D i)th function $(D
- * times) times.
- *
- * Examples:
- *------------------------------------------------------------------------------
- *int a;
- *void f0() { }
- *void f1() { auto b = a; }
- *void f2() { auto b = to!(string)(a); }
- *auto r = benchmark!(f0, f1, f2)(10_000_000);
- *------------------------------------------------------------------------------
- */
+/++
+ Benchmarks code for speed assessment and comparison.
+
+ Params:
+
+ fun = aliases of callable objects (e.g. function names). Each should
+ take no arguments.
+
+ times = The number of times each function is to be executed.
+
+ Returns:
+
+ An array of $(D n) $(D uint)s. Element at slot $(D i) contains the
+ number of milliseconds spent in calling the $(D i)th function $(D
+ times) times.
+
+ Examples:
+--------------------
+int a;
+void f0() { }
+void f1() { auto b = a; }
+void f2() { auto b = to!(string)(a); }
+auto r = benchmark!(f0, f1, f2)(10_000_000);
+--------------------
+ +/
@safe
-Ticks[lengthof!(fun)()] benchmark(fun...)(uint times)
+TickDuration[lengthof!(fun)()] benchmark(fun...)(uint times)
if(areAllSafe!fun)
{
- Ticks[lengthof!(fun)()] result;
+ TickDuration[lengthof!(fun)()] result;
StopWatch sw;
sw.start();
foreach (i, Unused; fun)
@@ -768,12 +29684,12 @@ Ticks[lengthof!(fun)()] benchmark(fun...)(uint times)
return result;
}
-/// ditto
+
@system
-Ticks[lengthof!(fun)()] benchmark(fun...)(uint times)
+TickDuration[lengthof!(fun)()] benchmark(fun...)(uint times)
if(!areAllSafe!fun)
{
- Ticks[lengthof!(fun)()] result;
+ TickDuration[lengthof!(fun)()] result;
StopWatch sw;
sw.start();
foreach (i, Unused; fun)
@@ -799,75 +29715,76 @@ unittest
}
-/*******************************************************************************
- * Return value of benchmark with two functions comparing.
- */
+/++
+ Return value of benchmark with two functions comparing.
+ +/
immutable struct ComparingBenchmarkResult
{
@safe:
- private Ticks m_tmBase;
- private Ticks m_tmTarget;
+ private TickDuration m_tmBase;
+ private TickDuration m_tmTarget;
- /***************************************************************************
- * Evaluation value
- *
- * This return the evaluation value of performance as the ratio that is
- * compared between BaseFunc's time and TargetFunc's time.
- * If performance is high, this returns a high value.
- */
- @property immutable
- real point()
+ /++
+ Evaluation value
+
+ This returns the evaluation value of performance as the ratio that is
+ compared between BaseFunc's time and TargetFunc's time.
+ If performance is high, this returns a high value.
+ +/
+ @property
+ real point() immutable pure
{
// @@@BUG@@@ workaround for bug 4689
- long t = m_tmTarget.value;
- return m_tmBase.value / cast(real)t;
+ long t = m_tmTarget.length;
+ return m_tmBase.length / cast(real)t;
}
- /***************************************************************************
- * The time required of the target function
- */
- @property immutable
- public Ticks targetTime()
+ /++
+ The time required of the target function
+ +/
+ @property
+ public TickDuration targetTime() immutable pure
{
return m_tmTarget;
}
- /***************************************************************************
- * The time required of the base function
- */
- @property immutable
- public Ticks baseTime()
+ /++
+ The time required of the base function
+ +/
+ @property
+ public TickDuration baseTime() immutable pure
{
return m_tmBase;
}
}
-/*******************************************************************************
- * Benchmark with two functions comparing.
- *
- * Params:
- * baseFunc = The function to become the base of the speed.
- * targetFunc = The function that wants to measure speed.
- * times = The number of times each function is to be executed.
- * Examples:
- *------------------------------------------------------------------------------
- *void f1() {
- * // ...
- *}
- *void f2() {
- * // ...
- *}
- *
- *void main() {
- * auto b = comparingBenchmark!(f1, f2, 0x80);
- * writeln(b.point);
- *}
- *------------------------------------------------------------------------------
- */
+/++
+ Benchmark with two functions comparing.
+
+ Params:
+ baseFunc = The function to become the base of the speed.
+ targetFunc = The function that wants to measure speed.
+ times = The number of times each function is to be executed.
+
+ Examples:
+--------------------
+void f1() {
+ // ...
+}
+void f2() {
+ // ...
+}
+
+void main() {
+ auto b = comparingBenchmark!(f1, f2, 0x80);
+ writeln(b.point);
+}
+--------------------
+ +/
@safe
ComparingBenchmarkResult comparingBenchmark(
alias baseFunc, alias targetFunc, int times = 0xfff)()
@@ -913,46 +29830,1189 @@ unittest
}
-//##############################################################################
-//##############################################################################
-//###
-//### Helper functions
-//###
-//##############################################################################
-//##############################################################################
+//==============================================================================
+// Section with other types.
+//==============================================================================
+
+/++
+ Exception type used by std.datetime.
+ +/
+alias TimeException DateTimeException;
-version (D_Ddoc)
+/++
+ Effectively a namespace to make it clear where its methods are getting
+ their time from. It cannot be instantiated.
+ +/
+final class Clock
{
- /***************************************************************************
- * Scope base measuring time.
- *
- * When a value that is returned by this function is destroyed,
- * func will run.
- * func is unaly function that requires Ticks.
- *
- * Examples:
- *--------------------------------------------------------------------------
- *writeln("benchmark start!");
- *{
- * auto mt = measureTime!((a){assert(a.seconds);});
- * doSomething();
- *}
- *writeln("benchmark end!");
- *--------------------------------------------------------------------------
- */
+public:
+
+ /++
+ Returns the current time in the local timezone.
+ +/
+ static SysTime currTime(immutable TimeZone tz = LocalTime())
+ {
+ return SysTime(currStdTime, tz);
+ }
+
+ unittest
+ {
+ //Verify that currTime() at least gives a time
+ //which isn't way off in the past (like if the
+ //conversions between epochs in currStdTime() was off).
+ assert(currTime > SysTime(Date(2010, 11, 1)));
+
+ assert(currTime(UTC()).timezone is UTC());
+ }
+
+
+ /++
+ Returns the number of hnsecs since midnight, January 1st, 1 A.D. for the
+ current time.
+
+ Throws:
+ ErrnoException (on Posix) or Exception (on Windows) if it fails to
+ get the time of day.
+ +/
+ @trusted
+ static @property long currStdTime()
+ {
+ enum hnsecsToUnixEpoch = 621_355_968_000_000_000L;
+
+ version(Windows)
+ {
+ enum adjustmentFromFileTime = 116_444_736_000_000_000L;
+
+ FILETIME fileTime;
+
+ GetSystemTimeAsFileTime(&fileTime);
+
+ ulong tempHNSecs = fileTime.dwHighDateTime;
+ tempHNSecs <<= 32;
+ tempHNSecs |= fileTime.dwLowDateTime;
+
+ return cast(long)tempHNSecs - adjustmentFromFileTime + hnsecsToUnixEpoch;
+ }
+ else version(Posix)
+ {
+ static if(is(typeof(clock_gettime)))
+ {
+ timespec ts;
+
+ if(clock_gettime(CLOCK_REALTIME, &ts) != 0)
+ throw new TimeException("Failed in clock_gettime().");
+
+ return convert!("seconds", "hnsecs")(ts.tv_sec) +
+ ts.tv_nsec / 100 +
+ hnsecsToUnixEpoch;
+ }
+ else
+ {
+ timeval tv;
+
+ if(gettimeofday(&tv, null) != 0)
+ throw new TimeException("Failed in gettimeofday().");
+
+ return convert!("seconds", "hnsecs")(tv.tv_sec) +
+ convert!("usecs", "hnsecs")(tv.tv_usec) +
+ hnsecsToUnixEpoch;
+ }
+ }
+ }
+
+
+ /++
+ The current system tick. The number of ticks per second varies from
+ system to system. This uses a monotonic clock, so it's intended for
+ precision timing by comparing relative time values, not for getting
+ the current system time.
+
+ Warning:
+ On some systems, the monotonic clock may stop counting when
+ the computer goes to sleep or hibernates. So, the monotonic
+ clock could be off if that occurs. This is known to happen
+ on Mac OS X. It has not been tested whether it occurs on
+ either Windows or on Linux.
+
+ Throws:
+ TimeException if it fails to get the time.
+ +/
+ @safe
+ static @property TickDuration currSystemTick()
+ {
+ return TickDuration.currSystemTick();
+ }
+
+ unittest
+ {
+ auto t = Clock.currSystemTick;
+ assert(t.length > 0);
+ }
+
+
+ /++
+ The current number of system ticks since the application started.
+ The number of ticks per second varies from system to system.
+ This uses a monotonic clock.
+
+ Warning:
+ On some systems, the monotonic clock may stop counting when
+ the computer goes to sleep or hibernates. So, the monotonic
+ clock could be off if that occurs. This is known to happen
+ on Mac OS X. It has not been tested whether it occurs on
+ either Windows or on Linux.
+
+ Throws:
+ ErrnoException (on Posix) or Exception (on Windows) if it fails to
+ get the time of day.
+ +/
+ @safe
+ static @property TickDuration currAppTick()
+ {
+ return currSystemTick - TickDuration.appOrigin;
+ }
+
+ unittest
+ {
+ auto a = Clock.currSystemTick;
+ auto b = Clock.currAppTick;
+ assert(a.length);
+ assert(a != b);
+ }
+
+
+ //TODO Add support for monotonic clocks.
+
+private:
+
+ @disable this() {}
+}
+
+
+//==============================================================================
+// Section with public helper functions and templates.
+//==============================================================================
+
+/++
+ Whether the given type defines all of the necessary functions for it to
+ function as a time point.
+ +/
+template isTimePoint(T)
+{
+ enum isTimePoint = hasMin!T &&
+ hasMax!T &&
+ hasOverloadedOpBinaryWithDuration!T &&
+ hasOverloadedOpAssignWithDuration!T &&
+ hasOverloadedOpBinaryWithSelf!T;
+}
+
+unittest
+{
+ static assert(isTimePoint!(Date));
+ static assert(isTimePoint!(DateTime));
+ static assert(isTimePoint!(TimeOfDay));
+ static assert(isTimePoint!(SysTime));
+ static assert(isTimePoint!(const Date));
+ static assert(isTimePoint!(const DateTime));
+ static assert(isTimePoint!(const TimeOfDay));
+ static assert(isTimePoint!(const SysTime));
+ static assert(isTimePoint!(immutable Date));
+ static assert(isTimePoint!(immutable DateTime));
+ static assert(isTimePoint!(immutable TimeOfDay));
+ static assert(isTimePoint!(immutable SysTime));
+}
+
+
+/++
+ Whether the given Gregorian Year is a leap year.
+
+ Params:
+ year = The year to to be tested.
+ +/
+static bool yearIsLeapYear(int year) pure nothrow
+{
+ if(year % 400 == 0)
+ return true;
+
+ if(year % 100 == 0)
+ return false;
+
+ return year % 4 == 0;
+}
+
+unittest
+{
+ //Test A.D.
+ assert(!yearIsLeapYear(1));
+ assert(!yearIsLeapYear(2));
+ assert(!yearIsLeapYear(3));
+ assert(yearIsLeapYear(4));
+ assert(!yearIsLeapYear(5));
+ assert(!yearIsLeapYear(6));
+ assert(!yearIsLeapYear(7));
+ assert(yearIsLeapYear(8));
+
+ assert(!yearIsLeapYear(100));
+ assert(!yearIsLeapYear(200));
+ assert(!yearIsLeapYear(300));
+ assert(yearIsLeapYear(400));
+ assert(!yearIsLeapYear(500));
+ assert(!yearIsLeapYear(600));
+ assert(!yearIsLeapYear(700));
+ assert(yearIsLeapYear(800));
+
+ assert(yearIsLeapYear(1996));
+ assert(!yearIsLeapYear(1997));
+ assert(!yearIsLeapYear(1998));
+ assert(!yearIsLeapYear(1999));
+ assert(yearIsLeapYear(2000));
+ assert(!yearIsLeapYear(2001));
+ assert(!yearIsLeapYear(2002));
+ assert(!yearIsLeapYear(2003));
+ assert(yearIsLeapYear(2004));
+ assert(!yearIsLeapYear(2005));
+ assert(!yearIsLeapYear(2006));
+ assert(!yearIsLeapYear(2007));
+ assert(yearIsLeapYear(2008));
+ assert(!yearIsLeapYear(2009));
+ assert(!yearIsLeapYear(2010));
+
+ //Test B.C.
+ assert(yearIsLeapYear(0));
+ assert(!yearIsLeapYear(-1));
+ assert(!yearIsLeapYear(-2));
+ assert(!yearIsLeapYear(-3));
+ assert(yearIsLeapYear(-4));
+ assert(!yearIsLeapYear(-5));
+ assert(!yearIsLeapYear(-6));
+ assert(!yearIsLeapYear(-7));
+ assert(yearIsLeapYear(-8));
+
+ assert(!yearIsLeapYear(-100));
+ assert(!yearIsLeapYear(-200));
+ assert(!yearIsLeapYear(-300));
+ assert(yearIsLeapYear(-400));
+ assert(!yearIsLeapYear(-500));
+ assert(!yearIsLeapYear(-600));
+ assert(!yearIsLeapYear(-700));
+ assert(yearIsLeapYear(-800));
+
+ assert(yearIsLeapYear(-1996));
+ assert(!yearIsLeapYear(-1997));
+ assert(!yearIsLeapYear(-1998));
+ assert(!yearIsLeapYear(-1999));
+ assert(yearIsLeapYear(-2000));
+ assert(!yearIsLeapYear(-2001));
+ assert(!yearIsLeapYear(-2002));
+ assert(!yearIsLeapYear(-2003));
+ assert(yearIsLeapYear(-2004));
+ assert(!yearIsLeapYear(-2005));
+ assert(!yearIsLeapYear(-2006));
+ assert(!yearIsLeapYear(-2007));
+ assert(yearIsLeapYear(-2008));
+ assert(!yearIsLeapYear(-2009));
+ assert(!yearIsLeapYear(-2010));
+}
+
+
+/++
+ Converts a time_t (which uses midnight, January 1st, 1970 UTC as its epoch
+ and seconds as its units) to std time (which uses midnight, January 1st,
+ 1 A.D. UTC and hnsecs as its units).
+
+ Params:
+ unixTime = The time_t to convert.
+ +/
+long unixTimeToStdTime(time_t unixTime) pure nothrow
+{
+ return 621355968000000000L + convert!("seconds", "hnsecs")(unixTime);
+}
+
+unittest
+{
+ assertPred!"=="(unixTimeToStdTime(0), 621355968000000000L); //Midnight, January 1st, 1970
+ assertPred!"=="(unixTimeToStdTime(86_400), 621355968000000000L + 864_000_000_000L); //Midnight, January 2nd, 1970
+ assertPred!"=="(unixTimeToStdTime(-86_400), 621355968000000000L - 864_000_000_000L); //Midnight, December 31st, 1969
+
+ assertPred!"=="(unixTimeToStdTime(0), (Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs");
+ assertPred!"=="(unixTimeToStdTime(0), (DateTime(1970, 1, 1) - DateTime(1, 1, 1)).total!"hnsecs");
+}
+
+
+/++
+ Converts std time (which uses midnight, January 1st, 1 A.D. UTC as its epoch
+ and hnsecs as its units) to time_t (which uses midnight, January 1st, 1970 UTC
+ as its epoch and seconds as its units). If time_t is 32 bits, rather than 64,
+ and the result can't fit in a 32-bit value, then the closest value that can
+ be held in 32 bits will be used (so time_t.max if it goes over or time_t.min
+ if it goes under).
+
+ Note:
+ While Windows systems require that time_t be non-negative (in spite of
+ time_t being signed), this function still returns negative numbers on
+ Windows, since it's more flexible to allow negative time_t for those
+ who need it. So, if you're on Windows and are using the standard C
+ functions or Win32 API functions which take a time_t, you may want to
+ check whether the return value of $(D stdTimeToUnixTime()) is non-negative.
+
+ Params:
+ stdTime = The std time to convert.
+ +/
+time_t stdTimeToUnixTime(long stdTime) pure nothrow
+{
+ immutable hnsecsAtUnixTimeEpoch = convert!("hnsecs", "seconds")(stdTime - 621355968000000000L);
+
+ static if(time_t.sizeof >= long.sizeof)
+ return cast(time_t)hnsecsAtUnixTimeEpoch;
+ else
+ {
+ if(hnsecsAtUnixTimeEpoch > 0)
+ {
+ if(hnsecsAtUnixTimeEpoch > time_t.max)
+ return time_t.max;
+ return cast(time_t)hnsecsAtUnixTimeEpoch;
+ }
+
+ if(hnsecsAtUnixTimeEpoch < time_t.min)
+ return time_t.min;
+
+ return cast(time_t)hnsecsAtUnixTimeEpoch;
+ }
+}
+
+unittest
+{
+ assertPred!"=="(stdTimeToUnixTime(621355968000000000L), 0); //Midnight, January 1st, 1970
+ assertPred!"=="(stdTimeToUnixTime(621355968000000000L + 864_000_000_000L), 86_400); //Midnight, January 2nd, 1970
+ assertPred!"=="(stdTimeToUnixTime(621355968000000000L - 864_000_000_000L), -86_400); //Midnight, December 31st, 1969
+
+ assertPred!"=="(stdTimeToUnixTime((Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs"), 0);
+ assertPred!"=="(stdTimeToUnixTime((DateTime(1970, 1, 1) - DateTime(1, 1, 1)).total!"hnsecs"), 0);
+}
+
+
+version(Windows)
+{
+ /++
+ On Windows, this converts a SYSTEMTIME struct to a SysTime.
+
+ Params:
+ st = The SYSTEMTIME struct to convert.
+ tz = The time zone that the time in the SYSTEMTIME struct
+ is assumed to be (if the SYSTEMTIME was supplied by a
+ Windows system call, the SYSTEMTIME will either be in
+ local time or UTC, depending on the call).
+
+ Throws:
+ DateTimeException if the given SYSTEMTIME will not fit in a SysTime,
+ which is highly unlikely to happen given that SysTime.max is in 29,228 A.D.
+ and the maximum SYSTEMTIME is in 30,827 A.D.
+ +/
+ SysTime SYSTEMTIMEToSysTime(const SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) pure
+ {
+ const max = SysTime.max;
+
+ static void throwLaterThanMax()
+ {
+ throw new DateTimeException("The given SYSTEMTIME is for a date greater than SysTime.max.");
+ }
+
+ if(st.wYear > max.year)
+ throwLaterThanMax();
+ else if(st.wYear == max.year)
+ {
+ if(st.wMonth > max.month)
+ throwLaterThanMax();
+ else if(st.wMonth == max.month)
+ {
+ if(st.wDay > max.day)
+ throwLaterThanMax();
+ else if(st.wDay == max.day)
+ {
+ if(st.wHour > max.hour)
+ throwLaterThanMax();
+ else if(st.wHour == max.hour)
+ {
+ if(st.wMinute > max.minute)
+ throwLaterThanMax();
+ else if(st.wMinute == max.minute)
+ {
+ if(st.wSecond > max.second)
+ throwLaterThanMax();
+ else if(st.wSecond == max.second)
+ {
+ if(st.wMilliseconds > max.fracSec.msecs)
+ throwLaterThanMax();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ auto dt = DateTime(st.wYear, st.wMonth, st.wDay,
+ st.wHour, st.wMinue, st.wSecond);
+
+ return SysTime(dt, FracSec.from!"msecs"(st.wMilliseconds), tz);
+ }
+
+ unittest
+ {
+ auto sysTime = Clock.currTime(UTC());
+ SYSTEMTIME st = void;
+ GetSystemTime(&st);
+ auto converted = SYSTEMTIMEToSystemTime(&st);
+
+ assertPred!"<="(sysTime, converted);
+ assertPred!"<="(converted - sysTime, dur!"msecs"(10));
+ }
+
+
+ /++
+ On Windows, this converts a SysTime to a SYSTEMTIME struct.
+
+ The SYSTEMTIME will be set using the given SysTime's time zone, so
+ if you want the SYSTEMTIME to be in UTC, set the SysTime's time zone
+ to UTC.
+
+ Params:
+ sysTime = The SysTime to convert.
+ st = The SYSTEMTIME struct to fill in with the date and
+ time from sysTime.
+
+ Throws:
+ DateTimeException if the given SysTime will not fit in a SYSTEMTIME.
+ This will only happen if the SysTime's date is prior to 1601 A.D.
+ +/
+ void SysTimeToSYSTEMTIME(in SysTime sysTime, SYSTEMTIME* st) pure
+ {
+ immutable dt = cast(DateTime)sysTime;
+
+ if(dt.year < 1601)
+ throw new DateTimeException("SYSTEMTIME cannot hold dates prior to the year 1601.");
+
+ st.wYear = dt.year;
+ st.wMonth = dt.month;
+ st.wDayOfWeek = dt.dayOfWeek;
+ st.wDay = dt.day;
+ st.wHour = dt.hour;
+ st.wMinute = dt.minute;
+ st.wSecond = dt.second;
+ st.wMilliseconds = sysTime.fracSec.msecs;
+ }
+
+ unittest
+ {
+ SYSTEMTIME st = void;
+ GetSystemTime(&st);
+ auto sysTime = SYSTEMTIMEToSysTime(&st, UTC());
+
+ SYSTEMTIME result = void;
+ SysTimeToSYSTEMTIME(sysTime, &result);
+
+ assertPred!"=="(st.wYear, result.wYear);
+ assertPred!"=="(st.wMonth, result.wMonth);
+ assertPred!"=="(st.wDayOfWeek, result.wDayOfWeek);
+ assertPred!"=="(st.wDay, result.wDay);
+ assertPred!"=="(st.wHour, result.wHour);
+ assertPred!"=="(st.wMinute, result.wMinute);
+ assertPred!"=="(st.wSecond, result.wSecond);
+ assertPred!"=="(st.wMillisecond, result.wMillisecond);
+ }
+
+
+ /++
+ On Windows, this converts a FILETIME struct to a SysTime.
+
+ Params:
+ ft = The FILETIME struct to convert.
+ tz = The time zone that the SysTime will be in (FILETIMEs are
+ in UTC).
+
+ Throws:
+ DateTimeException if the given FILETIME will not fit in a SysTime or
+ if the FILETIME cannot be converted to a SYSTEMTIME.
+ +/
+ SysTime FILETIMEToSysTime(const FILETIME* ft, immutable TimeZone tz = LocalTime()) pure
+ {
+ SYSTEMTIME st = void;
+
+ if(!FileTimeToSystemTime(ft, &st))
+ throw new DateTimeException("FileTimeToSystemTime() failed.");
+
+ auto sysTime = SYSTEMTIMEToSysTime(&st, UTC());
+ sysTime.timezone = tz;
+
+ return sysTime;
+ }
+
+ unittest
+ {
+ auto sysTime = Clock.currTime(UTC());
+ SYSTEMTIME st = void;
+ GetSystemTime(&st);
+
+ FILETIME ft = void;
+ SystemTimeToFileTime(&st, &ft);
+
+ auto converted = FILETIMEToSysTime(&ft);
+
+ assertPred!"<="(sysTime, converted);
+ assertPred!"<="(converted - sysTime, dur!"msecs"(10));
+ }
+
+
+ /++
+ On Windows, this converts a SysTime to a FILETIME struct.
+
+ Params:
+ sysTime = The SysTime to convert.
+ ft = The FILETIME struct to fill in with the date and
+ time from sysTime.
+
+ Throws:
+ DateTimeException if the given SysTime will not fit in a FILETIME.
+ +/
+ void SysTimeToFILETIME(SysTime sysTime, FILETIME* ft) pure
+ {
+ sysTime.timezone = UTC();
+ immutable dt = cast(DateTime)sysTime;
+
+ SYSTEMTIME st = void;
+ SysTimeToSYSTEMTIME(sysTime, st);
+
+ SystemTimeToFileTime(&st, ft);
+ }
+
+ unittest
+ {
+ SYSTEMTIME st = void;
+ GetSystemTime(&st);
+
+ FILETIME ft = void;
+ SystemTimeToFileTime(&st, &ft);
+ auto sysTime = FILETIMEToSysTime(&ft, UTC());
+
+ FILETIME result = void;
+ SysTimeToFILETIME(sysTime, &result);
+
+ assertPred!"=="(ft.dwLowDateTime, result.fwLowDateTime);
+ assertPred!"=="(ft.dwHighDateTime, result.fwHighDateTime);
+ }
+}
+else version(D_Ddoc)
+{
+ //These types don't exist outside of Windows.
+ alias int SYSTEMTIME;
+ alias int FILETIME;
+
+ /++
+ On Windows, this converts a SYSTEMTIME struct to a SysTime.
+
+ Params:
+ st = The SYSTEMTIME struct to convert.
+ tz = The time zone that the time in the SYSTEMTIME struct
+ is assumed to be (if the SYSTEMTIME was supplied by a
+ Windows system call, the SYSTEMTIME will either be in
+ local time or UTC, depending on the call).
+
+ Throws:
+ DateTimeException if the given SYSTEMTIME will not fit in a SysTime,
+ which is highly unlikely to happen given that SysTime.max is in 29,228 A.D.
+ and the maximum SYSTEMTIME is in 30,827 A.D.
+ +/
+ SysTime SYSTEMTIMEToSysTime(const SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) pure
+ {
+ assert(0, "No implementation. Function exists only for DDoc generation");
+ }
+
+
+ /++
+ On Windows, this converts a SysTime to a SYSTEMTIME struct.
+
+ The SYSTEMTIME will be set using the given SysTime's time zone, so
+ if you want the SYSTEMTIME to be in UTC, set the SysTime's time zone
+ to UTC.
+
+ Params:
+ sysTime = The SysTime to convert.
+ st = The SYSTEMTIME struct to fill in with the date and
+ time from sysTime.
+
+ Throws:
+ DateTimeException if the given SysTime will not fit in a SYSTEMTIME.
+ This will only happen if the SysTime's date is prior to 1601 A.D.
+ +/
+ void SysTimeToSYSTEMTIME(in SysTime sysTime, SYSTEMTIME* st) pure
+ {
+ assert(0, "No implementation. Function exists only for DDoc generation");
+ }
+
+
+ /++
+ On Windows, this converts a FILETIME struct to a SysTime.
+
+ Params:
+ ft = The FILETIME struct to convert.
+ tz = The time zone that the SysTime will be in (FILETIMEs are
+ in UTC).
+
+ Throws:
+ DateTimeException if the given FILETIME will not fit in a SysTime or
+ if the FILETIME cannot be converted to a SYSTEMTIME.
+ +/
+ SysTime FILETIMEToSysTime(const FILETIME* ft, immutable TimeZone tz = LocalTime()) pure
+ {
+ assert(0, "No implementation. Function exists only for DDoc generation");
+ }
+
+
+ /++
+ On Windows, this converts a SysTime to a FILETIME struct.
+
+ Params:
+ sysTime = The SysTime to convert.
+ ft = The FILETIME struct to fill in with the date and
+ time from sysTime.
+
+ Throws:
+ DateTimeException if the given SysTime will not fit in a FILETIME.
+ +/
+ void SysTimeToFILETIME(SysTime sysTime, FILETIME* ft) pure
+ {
+ assert(0, "No implementation. Function exists only for DDoc generation");
+ }
+}
+
+
+/++
+ Type representing the DOS file date/time format.
+ +/
+typedef uint DosFileTime;
+
+/++
+ Converts from DOS file date/time to SysTime.
+
+ Params:
+ dft = The DOS file time to convert.
+ tz = The time zone which the DOS file time is assumed to be in.
+
+ Throws:
+ DateTimeException if the DosFileTime is invalid.
+ +/
+SysTime DosFileTimeToSysTime(DosFileTime dft, immutable TimeZone tz = LocalTime())
+{
+ uint dt = cast(uint)dft;
+
+ if(dt == 0)
+ throw new DateTimeException("Invalid DosFileTime.");
+
+ int year = ((dt >> 25) & 0x7F) + 1980;
+ int month = ((dt >> 21) & 0x0F) - 1; // 1..12
+ int dayOfMonth = ((dt >> 16) & 0x1F); // 1..31
+ int hour = (dt >> 11) & 0x1F; // 0..23
+ int minute = (dt >> 5) & 0x3F; // 0..59
+ int second = (dt << 1) & 0x3E; // 0..58 (in 2 second increments)
+
+ SysTime sysTime = void;
+
+ try
+ return SysTime(DateTime(year, month, dayOfMonth, hour, minute, second), tz);
+ catch(DateTimeException dte)
+ throw new DateTimeException("Invalid DosFileTime", __FILE__, __LINE__, dte);
+}
+
+
+/++
+ Converts from SysTime to DOS file date/time.
+
+ Params:
+ sysTime = The SysTime to convert.
+
+ Throws:
+ DateTimeException if the given SysTime cannot be converted to
+ a DosFileTime.
+ +/
+DosFileTime SysTimeToDosFileTime(SysTime sysTime)
+{
+ auto dateTime = cast(DateTime)sysTime;
+
+ if(dateTime.year < 1980)
+ throw new DateTimeException("DOS File Times cannot hold dates prior to 1980.");
+
+ if(dateTime.year > 2107)
+ throw new DateTimeException("DOS File Times cannot hold dates passed 2107.");
+
+ uint retval = 0;
+ retval = (dateTime.year - 1980) << 25;
+ retval |= ((dateTime.month + 1) & 0x0F) << 21;
+ retval |= (dateTime.day & 0x1F) << 16;
+ retval |= (dateTime.hour & 0x1F) << 11;
+ retval |= (dateTime.minute & 0x3F) << 5;
+ retval |= (dateTime.second >> 1) & 0x1F;
+
+ return cast(DosFileTime)retval;
+}
+
+
+
+/++
+ Whether all of the given strings are valid units of time.
+
+ "nsecs" is not considered a valid unit of time. Nothing in
+ std.datetime can handle precision greater than hnsecs, and
+ the few functions in core.time which deal with "nsecs"
+ deal with it explicitly.
+ +/
+bool validTimeUnits(string[] units...)
+{
+ foreach(str; units)
+ {
+ if(!canFind(timeStrings.dup, str))
+ return false;
+ }
+
+ return true;
+}
+
+
+/++
+ Compares two TimeStrings. "years" are the largest units and "hnsecs" are
+ the smallest.
+
+ Returns:
+ $(TABLE
+ $(TR $(TD this < rhs) $(TD < 0))
+ $(TR $(TD this == rhs) $(TD 0))
+ $(TR $(TD this > rhs) $(TD > 0))
+ )
+
+ Throws:
+ DateTimeException if either of the given strings is not a valid time
+ unit string.
+ +/
+int cmpTimeUnits(string lhs, string rhs)
+{
+ auto tstrings = timeStrings.dup;
+ immutable indexOfLHS = std.algorithm.indexOf(tstrings, lhs);
+ immutable indexOfRHS = std.algorithm.indexOf(tstrings, rhs);
+
+ enforce(indexOfLHS != -1, format("%s is not a valid TimeString", lhs));
+ enforce(indexOfRHS != -1, format("%s is not a valid TimeString", rhs));
+
+ if(indexOfLHS < indexOfRHS)
+ return -1;
+ if(indexOfLHS > indexOfRHS)
+ return 1;
+
+ return 0;
+}
+
+unittest
+{
+ foreach(i, outerUnits; timeStrings)
+ {
+ assertPred!"=="(cmpTimeUnits(outerUnits, outerUnits), 0);
+
+ //For some reason, $ won't compile.
+ foreach(innerUnits; timeStrings[i+1 .. timeStrings.length])
+ assertPred!"=="(cmpTimeUnits(outerUnits, innerUnits), -1);
+ }
+
+ foreach(i, outerUnits; timeStrings)
+ {
+ foreach(innerUnits; timeStrings[0 .. i])
+ assertPred!"=="(cmpTimeUnits(outerUnits, innerUnits), 1);
+ }
+}
+
+
+/++
+ Compares two time unit strings at compile time. "years" are the largest
+ units and "hnsecs" are the smallest.
+
+ This template is used instead of $(D cmpTimeUnits()) because exceptions
+ can't be thrown at compile-time and $(D cmpTimeUnits()) must enforce that
+ the strings it's given are valid time unit strings. This template uses a
+ template constraint instead.
+
+ Returns:
+ $(TABLE
+ $(TR $(TD this < rhs) $(TD < 0))
+ $(TR $(TD this == rhs) $(TD 0))
+ $(TR $(TD this > rhs) $(TD > 0))
+ )
+ +/
+template CmpTimeUnits(string lhs, string rhs)
+ if(validTimeUnits(lhs, rhs))
+{
+ enum CmpTimeUnits = cmpTimeUnitsCTFE(lhs, rhs);
+}
+
+
+/+
+ Helper function for CmpTimeUnits.
+ +/
+private int cmpTimeUnitsCTFE(string lhs, string rhs)
+{
+ auto tstrings = timeStrings.dup;
+ immutable indexOfLHS = std.algorithm.indexOf(tstrings, lhs);
+ immutable indexOfRHS = std.algorithm.indexOf(tstrings, rhs);
+
+ if(indexOfLHS < indexOfRHS)
+ return -1;
+ if(indexOfLHS > indexOfRHS)
+ return 1;
+
+ return 0;
+}
+
+unittest
+{
+ static string genTest(size_t index)
+ {
+ auto currUnits = timeStrings[index];
+ auto test = `assertPred!"=="(CmpTimeUnits!("` ~ currUnits ~ `", "` ~ currUnits ~ `"), 0); `;
+
+ //For some reason, $ won't compile.
+ foreach(units; timeStrings[index + 1 .. timeStrings.length])
+ test ~= `assertPred!"=="(CmpTimeUnits!("` ~ currUnits ~ `", "` ~ units ~ `"), -1); `;
+
+ foreach(units; timeStrings[0 .. index])
+ test ~= `assertPred!"=="(CmpTimeUnits!("` ~ currUnits ~ `", "` ~ units ~ `"), 1); `;
+
+ return test;
+ }
+
+ mixin(genTest(0));
+ mixin(genTest(1));
+ mixin(genTest(2));
+ mixin(genTest(3));
+ mixin(genTest(4));
+ mixin(genTest(5));
+ mixin(genTest(6));
+ mixin(genTest(7));
+ mixin(genTest(8));
+ mixin(genTest(9));
+}
+
+
+/++
+ Returns whether the given value is valid for the given unit type when in a
+ time point. Naturally, a duration is not held to a particular range, but
+ the values in a time point are (e.g. a month must be in the range of
+ 1 - 12 inclusive).
+
+ Params:
+ units = The units of time to validate.
+ value = The number to validate.
+
+ Examples:
+--------------------
+assert(valid!"hours"(12));
+assert(!valid!"hours"(32));
+assert(valid!"months"(12));
+assert(!valid!"months"(13));
+--------------------
+ +/
+bool valid(string units)(int value) pure nothrow
+ if(units == "months" ||
+ units == "hours" ||
+ units == "minutes" ||
+ units == "seconds")
+{
+ static if(units == "months")
+ return value >= Month.jan && value <= Month.dec;
+ else static if(units == "hours")
+ return value >= 0 && value <= TimeOfDay.maxHour;
+ else static if(units == "minutes")
+ return value >= 0 && value <= TimeOfDay.maxMinute;
+ else static if(units == "seconds")
+ return value >= 0 && value <= TimeOfDay.maxSecond;
+}
+
+unittest
+{
+ //Verify Examples.
+ assert(valid!"hours"(12));
+ assert(!valid!"hours"(32));
+ assert(valid!"months"(12));
+ assert(!valid!"months"(13));
+}
+
+
+/++
+ Returns whether the given day is valid for the given year and month.
+
+ Params:
+ units = The units of time to validate.
+ year = The year of the day to validate.
+ month = The month of the day to validate.
+ day = The day to validate.
+ +/
+bool valid(string units)(int year, int month, int day) pure nothrow
+ if(units == "days")
+{
+ return day > 0 && day <= maxDay(year, month);
+}
+
+
+/++
+ Params:
+ units = The units of time to validate.
+ value = The number to validate.
+ file = The file that the DateTimeException will list if thrown.
+ line = The line number that the DateTimeException will list if thrown.
+
+ Throws:
+ DateTimeException if valid!units(value) is false.
+ +/
+void enforceValid(string units)(int value, string file = __FILE__, size_t line = __LINE__) pure
+ if(units == "months" ||
+ units == "hours" ||
+ units == "minutes" ||
+ units == "seconds")
+{
+ static if(units == "months")
+ {
+ if(!valid!units(value))
+ throw new DateTimeException(numToString(value) ~ " is not a valid month of the year.", file, line);
+ }
+ else static if(units == "hours")
+ {
+ if(!valid!units(value))
+ throw new DateTimeException(numToString(value) ~ " is not a valid hour of the day.", file, line);
+ }
+ else static if(units == "minutes")
+ {
+ if(!valid!units(value))
+ throw new DateTimeException(numToString(value) ~ " is not a valid minute of an hour.", file, line);
+ }
+ else static if(units == "seconds")
+ {
+ if(!valid!units(value))
+ throw new DateTimeException(numToString(value) ~ " is not a valid second of a minute.", file, line);
+ }
+}
+
+
+/++
+ Params:
+ units = The units of time to validate.
+ year = The year of the day to validate.
+ month = The month of the day to validate.
+ day = The day to validate.
+ file = The file that the DateTimeException will list if thrown.
+ line = The line number that the DateTimeException will list if thrown.
+
+ Throws:
+ DateTimeException if valid!"days"(year, month, day) is false.
+ +/
+void enforceValid(string units)(int year, Month month, int day, string file = __FILE__, size_t line = __LINE__) pure
+ if(units == "days")
+{
+ if(!valid!"days"(year, month, day))
+ {
+ throw new DateTimeException(numToString(day) ~
+ " is not a valid day in " ~
+ monthToString(month) ~
+ " in " ~
+ numToString(year), file, line);
+ }
+}
+
+
+/++
+ Returns the number of months from the current months of the year to the
+ given month of the year. If they are the same, then the result is 0.
+
+ Params:
+ currMonth = The current month of the year.
+ month = The month of the year to get the number of months to.
+ +/
+static int monthsToMonth(int currMonth, int month) pure
+{
+ enforceValid!"months"(currMonth);
+ enforceValid!"months"(month);
+
+ if(currMonth == month)
+ return 0;
+
+ if(currMonth < month)
+ return month - currMonth;
+
+ return (Month.dec - currMonth) + month;
+}
+
+unittest
+{
+ assertPred!"=="(monthsToMonth(Month.jan, Month.jan), 0);
+ assertPred!"=="(monthsToMonth(Month.jan, Month.feb), 1);
+ assertPred!"=="(monthsToMonth(Month.jan, Month.mar), 2);
+ assertPred!"=="(monthsToMonth(Month.jan, Month.apr), 3);
+ assertPred!"=="(monthsToMonth(Month.jan, Month.may), 4);
+ assertPred!"=="(monthsToMonth(Month.jan, Month.jun), 5);
+ assertPred!"=="(monthsToMonth(Month.jan, Month.jul), 6);
+ assertPred!"=="(monthsToMonth(Month.jan, Month.aug), 7);
+ assertPred!"=="(monthsToMonth(Month.jan, Month.sep), 8);
+ assertPred!"=="(monthsToMonth(Month.jan, Month.oct), 9);
+ assertPred!"=="(monthsToMonth(Month.jan, Month.nov), 10);
+ assertPred!"=="(monthsToMonth(Month.jan, Month.dec), 11);
+
+ assertPred!"=="(monthsToMonth(Month.may, Month.jan), 8);
+ assertPred!"=="(monthsToMonth(Month.may, Month.feb), 9);
+ assertPred!"=="(monthsToMonth(Month.may, Month.mar), 10);
+ assertPred!"=="(monthsToMonth(Month.may, Month.apr), 11);
+ assertPred!"=="(monthsToMonth(Month.may, Month.may), 0);
+ assertPred!"=="(monthsToMonth(Month.may, Month.jun), 1);
+ assertPred!"=="(monthsToMonth(Month.may, Month.jul), 2);
+ assertPred!"=="(monthsToMonth(Month.may, Month.aug), 3);
+ assertPred!"=="(monthsToMonth(Month.may, Month.sep), 4);
+ assertPred!"=="(monthsToMonth(Month.may, Month.oct), 5);
+ assertPred!"=="(monthsToMonth(Month.may, Month.nov), 6);
+ assertPred!"=="(monthsToMonth(Month.may, Month.dec), 7);
+
+ assertPred!"=="(monthsToMonth(Month.oct, Month.jan), 3);
+ assertPred!"=="(monthsToMonth(Month.oct, Month.feb), 4);
+ assertPred!"=="(monthsToMonth(Month.oct, Month.mar), 5);
+ assertPred!"=="(monthsToMonth(Month.oct, Month.apr), 6);
+ assertPred!"=="(monthsToMonth(Month.oct, Month.may), 7);
+ assertPred!"=="(monthsToMonth(Month.oct, Month.jun), 8);
+ assertPred!"=="(monthsToMonth(Month.oct, Month.jul), 9);
+ assertPred!"=="(monthsToMonth(Month.oct, Month.aug), 10);
+ assertPred!"=="(monthsToMonth(Month.oct, Month.sep), 11);
+ assertPred!"=="(monthsToMonth(Month.oct, Month.oct), 0);
+ assertPred!"=="(monthsToMonth(Month.oct, Month.nov), 1);
+ assertPred!"=="(monthsToMonth(Month.oct, Month.dec), 2);
+
+ assertPred!"=="(monthsToMonth(Month.dec, Month.jan), 1);
+ assertPred!"=="(monthsToMonth(Month.dec, Month.feb), 2);
+ assertPred!"=="(monthsToMonth(Month.dec, Month.mar), 3);
+ assertPred!"=="(monthsToMonth(Month.dec, Month.apr), 4);
+ assertPred!"=="(monthsToMonth(Month.dec, Month.may), 5);
+ assertPred!"=="(monthsToMonth(Month.dec, Month.jun), 6);
+ assertPred!"=="(monthsToMonth(Month.dec, Month.jul), 7);
+ assertPred!"=="(monthsToMonth(Month.dec, Month.aug), 8);
+ assertPred!"=="(monthsToMonth(Month.dec, Month.sep), 9);
+ assertPred!"=="(monthsToMonth(Month.dec, Month.oct), 10);
+ assertPred!"=="(monthsToMonth(Month.dec, Month.nov), 11);
+ assertPred!"=="(monthsToMonth(Month.dec, Month.dec), 0);
+}
+
+
+/++
+ Returns the number of days from the current day of the week to the given
+ day of the week. If they are the same, then the result is 0.
+
+ Params:
+ currDoW = The current day of the week.
+ dow = The day of the week to get the number of days to.
+ +/
+static int daysToDayOfWeek(DayOfWeek currDoW, DayOfWeek dow) pure nothrow
+{
+ if(currDoW == dow)
+ return 0;
+
+ if(currDoW < dow)
+ return dow - currDoW;
+
+ return (DayOfWeek.sat - currDoW) + dow + 1;
+}
+
+unittest
+{
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.sun), 0);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.mon), 1);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.tue), 2);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.wed), 3);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.thu), 4);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.fri), 5);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.sat), 6);
+
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sun), 6);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.mon), 0);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.tue), 1);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.wed), 2);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.thu), 3);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.fri), 4);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sat), 5);
+
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.sun), 5);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.mon), 6);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.tue), 0);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.wed), 1);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.thu), 2);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.fri), 3);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.sat), 4);
+
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.sun), 4);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.mon), 5);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.tue), 6);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.wed), 0);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.thu), 1);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.fri), 2);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.sat), 3);
+
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.sun), 3);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.mon), 4);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.tue), 5);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.wed), 6);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.thu), 0);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.fri), 1);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.sat), 2);
+
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.sun), 2);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.mon), 3);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.tue), 4);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.wed), 5);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.thu), 6);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.fri), 0);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.sat), 1);
+
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.sun), 1);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.mon), 2);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.tue), 3);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.wed), 4);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.thu), 5);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.fri), 6);
+ assertPred!"=="(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.sat), 0);
+}
+
+
+//This should be removed as soon the bug with auto return functions not
+//showing up in the documentation generated by ddoc is fixed.
+version(D_Ddoc)
+{
+ //Here purely to make it so that TemporaryValue is defined and will compile.
+ alias long TemporaryValue;
+
+ /++
+ Function for starting to a stop watch time when the function is called
+ and stopping it when its return value goes out of scope and is destroyed.
+
+ When the value that is returned by this function is destroyed,
+ $(D func()) will run. $(D func()) is a unary function that takes a
+ TickDuration.
+
+ Examples:
+--------------------
+writeln("benchmark start!");
+{
+auto mt = measureTime!((a){assert(a.seconds);});
+doSomething();
+}
+writeln("benchmark end!");
+--------------------
+ +/
TemporaryValue measureTime(alias func)();
-
-
- // for -unittest -D
- alias void* TemporaryValue;
}
else
{
@safe
{
auto measureTime(alias func)()
- if (isSafe!func)
+ if(isSafe!func)
{
struct TMP
{
@@ -969,7 +31029,7 @@ else
return TMP(autoStart);
}
}
-
+
@system
{
auto measureTime(alias func)()
@@ -992,12 +31052,11 @@ else
}
}
-
@system
unittest
{
{
- auto mt = measureTime!((a){assert(a.seconds <>= 0);});
+ auto mt = measureTime!((a){assert(a.to!("seconds", real) <>= 0);});
}
/+
@@ -1008,3 +31067,1763 @@ unittest
}
+/
}
+
+
+//==============================================================================
+// Private Section.
+//
+// Note that the templates in the private section are documented but do _not_
+// have both +'s to begin their documentation comment blocks. This is because
+// of bug 2775 ( http://d.puremagic.com/issues/show_bug.cgi?id=2775 ) which
+// makes it so that all templates are actually public. Ideally, most (if not all)
+// of these templates would be inside of isTimePoint, but bug 4675
+// ( http://d.puremagic.com/issues/show_bug.cgi?id=4675 ) which currently prevents
+// putting more that the enum with the template's name inside of an eponymous
+// template.
+//==============================================================================
+private:
+
+
+//==============================================================================
+// Section with private enums and constants.
+//==============================================================================
+
+enum daysInYear = 365; /// The number of days in a non-leap year.
+enum daysInLeapYear = 366; /// The numbef or days in a leap year.
+enum daysIn4Years = daysInYear * 3 + daysInLeapYear; /// Number of days in 4 years.
+enum daysIn100Years = daysIn4Years * 25 - 1; /// The number of days in 100 years.
+enum daysIn400Years = daysIn100Years * 4 + 1; /// The number of days in 400 years.
+
+
+//==============================================================================
+// Section with private helper functions and templates.
+//==============================================================================
+
+/+
+ Template to help with converting between time units.
+ +/
+template hnsecsPer(string units)
+ if(CmpTimeUnits!(units, "months") < 0)
+{
+ static if(units == "hnsecs")
+ enum hnsecsPer = 1L;
+ else static if(units == "usecs")
+ enum hnsecsPer = 10L;
+ else static if(units == "msecs")
+ enum hnsecsPer = 1000 * hnsecsPer!"usecs";
+ else static if(units == "seconds")
+ enum hnsecsPer = 1000 * hnsecsPer!"msecs";
+ else static if(units == "minutes")
+ enum hnsecsPer = 60 * hnsecsPer!"seconds";
+ else static if(units == "hours")
+ enum hnsecsPer = 60 * hnsecsPer!"minutes";
+ else static if(units == "days")
+ enum hnsecsPer = 24 * hnsecsPer!"hours";
+ else static if(units == "weeks")
+ enum hnsecsPer = 7 * hnsecsPer!"days";
+}
+
+
+/+
+ Splits out a particular unit from hnsecs and gives you the value for that
+ unit and the remaining hnsecs. It really shouldn't be used unless unless
+ all units larger than the given units have already been split out.
+
+ Params:
+ units = The units to split out.
+ hnsecs = The current total hnsecs. Upon returning, it is the hnsecs left
+ after splitting out the given units.
+
+ Returns:
+ The number of the given units from converting hnsecs to those units.
+
+ Examples:
+--------------------
+auto hnsecs = 2595000000007L;
+immutable days = splitUnitsFromHNSecs!"days"(hnsecs);
+assert(days == 3);
+assert(hnsecs == 3000000007);
+
+immutable minutes = splitUnitsFromHNSecs!"minutes"(hnsecs);
+assert(minutes == 5);
+assert(hnsecs == 7);
+--------------------
+ +/
+long splitUnitsFromHNSecs(string units)(ref long hnsecs) pure nothrow
+ if(validTimeUnits(units) &&
+ CmpTimeUnits!(units, "months") < 0)
+{
+ immutable value = convert!("hnsecs", units)(hnsecs);
+ hnsecs -= convert!(units, "hnsecs")(value);
+
+ return value;
+}
+
+unittest
+{
+ //Verify Example.
+ auto hnsecs = 2595000000007L;
+ immutable days = splitUnitsFromHNSecs!"days"(hnsecs);
+ assert(days == 3);
+ assert(hnsecs == 3000000007);
+
+ immutable minutes = splitUnitsFromHNSecs!"minutes"(hnsecs);
+ assert(minutes == 5);
+ assert(hnsecs == 7);
+}
+
+
+/+
+ This function is used to split out the units without getting the remaining
+ hnsecs.
+
+ See_Also:
+ splitUnitsFromHNSecs()
+
+ Params:
+ units = The units to split out.
+ hnsecs = The current total hnsecs.
+
+ Returns:
+ The split out value.
+
+ Examples:
+--------------------
+auto hnsecs = 2595000000007L;
+immutable days = getUnitsFromHNSecs!"days"(hnsecs);
+assert(days == 3);
+assert(hnsecs == 2595000000007L);
+--------------------
+ +/
+long getUnitsFromHNSecs(string units)(long hnsecs) pure nothrow
+ if(validTimeUnits(units) &&
+ CmpTimeUnits!(units, "months") < 0)
+{
+ return convert!("hnsecs", units)(hnsecs);
+}
+
+unittest
+{
+ //Verify Example.
+ auto hnsecs = 2595000000007L;
+ immutable days = getUnitsFromHNSecs!"days"(hnsecs);
+ assert(days == 3);
+ assert(hnsecs == 2595000000007L);
+}
+
+
+/+
+ This function is used to split out the units without getting the units but
+ just the remaining hnsecs.
+
+ See_Also:
+ splitUnitsFromHNSecs()
+
+ Params:
+ units = The units to split out.
+ hnsecs = The current total hnsecs.
+
+ Returns:
+ The remaining hnsecs.
+
+ Examples:
+--------------------
+auto hnsecs = 2595000000007L;
+auto returned = removeUnitsFromHNSecs!"days"(hnsecs);
+assert(returned == 3000000007);
+assert(hnsecs == 2595000000007L);
+--------------------
+ +/
+long removeUnitsFromHNSecs(string units)(long hnsecs) pure nothrow
+ if(validTimeUnits(units) &&
+ CmpTimeUnits!(units, "months") < 0)
+{
+ immutable value = convert!("hnsecs", units)(hnsecs);
+
+ return hnsecs - convert!(units, "hnsecs")(value);
+}
+
+unittest
+{
+ //Verify Example.
+ auto hnsecs = 2595000000007L;
+ auto returned = removeUnitsFromHNSecs!"days"(hnsecs);
+ assert(returned == 3000000007);
+ assert(hnsecs == 2595000000007L);
+}
+
+
+/+
+ The maximum valid Day in the given month in the given year.
+
+ Params:
+ year = The year to get the day for.
+ month = The month of the Gregorian Calendar to get the day for.
+ +/
+static ubyte maxDay(int year, int month) pure nothrow
+in
+{
+ assert(valid!"months"(month));
+}
+body
+{
+ switch(month)
+ {
+ case Month.jan, Month.mar, Month.may, Month.jul, Month.aug, Month.oct, Month.dec:
+ return 31;
+ case Month.feb:
+ return yearIsLeapYear(year) ? 29 : 28;
+ case Month.apr, Month.jun, Month.sep, Month.nov:
+ return 30;
+ default:
+ assert(0, "Invalid month.");
+ }
+}
+
+unittest
+{
+ //Test A.D.
+ assertPred!"=="(maxDay(1999, 1), 31);
+ assertPred!"=="(maxDay(1999, 2), 28);
+ assertPred!"=="(maxDay(1999, 3), 31);
+ assertPred!"=="(maxDay(1999, 4), 30);
+ assertPred!"=="(maxDay(1999, 5), 31);
+ assertPred!"=="(maxDay(1999, 6), 30);
+ assertPred!"=="(maxDay(1999, 7), 31);
+ assertPred!"=="(maxDay(1999, 8), 31);
+ assertPred!"=="(maxDay(1999, 9), 30);
+ assertPred!"=="(maxDay(1999, 10), 31);
+ assertPred!"=="(maxDay(1999, 11), 30);
+ assertPred!"=="(maxDay(1999, 12), 31);
+
+ assertPred!"=="(maxDay(2000, 1), 31);
+ assertPred!"=="(maxDay(2000, 2), 29);
+ assertPred!"=="(maxDay(2000, 3), 31);
+ assertPred!"=="(maxDay(2000, 4), 30);
+ assertPred!"=="(maxDay(2000, 5), 31);
+ assertPred!"=="(maxDay(2000, 6), 30);
+ assertPred!"=="(maxDay(2000, 7), 31);
+ assertPred!"=="(maxDay(2000, 8), 31);
+ assertPred!"=="(maxDay(2000, 9), 30);
+ assertPred!"=="(maxDay(2000, 10), 31);
+ assertPred!"=="(maxDay(2000, 11), 30);
+ assertPred!"=="(maxDay(2000, 12), 31);
+
+ //Test B.C.
+ assertPred!"=="(maxDay(-1999, 1), 31);
+ assertPred!"=="(maxDay(-1999, 2), 28);
+ assertPred!"=="(maxDay(-1999, 3), 31);
+ assertPred!"=="(maxDay(-1999, 4), 30);
+ assertPred!"=="(maxDay(-1999, 5), 31);
+ assertPred!"=="(maxDay(-1999, 6), 30);
+ assertPred!"=="(maxDay(-1999, 7), 31);
+ assertPred!"=="(maxDay(-1999, 8), 31);
+ assertPred!"=="(maxDay(-1999, 9), 30);
+ assertPred!"=="(maxDay(-1999, 10), 31);
+ assertPred!"=="(maxDay(-1999, 11), 30);
+ assertPred!"=="(maxDay(-1999, 12), 31);
+
+ assertPred!"=="(maxDay(-2000, 1), 31);
+ assertPred!"=="(maxDay(-2000, 2), 29);
+ assertPred!"=="(maxDay(-2000, 3), 31);
+ assertPred!"=="(maxDay(-2000, 4), 30);
+ assertPred!"=="(maxDay(-2000, 5), 31);
+ assertPred!"=="(maxDay(-2000, 6), 30);
+ assertPred!"=="(maxDay(-2000, 7), 31);
+ assertPred!"=="(maxDay(-2000, 8), 31);
+ assertPred!"=="(maxDay(-2000, 9), 30);
+ assertPred!"=="(maxDay(-2000, 10), 31);
+ assertPred!"=="(maxDay(-2000, 11), 30);
+ assertPred!"=="(maxDay(-2000, 12), 31);
+}
+
+
+/+
+ Returns the day of the week for the given day of the Gregorian Calendar.
+
+ Params:
+ day = The day of the Gregorian Calendar for which to get the day of
+ the week.
+ +/
+DayOfWeek getDayOfWeek(int day) pure nothrow
+{
+ //January 1st, 1 A.D. was a Monday
+ if(day >= 0)
+ return cast(DayOfWeek)(day % 7);
+ else
+ {
+ immutable dow = cast(DayOfWeek)((day % 7) + 7);
+
+ if(dow == 7)
+ return DayOfWeek.sun;
+ else
+ return dow;
+ }
+}
+
+unittest
+{
+ //Test A.D.
+ assertPred!"=="(getDayOfWeek(SysTime(Date(1, 1, 1)).dayOfGregorianCal), DayOfWeek.mon);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(1, 1, 2)).dayOfGregorianCal), DayOfWeek.tue);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(1, 1, 3)).dayOfGregorianCal), DayOfWeek.wed);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(1, 1, 4)).dayOfGregorianCal), DayOfWeek.thu);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(1, 1, 5)).dayOfGregorianCal), DayOfWeek.fri);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(1, 1, 6)).dayOfGregorianCal), DayOfWeek.sat);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(1, 1, 7)).dayOfGregorianCal), DayOfWeek.sun);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(1, 1, 8)).dayOfGregorianCal), DayOfWeek.mon);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(1, 1, 9)).dayOfGregorianCal), DayOfWeek.tue);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(2, 1, 1)).dayOfGregorianCal), DayOfWeek.tue);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(3, 1, 1)).dayOfGregorianCal), DayOfWeek.wed);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(4, 1, 1)).dayOfGregorianCal), DayOfWeek.thu);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(5, 1, 1)).dayOfGregorianCal), DayOfWeek.sat);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(2000, 1, 1)).dayOfGregorianCal), DayOfWeek.sat);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(2010, 8, 22)).dayOfGregorianCal), DayOfWeek.sun);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(2010, 8, 23)).dayOfGregorianCal), DayOfWeek.mon);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(2010, 8, 24)).dayOfGregorianCal), DayOfWeek.tue);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(2010, 8, 25)).dayOfGregorianCal), DayOfWeek.wed);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(2010, 8, 26)).dayOfGregorianCal), DayOfWeek.thu);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(2010, 8, 27)).dayOfGregorianCal), DayOfWeek.fri);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(2010, 8, 28)).dayOfGregorianCal), DayOfWeek.sat);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(2010, 8, 29)).dayOfGregorianCal), DayOfWeek.sun);
+
+ //Test B.C.
+ assertPred!"=="(getDayOfWeek(SysTime(Date(0, 12, 31)).dayOfGregorianCal), DayOfWeek.sun);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(0, 12, 30)).dayOfGregorianCal), DayOfWeek.sat);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(0, 12, 29)).dayOfGregorianCal), DayOfWeek.fri);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(0, 12, 28)).dayOfGregorianCal), DayOfWeek.thu);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(0, 12, 27)).dayOfGregorianCal), DayOfWeek.wed);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(0, 12, 26)).dayOfGregorianCal), DayOfWeek.tue);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(0, 12, 25)).dayOfGregorianCal), DayOfWeek.mon);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(0, 12, 24)).dayOfGregorianCal), DayOfWeek.sun);
+ assertPred!"=="(getDayOfWeek(SysTime(Date(0, 12, 23)).dayOfGregorianCal), DayOfWeek.sat);
+}
+
+
+/++
+ Returns the string representation of the given month.
+
+ Params:
+ useLongName = Whether the long or short version of the month name should
+ be used.
+ plural = Whether the string should be plural or not.
+
+ Throws:
+ DateTimeException if the given month is not a valid month.
+ +/
+string monthToString(Month month, bool useLongName = true) pure
+{
+ if(useLongName == true)
+ {
+ switch(month)
+ {
+ case Month.jan:
+ return "January";
+ case Month.feb:
+ return "February";
+ case Month.mar:
+ return "March";
+ case Month.apr:
+ return "April";
+ case Month.may:
+ return "May";
+ case Month.jun:
+ return "June";
+ case Month.jul:
+ return "July";
+ case Month.aug:
+ return "August";
+ case Month.sep:
+ return "September";
+ case Month.oct:
+ return "October";
+ case Month.nov:
+ return "November";
+ case Month.dec:
+ return "December";
+ default:
+ throw new DateTimeException("Invalid month: " ~ numToString(month));
+ }
+ }
+ else
+ {
+ switch(month)
+ {
+ case Month.jan:
+ return "Jan";
+ case Month.feb:
+ return "Feb";
+ case Month.mar:
+ return "Mar";
+ case Month.apr:
+ return "Apr";
+ case Month.may:
+ return "May";
+ case Month.jun:
+ return "Jun";
+ case Month.jul:
+ return "Jul";
+ case Month.aug:
+ return "Aug";
+ case Month.sep:
+ return "Sep";
+ case Month.oct:
+ return "Oct";
+ case Month.nov:
+ return "Nov";
+ case Month.dec:
+ return "Dec";
+ default:
+ throw new DateTimeException("Invalid month: " ~ numToString(month));
+ }
+ }
+}
+
+unittest
+{
+ static void testMTSInvalid(Month month, bool useLongName)
+ {
+ monthToString(month, useLongName);
+ }
+
+ assertThrown!DateTimeException(testMTSInvalid(cast(Month)0, true));
+ assertThrown!DateTimeException(testMTSInvalid(cast(Month)0, false));
+ assertThrown!DateTimeException(testMTSInvalid(cast(Month)13, true));
+ assertThrown!DateTimeException(testMTSInvalid(cast(Month)13, false));
+
+ assertPred!"=="(monthToString(Month.jan), "January");
+ assertPred!"=="(monthToString(Month.feb), "February");
+ assertPred!"=="(monthToString(Month.mar), "March");
+ assertPred!"=="(monthToString(Month.apr), "April");
+ assertPred!"=="(monthToString(Month.may), "May");
+ assertPred!"=="(monthToString(Month.jun), "June");
+ assertPred!"=="(monthToString(Month.jul), "July");
+ assertPred!"=="(monthToString(Month.aug), "August");
+ assertPred!"=="(monthToString(Month.sep), "September");
+ assertPred!"=="(monthToString(Month.oct), "October");
+ assertPred!"=="(monthToString(Month.nov), "November");
+ assertPred!"=="(monthToString(Month.dec), "December");
+
+ assertPred!"=="(monthToString(Month.jan, false), "Jan");
+ assertPred!"=="(monthToString(Month.feb, false), "Feb");
+ assertPred!"=="(monthToString(Month.mar, false), "Mar");
+ assertPred!"=="(monthToString(Month.apr, false), "Apr");
+ assertPred!"=="(monthToString(Month.may, false), "May");
+ assertPred!"=="(monthToString(Month.jun, false), "Jun");
+ assertPred!"=="(monthToString(Month.jul, false), "Jul");
+ assertPred!"=="(monthToString(Month.aug, false), "Aug");
+ assertPred!"=="(monthToString(Month.sep, false), "Sep");
+ assertPred!"=="(monthToString(Month.oct, false), "Oct");
+ assertPred!"=="(monthToString(Month.nov, false), "Nov");
+ assertPred!"=="(monthToString(Month.dec, false), "Dec");
+}
+
+
+/++
+ Returns the Month corresponding to the given string. Casing is ignored.
+
+ Params:
+ monthStr = The string representation of the month to get the Month for.
+
+ Throws:
+ DateTimeException if the given month is not a valid month string.
+ +/
+Month monthFromString(string monthStr)
+{
+ switch(tolower(monthStr))
+ {
+ case "january":
+ case "jan":
+ return Month.jan;
+ case "february":
+ case "feb":
+ return Month.feb;
+ case "march":
+ case "mar":
+ return Month.mar;
+ case "april":
+ case "apr":
+ return Month.apr;
+ case "may":
+ return Month.may;
+ case "june":
+ case "jun":
+ return Month.jun;
+ case "july":
+ case "jul":
+ return Month.jul;
+ case "august":
+ case "aug":
+ return Month.aug;
+ case "september":
+ case "sep":
+ return Month.sep;
+ case "october":
+ case "oct":
+ return Month.oct;
+ case "november":
+ case "nov":
+ return Month.nov;
+ case "december":
+ case "dec":
+ return Month.dec;
+ default:
+ throw new DateTimeException(format("Invalid month %s", monthStr));
+ }
+}
+
+unittest
+{
+ static void testMFSInvalid(string monthStr)
+ {
+ monthFromString(monthStr);
+ }
+
+ assertThrown!DateTimeException(testMFSInvalid("Ja"));
+ assertThrown!DateTimeException(testMFSInvalid("Janu"));
+ assertThrown!DateTimeException(testMFSInvalid("Januar"));
+ assertThrown!DateTimeException(testMFSInvalid("Januarys"));
+ assertThrown!DateTimeException(testMFSInvalid("JJanuary"));
+
+ assertPred!"=="(monthFromString(monthToString(Month.jan)), Month.jan);
+ assertPred!"=="(monthFromString(monthToString(Month.feb)), Month.feb);
+ assertPred!"=="(monthFromString(monthToString(Month.mar)), Month.mar);
+ assertPred!"=="(monthFromString(monthToString(Month.apr)), Month.apr);
+ assertPred!"=="(monthFromString(monthToString(Month.may)), Month.may);
+ assertPred!"=="(monthFromString(monthToString(Month.jun)), Month.jun);
+ assertPred!"=="(monthFromString(monthToString(Month.jul)), Month.jul);
+ assertPred!"=="(monthFromString(monthToString(Month.aug)), Month.aug);
+ assertPred!"=="(monthFromString(monthToString(Month.sep)), Month.sep);
+ assertPred!"=="(monthFromString(monthToString(Month.oct)), Month.oct);
+ assertPred!"=="(monthFromString(monthToString(Month.nov)), Month.nov);
+ assertPred!"=="(monthFromString(monthToString(Month.dec)), Month.dec);
+
+ assertPred!"=="(monthFromString(monthToString(Month.jan, false)), Month.jan);
+ assertPred!"=="(monthFromString(monthToString(Month.feb, false)), Month.feb);
+ assertPred!"=="(monthFromString(monthToString(Month.mar, false)), Month.mar);
+ assertPred!"=="(monthFromString(monthToString(Month.apr, false)), Month.apr);
+ assertPred!"=="(monthFromString(monthToString(Month.may, false)), Month.may);
+ assertPred!"=="(monthFromString(monthToString(Month.jun, false)), Month.jun);
+ assertPred!"=="(monthFromString(monthToString(Month.jul, false)), Month.jul);
+ assertPred!"=="(monthFromString(monthToString(Month.aug, false)), Month.aug);
+ assertPred!"=="(monthFromString(monthToString(Month.sep, false)), Month.sep);
+ assertPred!"=="(monthFromString(monthToString(Month.oct, false)), Month.oct);
+ assertPred!"=="(monthFromString(monthToString(Month.nov, false)), Month.nov);
+ assertPred!"=="(monthFromString(monthToString(Month.dec, false)), Month.dec);
+
+ assertPred!"=="(monthFromString("JANUARY"), Month.jan);
+ assertPred!"=="(monthFromString("JAN"), Month.jan);
+ assertPred!"=="(monthFromString("january"), Month.jan);
+ assertPred!"=="(monthFromString("jan"), Month.jan);
+ assertPred!"=="(monthFromString("jaNuary"), Month.jan);
+ assertPred!"=="(monthFromString("jaN"), Month.jan);
+ assertPred!"=="(monthFromString("jaNuaRy"), Month.jan);
+ assertPred!"=="(monthFromString("jAn"), Month.jan);
+}
+
+
+/+
+ The time units which are one step smaller than the given units.
+
+ Examples:
+--------------------
+assert(nextSmallerTimeUnits!"years" == "months");
+assert(nextSmallerTimeUnits!"usecs" == "hnsecs");
+--------------------
+ +/
+template nextSmallerTimeUnits(string units)
+ if(validTimeUnits(units) &&
+ timeStrings.front != units)
+{
+ enum nextSmallerTimeUnits = timeStrings[std.algorithm.indexOf(timeStrings.dup, units) - 1];
+}
+
+unittest
+{
+ assertPred!"=="(nextSmallerTimeUnits!"months", "weeks");
+ assertPred!"=="(nextSmallerTimeUnits!"weeks", "days");
+ assertPred!"=="(nextSmallerTimeUnits!"days", "hours");
+ assertPred!"=="(nextSmallerTimeUnits!"hours", "minutes");
+ assertPred!"=="(nextSmallerTimeUnits!"minutes", "seconds");
+ assertPred!"=="(nextSmallerTimeUnits!"seconds", "msecs");
+ assertPred!"=="(nextSmallerTimeUnits!"msecs", "usecs");
+
+ static assert(!__traits(compiles, nextSmallerTimeUnits!"hnsecs"));
+
+ //Verify Examples
+ assert(nextSmallerTimeUnits!"years" == "months");
+ assert(nextSmallerTimeUnits!"usecs" == "hnsecs");
+}
+
+
+/+
+ The time units which are one step larger than the given units.
+
+ Examples:
+--------------------
+assert(nextLargerTimeUnits!"months" == "years");
+assert(nextLargerTimeUnits!"hnsecs" == "usecs");
+--------------------
+ +/
+template nextLargerTimeUnits(string units)
+ if(validTimeUnits(units) &&
+ timeStrings.back != units)
+{
+ enum nextLargerTimeUnits = timeStrings[std.algorithm.indexOf(timeStrings.dup, units) + 1];
+}
+
+unittest
+{
+ assertPred!"=="(nextLargerTimeUnits!"usecs", "msecs");
+ assertPred!"=="(nextLargerTimeUnits!"msecs", "seconds");
+ assertPred!"=="(nextLargerTimeUnits!"seconds", "minutes");
+ assertPred!"=="(nextLargerTimeUnits!"minutes", "hours");
+ assertPred!"=="(nextLargerTimeUnits!"hours", "days");
+ assertPred!"=="(nextLargerTimeUnits!"days", "weeks");
+ assertPred!"=="(nextLargerTimeUnits!"weeks", "months");
+
+ static assert(!__traits(compiles, nextLargerTimeUnits!"years"));
+
+ //Verify Examples
+ assert(nextLargerTimeUnits!"months" == "years");
+ assert(nextLargerTimeUnits!"hnsecs" == "usecs");
+}
+
+
+/++
+ Returns the given hnsecs as an ISO string of fractional seconds.
+ +/
+static string fracSecToISOString(int hnsecs) nothrow
+in
+{
+ assert(hnsecs >= 0);
+}
+body
+{
+ try
+ {
+ string isoString = format(".%07d", hnsecs);
+
+ while(isoString.endsWith("0"))
+ isoString.popBack();
+
+ if(isoString.length == 1)
+ return "";
+
+ return isoString;
+ }
+ catch(Exception e)
+ assert(0, "format() threw.");
+}
+
+unittest
+{
+ assertPred!"=="(fracSecToISOString(0), "");
+ assertPred!"=="(fracSecToISOString(1), ".0000001");
+ assertPred!"=="(fracSecToISOString(10), ".000001");
+ assertPred!"=="(fracSecToISOString(100), ".00001");
+ assertPred!"=="(fracSecToISOString(1000), ".0001");
+ assertPred!"=="(fracSecToISOString(10_000), ".001");
+ assertPred!"=="(fracSecToISOString(100_000), ".01");
+ assertPred!"=="(fracSecToISOString(1_000_000), ".1");
+ assertPred!"=="(fracSecToISOString(1_000_001), ".1000001");
+ assertPred!"=="(fracSecToISOString(1_001_001), ".1001001");
+ assertPred!"=="(fracSecToISOString(1_071_601), ".1071601");
+ assertPred!"=="(fracSecToISOString(1_271_641), ".1271641");
+ assertPred!"=="(fracSecToISOString(9_999_999), ".9999999");
+ assertPred!"=="(fracSecToISOString(9_999_990), ".999999");
+ assertPred!"=="(fracSecToISOString(9_999_900), ".99999");
+ assertPred!"=="(fracSecToISOString(9_999_000), ".9999");
+ assertPred!"=="(fracSecToISOString(9_990_000), ".999");
+ assertPred!"=="(fracSecToISOString(9_900_000), ".99");
+ assertPred!"=="(fracSecToISOString(9_000_000), ".9");
+ assertPred!"=="(fracSecToISOString(999), ".0000999");
+ assertPred!"=="(fracSecToISOString(9990), ".000999");
+ assertPred!"=="(fracSecToISOString(99_900), ".00999");
+ assertPred!"=="(fracSecToISOString(999_000), ".0999");
+}
+
+
+/++
+ Returns a FracSec corresponding to to the given ISO string of
+ fractional seconds.
+ +/
+static FracSec fracSecFromISOString(S)(in S isoString)
+ if(isSomeString!S)
+{
+ if(isoString.empty)
+ return FracSec.from!"hnsecs"(0);
+
+ auto dstr = to!dstring(isoString);
+
+ enforce(dstr.startsWith("."), new DateTimeException("Invalid ISO String"));
+ dstr.popFront();
+
+ enforce(!dstr.empty && dstr.length <= 7, new DateTimeException("Invalid ISO String"));
+ enforce(!canFind!((dchar c){return !isdigit(c);})(dstr), new DateTimeException("Invalid ISO String"));
+
+ dchar[7] fullISOString;
+
+ foreach(i, ref dchar c; fullISOString)
+ {
+ if(i < dstr.length)
+ c = dstr[i];
+ else
+ c = '0';
+ }
+
+ return FracSec.from!"hnsecs"(to!int(fullISOString[]));
+}
+
+unittest
+{
+ static void testFSInvalid(string isoString)
+ {
+ fracSecFromISOString(isoString);
+ }
+
+ assertThrown!DateTimeException(testFSInvalid("."));
+ assertThrown!DateTimeException(testFSInvalid("0."));
+ assertThrown!DateTimeException(testFSInvalid("0"));
+ assertThrown!DateTimeException(testFSInvalid("0000000"));
+ assertThrown!DateTimeException(testFSInvalid(".00000000"));
+ assertThrown!DateTimeException(testFSInvalid(".00000001"));
+ assertThrown!DateTimeException(testFSInvalid("T"));
+ assertThrown!DateTimeException(testFSInvalid("T."));
+ assertThrown!DateTimeException(testFSInvalid(".T"));
+
+ assertPred!"=="(fracSecFromISOString(""), FracSec.from!"hnsecs"(0));
+ assertPred!"=="(fracSecFromISOString(".0000001"), FracSec.from!"hnsecs"(1));
+ assertPred!"=="(fracSecFromISOString(".000001"), FracSec.from!"hnsecs"(10));
+ assertPred!"=="(fracSecFromISOString(".00001"), FracSec.from!"hnsecs"(100));
+ assertPred!"=="(fracSecFromISOString(".0001"), FracSec.from!"hnsecs"(1000));
+ assertPred!"=="(fracSecFromISOString(".001"), FracSec.from!"hnsecs"(10_000));
+ assertPred!"=="(fracSecFromISOString(".01"), FracSec.from!"hnsecs"(100_000));
+ assertPred!"=="(fracSecFromISOString(".1"), FracSec.from!"hnsecs"(1_000_000));
+ assertPred!"=="(fracSecFromISOString(".1000001"), FracSec.from!"hnsecs"(1_000_001));
+ assertPred!"=="(fracSecFromISOString(".1001001"), FracSec.from!"hnsecs"(1_001_001));
+ assertPred!"=="(fracSecFromISOString(".1071601"), FracSec.from!"hnsecs"(1_071_601));
+ assertPred!"=="(fracSecFromISOString(".1271641"), FracSec.from!"hnsecs"(1_271_641));
+ assertPred!"=="(fracSecFromISOString(".9999999"), FracSec.from!"hnsecs"(9_999_999));
+ assertPred!"=="(fracSecFromISOString(".9999990"), FracSec.from!"hnsecs"(9_999_990));
+ assertPred!"=="(fracSecFromISOString(".999999"), FracSec.from!"hnsecs"(9_999_990));
+ assertPred!"=="(fracSecFromISOString(".9999900"), FracSec.from!"hnsecs"(9_999_900));
+ assertPred!"=="(fracSecFromISOString(".99999"), FracSec.from!"hnsecs"(9_999_900));
+ assertPred!"=="(fracSecFromISOString(".9999000"), FracSec.from!"hnsecs"(9_999_000));
+ assertPred!"=="(fracSecFromISOString(".9999"), FracSec.from!"hnsecs"(9_999_000));
+ assertPred!"=="(fracSecFromISOString(".9990000"), FracSec.from!"hnsecs"(9_990_000));
+ assertPred!"=="(fracSecFromISOString(".999"), FracSec.from!"hnsecs"(9_990_000));
+ assertPred!"=="(fracSecFromISOString(".9900000"), FracSec.from!"hnsecs"(9_900_000));
+ assertPred!"=="(fracSecFromISOString(".9900"), FracSec.from!"hnsecs"(9_900_000));
+ assertPred!"=="(fracSecFromISOString(".99"), FracSec.from!"hnsecs"(9_900_000));
+ assertPred!"=="(fracSecFromISOString(".9000000"), FracSec.from!"hnsecs"(9_000_000));
+ assertPred!"=="(fracSecFromISOString(".9"), FracSec.from!"hnsecs"(9_000_000));
+ assertPred!"=="(fracSecFromISOString(".0000999"), FracSec.from!"hnsecs"(999));
+ assertPred!"=="(fracSecFromISOString(".0009990"), FracSec.from!"hnsecs"(9990));
+ assertPred!"=="(fracSecFromISOString(".000999"), FracSec.from!"hnsecs"(9990));
+ assertPred!"=="(fracSecFromISOString(".0099900"), FracSec.from!"hnsecs"(99_900));
+ assertPred!"=="(fracSecFromISOString(".00999"), FracSec.from!"hnsecs"(99_900));
+ assertPred!"=="(fracSecFromISOString(".0999000"), FracSec.from!"hnsecs"(999_000));
+ assertPred!"=="(fracSecFromISOString(".0999"), FracSec.from!"hnsecs"(999_000));
+}
+
+
+/+
+ Whether the given type defines the static property min which returns the
+ minimum value for the type.
+ +/
+template hasMin(T)
+{
+ enum hasMin = __traits(hasMember, T, "min") &&
+ __traits(isStaticFunction, T.min) &&
+ is(ReturnType!(T.min) == Unqual!T) &&
+ (functionAttributes!(T.min) & FunctionAttribute.PROPERTY) &&
+ (functionAttributes!(T.min) & FunctionAttribute.NOTHROW);
+ //(functionAttributes!(T.min) & FunctionAttribute.PURE); //Ideally this would be the case, but SysTime's min() can't currently be pure.
+}
+
+unittest
+{
+ static assert(hasMin!(Date));
+ static assert(hasMin!(TimeOfDay));
+ static assert(hasMin!(DateTime));
+ static assert(hasMin!(SysTime));
+ static assert(hasMin!(const Date));
+ static assert(hasMin!(const TimeOfDay));
+ static assert(hasMin!(const DateTime));
+ static assert(hasMin!(const SysTime));
+ static assert(hasMin!(immutable Date));
+ static assert(hasMin!(immutable TimeOfDay));
+ static assert(hasMin!(immutable SysTime));
+}
+
+
+/+
+ Whether the given type defines the static property max which returns the
+ maximum value for the type.
+ +/
+template hasMax(T)
+{
+ enum hasMax = __traits(hasMember, T, "max") &&
+ __traits(isStaticFunction, T.max) &&
+ is(ReturnType!(T.max) == Unqual!T) &&
+ (functionAttributes!(T.max) & FunctionAttribute.PROPERTY) &&
+ (functionAttributes!(T.max) & FunctionAttribute.NOTHROW);
+ //(functionAttributes!(T.max) & FunctionAttribute.PURE); //Ideally this would be the case, but SysTime's max() can't currently be pure.
+}
+
+unittest
+{
+ static assert(hasMax!(Date));
+ static assert(hasMax!(TimeOfDay));
+ static assert(hasMax!(DateTime));
+ static assert(hasMax!(SysTime));
+ static assert(hasMax!(const Date));
+ static assert(hasMax!(const TimeOfDay));
+ static assert(hasMax!(const DateTime));
+ static assert(hasMax!(const SysTime));
+ static assert(hasMax!(immutable Date));
+ static assert(hasMax!(immutable TimeOfDay));
+ static assert(hasMax!(immutable DateTime));
+ static assert(hasMax!(immutable SysTime));
+}
+
+
+/+
+ Whether the given type defines the overloaded opBinary operators that a time
+ point is supposed to define which work with time durations. Namely:
+
+ $(TABLE
+ $(TR $(TD TimePoint opBinary"+"(duration)))
+ $(TR $(TD TimePoint opBinary"-"(duration)))
+ )
+ +/
+template hasOverloadedOpBinaryWithDuration(T)
+{
+ enum hasOverloadedOpBinaryWithDuration = __traits(compiles, T.init + dur!"days"(5)) &&
+ is(typeof(T.init + dur!"days"(5)) == Unqual!T) &&
+ __traits(compiles, T.init - dur!"days"(5)) &&
+ is(typeof(T.init - dur!"days"(5)) == Unqual!T) &&
+ __traits(compiles, T.init + TickDuration.from!"hnsecs"(5)) &&
+ is(typeof(T.init + TickDuration.from!"hnsecs"(5)) == Unqual!T) &&
+ __traits(compiles, T.init - TickDuration.from!"hnsecs"(5)) &&
+ is(typeof(T.init - TickDuration.from!"hnsecs"(5)) == Unqual!T);
+}
+
+unittest
+{
+ static assert(hasOverloadedOpBinaryWithDuration!(Date));
+ static assert(hasOverloadedOpBinaryWithDuration!(TimeOfDay));
+ static assert(hasOverloadedOpBinaryWithDuration!(DateTime));
+ static assert(hasOverloadedOpBinaryWithDuration!(SysTime));
+ static assert(hasOverloadedOpBinaryWithDuration!(const Date));
+ static assert(hasOverloadedOpBinaryWithDuration!(const TimeOfDay));
+ static assert(hasOverloadedOpBinaryWithDuration!(const DateTime));
+ static assert(hasOverloadedOpBinaryWithDuration!(const SysTime));
+ static assert(hasOverloadedOpBinaryWithDuration!(immutable Date));
+ static assert(hasOverloadedOpBinaryWithDuration!(immutable TimeOfDay));
+ static assert(hasOverloadedOpBinaryWithDuration!(immutable DateTime));
+ static assert(hasOverloadedOpBinaryWithDuration!(immutable SysTime));
+}
+
+
+/+
+ Whether the given type defines the overloaded opOpAssign operators that a time point is supposed
+ to define. Namely:
+
+ $(TABLE
+ $(TR $(TD TimePoint opOpAssign"+"(duration)))
+ $(TR $(TD TimePoint opOpAssign"-"(duration)))
+ )
+ +/
+template hasOverloadedOpAssignWithDuration(T)
+{
+ enum hasOverloadedOpAssignWithDuration = __traits(compiles, T.init += dur!"days"(5)) &&
+ is(typeof(T.init += dur!"days"(5)) == Unqual!T) &&
+ __traits(compiles, T.init -= dur!"days"(5)) &&
+ is(typeof(T.init -= dur!"days"(5)) == Unqual!T) &&
+ __traits(compiles, T.init += TickDuration.from!"hnsecs"(5)) &&
+ is(typeof(T.init += TickDuration.from!"hnsecs"(5)) == Unqual!T) &&
+ __traits(compiles, T.init -= TickDuration.from!"hnsecs"(5)) &&
+ is(typeof(T.init -= TickDuration.from!"hnsecs"(5)) == Unqual!T);
+}
+
+unittest
+{
+ static assert(hasOverloadedOpAssignWithDuration!(Date));
+ static assert(hasOverloadedOpAssignWithDuration!(TimeOfDay));
+ static assert(hasOverloadedOpAssignWithDuration!(DateTime));
+ static assert(hasOverloadedOpAssignWithDuration!(SysTime));
+ static assert(hasOverloadedOpAssignWithDuration!(const Date));
+ static assert(hasOverloadedOpAssignWithDuration!(const TimeOfDay));
+ static assert(hasOverloadedOpAssignWithDuration!(const DateTime));
+ static assert(hasOverloadedOpAssignWithDuration!(const SysTime));
+ static assert(hasOverloadedOpAssignWithDuration!(immutable Date));
+ static assert(hasOverloadedOpAssignWithDuration!(immutable TimeOfDay));
+ static assert(hasOverloadedOpAssignWithDuration!(immutable DateTime));
+ static assert(hasOverloadedOpAssignWithDuration!(immutable SysTime));
+}
+
+
+/+
+ Whether the given type defines the overloaded opBinary operator that a time point is supposed
+ to define which works with itself. Namely:
+
+ $(TABLE
+ $(TR $(TD duration opBinary"-"(Date)))
+ )
+ +/
+template hasOverloadedOpBinaryWithSelf(T)
+{
+ enum hasOverloadedOpBinaryWithSelf = __traits(compiles, T.init - T.init) &&
+ is(Unqual!(typeof(T.init - T.init)) == Duration);
+}
+
+unittest
+{
+ static assert(hasOverloadedOpBinaryWithSelf!(Date));
+ static assert(hasOverloadedOpBinaryWithSelf!(TimeOfDay));
+ static assert(hasOverloadedOpBinaryWithSelf!(DateTime));
+ static assert(hasOverloadedOpBinaryWithSelf!(SysTime));
+ static assert(hasOverloadedOpBinaryWithSelf!(const Date));
+ static assert(hasOverloadedOpBinaryWithSelf!(const TimeOfDay));
+ static assert(hasOverloadedOpBinaryWithSelf!(const DateTime));
+ static assert(hasOverloadedOpBinaryWithSelf!(const SysTime));
+ static assert(hasOverloadedOpBinaryWithSelf!(immutable Date));
+ static assert(hasOverloadedOpBinaryWithSelf!(immutable TimeOfDay));
+ static assert(hasOverloadedOpBinaryWithSelf!(immutable DateTime));
+ static assert(hasOverloadedOpBinaryWithSelf!(immutable SysTime));
+}
+
+/++
+ Unfortunately, to!string() is not pure, so here's a way to convert
+ a number to a string which is. Once to!string() is properly pure
+ (like it hopefully will be at some point), this function should
+ be removed in favor of using to!string().
+ +/
+string numToString(long value) pure nothrow
+{
+ try
+ {
+ immutable negative = value < 0;
+ char[25] str;
+ size_t i = str.length;
+
+ if(negative)
+ value = -value;
+
+ while(1)
+ {
+ char digit = cast(char)('0' + value % 10);
+ value /= 10;
+
+ str[--i] = digit;
+ assert(i > 0);
+
+ if(value == 0)
+ break;
+ }
+
+ if(negative)
+ return "-" ~ str[i .. $].idup;
+ else
+ return str[i .. $].idup;
+ }
+ catch(Exception e)
+ assert(0, "Something threw when nothing can throw.");
+}
+
+
+/+
+ A temporary replacement for Rebindable!() until bug http://d.puremagic.com/issues/show_bug.cgi?id=4977
+ is fixed.
+ +/
+template DTRebindable(T) if (is(T == class) || is(T == interface) || isArray!(T))
+{
+ static if(!is(T X == const(U), U) && !is(T X == immutable(U), U))
+ {
+ alias T DTRebindable;
+ }
+ else static if(isArray!(T))
+ {
+ alias const(ElementType!(T))[] DTRebindable;
+ }
+ else
+ {
+ struct DTRebindable
+ {
+ private union
+ {
+ T original;
+ U stripped;
+ }
+
+ void opAssign(T another) pure nothrow
+ {
+ stripped = cast(U) another;
+ }
+
+ void opAssign(DTRebindable another) pure nothrow
+ {
+ stripped = another.stripped;
+ }
+
+ static if(is(T == const U))
+ {
+ // safely assign immutable to const
+ void opAssign(DTRebindable!(immutable U) another) pure nothrow
+ {
+ stripped = another.stripped;
+ }
+ }
+
+ this(T initializer) pure nothrow
+ {
+ opAssign(initializer);
+ }
+
+ @property ref T get() pure nothrow
+ {
+ return original;
+ }
+
+ @property ref T get() const pure nothrow
+ {
+ return original;
+ }
+
+ alias get this;
+
+ T opDot() pure nothrow
+ {
+ return original;
+ }
+
+ T opDot() const pure nothrow
+ {
+ return original;
+ }
+ }
+ }
+}
+
+
+//==============================================================================
+// Unit testing functions.
+//
+// Hopefully a version of these will end up in std.exception soon, and these
+// will be able to be removed. Not all of the functions currently under review
+// are here, just the ones which std.datetime uses.
+//==============================================================================
+
+void assertThrown(T : Throwable = Exception, F)
+ (lazy F funcToCall, string msg = null, string file = __FILE__, size_t line = __LINE__)
+{
+ bool thrown = false;
+
+ try
+ funcToCall();
+ catch(T t)
+ thrown = true;
+
+ if(!thrown)
+ {
+ if(msg.empty)
+ throw new AssertError(format("assertThrown failed: No %s was thrown.", T.stringof), file, line);
+ else
+ throw new AssertError(format("assertThrown failed: No %s was thrown: %s", T.stringof, msg), file, line);
+ }
+}
+
+unittest
+{
+ void throwEx(Throwable t)
+ {
+ throw t;
+ }
+
+ void nothrowEx()
+ {
+ }
+
+ try
+ assertThrown!Exception(throwEx(new Exception("It's an Exception")));
+ catch(AssertError)
+ assert(0);
+
+ try
+ assertThrown!Exception(throwEx(new Exception("It's an Exception")), "It's a message");
+ catch(AssertError)
+ assert(0);
+
+ try
+ assertThrown!AssertError(throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__)));
+ catch(AssertError)
+ assert(0);
+
+ try
+ assertThrown!AssertError(throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__)), "It's a message");
+ catch(AssertError)
+ assert(0);
+
+
+ {
+ bool thrown = false;
+ try
+ assertThrown!Exception(nothrowEx());
+ catch(AssertError)
+ thrown = true;
+
+ assert(thrown);
+ }
+
+ {
+ bool thrown = false;
+ try
+ assertThrown!Exception(nothrowEx(), "It's a message");
+ catch(AssertError)
+ thrown = true;
+
+ assert(thrown);
+ }
+
+ {
+ bool thrown = false;
+ try
+ assertThrown!AssertError(nothrowEx());
+ catch(AssertError)
+ thrown = true;
+
+ assert(thrown);
+ }
+
+ {
+ bool thrown = false;
+ try
+ assertThrown!AssertError(nothrowEx(), "It's a message");
+ catch(AssertError)
+ thrown = true;
+
+ assert(thrown);
+ }
+
+ //Verify Examples.
+ void timeFunc(int hour, int minute, int second)
+ {
+ enforce(hour >= 0 && hour <= 23);
+ enforce(minute >= 0 && minute <= 59);
+ enforce(second >= 0 && second <= 59);
+
+ //...
+ }
+
+ assertThrown!Exception(timeFunc(-1, 15, 30));
+ assertThrown!Exception(timeFunc(12, 60, 30));
+ assertThrown(timeFunc(12, 15, 60)); //Exception is default.
+
+
+ void nameFunc(string name)
+ {
+ enforce(!name.empty);
+ enforce(name.length < 30);
+
+ //...
+ }
+
+ assertThrown(nameFunc(""));
+ assertThrown(nameFunc("1234567890123456789012345678901"));
+
+
+ void assertPlease()
+ {
+ }
+
+ assert(collectExceptionMsg(assertThrown!AssertError(assertPlease())) ==
+ "assertThrown failed: No AssertError was thrown.");
+
+ assert(collectExceptionMsg(assertThrown!AssertError(assertPlease(), "error!")) ==
+ "assertThrown failed: No AssertError was thrown: error!");
+}
+
+
+void assertPred(string op, L, R)
+ (L lhs, R rhs, lazy string msg = null, string file = __FILE__, size_t line = __LINE__)
+ if((op == "<" ||
+ op == "<=" ||
+ op == "==" ||
+ op == "!=" ||
+ op == ">=" ||
+ op == ">") &&
+ __traits(compiles, mixin("lhs " ~ op ~ " rhs")) &&
+ isPrintable!L &&
+ isPrintable!R)
+{
+ immutable result = mixin("lhs " ~ op ~ " rhs");
+
+ if(!result)
+ {
+ if(msg.empty)
+ throw new AssertError(format(`assertPred!"%s" failed: [%s] is not %s [%s].`, op, lhs, op, rhs), file, line);
+ else
+ throw new AssertError(format(`assertPred!"%s" failed: [%s] is not %s [%s]: %s`, op, lhs, op, rhs, msg), file, line);
+ }
+}
+
+unittest
+{
+ struct IntWrapper
+ {
+ int value;
+
+ this(int value)
+ {
+ this.value = value;
+ }
+
+ string toString()
+ {
+ return to!string(value);
+ }
+ }
+
+ //Test ==.
+ assertNotThrown!AssertError(assertPred!"=="(6, 6));
+ assertNotThrown!AssertError(assertPred!"=="(6, 6.0));
+ assertNotThrown!AssertError(assertPred!"=="(IntWrapper(6), IntWrapper(6)));
+
+ assertThrown!AssertError(assertPred!"=="(6, 7));
+ assertThrown!AssertError(assertPred!"=="(6, 6.1));
+ assertThrown!AssertError(assertPred!"=="(IntWrapper(6), IntWrapper(7)));
+ assertThrown!AssertError(assertPred!"=="(IntWrapper(7), IntWrapper(6)));
+
+ assertPred!"=="(collectExceptionMsg(assertPred!"=="(6, 7)),
+ `assertPred!"==" failed: [6] is not == [7].`);
+ assertPred!"=="(collectExceptionMsg(assertPred!"=="(6, 7, "It failed!")),
+ `assertPred!"==" failed: [6] is not == [7]: It failed!`);
+
+ //Test !=.
+ assertNotThrown!AssertError(assertPred!"!="(6, 7));
+ assertNotThrown!AssertError(assertPred!"!="(6, 6.1));
+ assertNotThrown!AssertError(assertPred!"!="(IntWrapper(6), IntWrapper(7)));
+ assertNotThrown!AssertError(assertPred!"!="(IntWrapper(7), IntWrapper(6)));
+
+ assertThrown!AssertError(assertPred!"!="(6, 6));
+ assertThrown!AssertError(assertPred!"!="(6, 6.0));
+ assertThrown!AssertError(assertPred!"!="(IntWrapper(6), IntWrapper(6)));
+
+ assertPred!"=="(collectExceptionMsg(assertPred!"!="(6, 6)),
+ `assertPred!"!=" failed: [6] is not != [6].`);
+ assertPred!"=="(collectExceptionMsg(assertPred!"!="(6, 6, "It failed!")),
+ `assertPred!"!=" failed: [6] is not != [6]: It failed!`);
+
+ //Test <, <=, >=, >.
+ assertNotThrown!AssertError(assertPred!"<"(5, 7));
+ assertNotThrown!AssertError(assertPred!"<="(5, 7));
+ assertNotThrown!AssertError(assertPred!"<="(5, 5));
+ assertNotThrown!AssertError(assertPred!">="(7, 7));
+ assertNotThrown!AssertError(assertPred!">="(7, 5));
+ assertNotThrown!AssertError(assertPred!">"(7, 5));
+
+ assertThrown!AssertError(assertPred!"<"(7, 5));
+ assertThrown!AssertError(assertPred!"<="(7, 5));
+ assertThrown!AssertError(assertPred!">="(5, 7));
+ assertThrown!AssertError(assertPred!">"(5, 7));
+
+ assertPred!"=="(collectExceptionMsg(assertPred!"<"(7, 5)),
+ `assertPred!"<" failed: [7] is not < [5].`);
+ assertPred!"=="(collectExceptionMsg(assertPred!"<"(7, 5, "It failed!")),
+ `assertPred!"<" failed: [7] is not < [5]: It failed!`);
+
+ //Verify Examples.
+
+ //Equivalent to assert(5 / 2 + 4 < 27);
+ assertPred!"<"(5 / 2 + 4, 27);
+
+ //Equivalent to assert(4 <= 5);
+ assertPred!"<="(4, 5);
+
+ //Equivalent to assert(1 * 2.1 == 2.1);
+ assertPred!"=="(1 * 2.1, 2.1);
+
+ //Equivalent to assert("hello " ~ "world" != "goodbye world");
+ assertPred!"!="("hello " ~ "world", "goodbye world");
+
+ //Equivalent to assert(14.2 >= 14);
+ assertPred!">="(14.2, 14);
+
+ //Equivalent to assert(15 > 2 + 1);
+ assertPred!">"(15, 2 + 1);
+
+ assert(collectExceptionMsg(assertPred!"=="("hello", "goodbye")) ==
+ `assertPred!"==" failed: [hello] is not == [goodbye].`);
+
+ assert(collectExceptionMsg(assertPred!"<"(5, 2, "My test failed!")) ==
+ `assertPred!"<" failed: [5] is not < [2]: My test failed!`);
+}
+
+
+void assertNotThrown(T : Throwable = Exception, F)
+ (lazy F funcToCall, string msg = null, string file = __FILE__, size_t line = __LINE__)
+{
+ try
+ funcToCall();
+ catch(T t)
+ {
+ if(msg.empty)
+ throw new AssertError(format("assertNotThrown failed: %s was thrown.", T.stringof), file, line);
+ else
+ throw new AssertError(format("assertNotThrown failed: %s was thrown: %s", T.stringof, msg), file, line);
+ }
+}
+
+unittest
+{
+ void throwEx(Throwable t)
+ {
+ throw t;
+ }
+
+ void nothrowEx()
+ {
+ }
+
+ try
+ assertNotThrown!Exception(nothrowEx());
+ catch(AssertError)
+ assert(0);
+
+ try
+ assertNotThrown!Exception(nothrowEx(), "It's a message");
+ catch(AssertError)
+ assert(0);
+
+ try
+ assertNotThrown!AssertError(nothrowEx());
+ catch(AssertError)
+ assert(0);
+
+ try
+ assertNotThrown!AssertError(nothrowEx(), "It's a message");
+ catch(AssertError)
+ assert(0);
+
+
+ {
+ bool thrown = false;
+ try
+ assertNotThrown!Exception(throwEx(new Exception("It's an Exception")));
+ catch(AssertError)
+ thrown = true;
+
+ assert(thrown);
+ }
+
+ {
+ bool thrown = false;
+ try
+ assertNotThrown!Exception(throwEx(new Exception("It's an Exception")), "It's a message");
+ catch(AssertError)
+ thrown = true;
+
+ assert(thrown);
+ }
+
+ {
+ bool thrown = false;
+ try
+ assertNotThrown!AssertError(throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__)));
+ catch(AssertError)
+ thrown = true;
+
+ assert(thrown);
+ }
+
+ {
+ bool thrown = false;
+ try
+ assertNotThrown!AssertError(throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__)), "It's a message");
+ catch(AssertError)
+ thrown = true;
+
+ assert(thrown);
+ }
+
+ //Verify Examples.
+ void timeFunc(int hour, int minute, int second)
+ {
+ enforce(hour >= 0 && hour <= 23);
+ enforce(minute >= 0 && minute <= 59);
+ enforce(second >= 0 && second <= 59);
+
+ //...
+ }
+
+ assertNotThrown!Exception(timeFunc(0, 0, 0));
+ assertNotThrown!Exception(timeFunc(12, 15, 30));
+ assertNotThrown(timeFunc(23, 59, 59)); //Exception is default.
+
+
+ void nameFunc(string name)
+ {
+ enforce(!name.empty);
+ enforce(name.length < 30);
+
+ //...
+ }
+
+ assertNotThrown(nameFunc("Walter Bright"));
+ assertNotThrown(nameFunc("Andrei Alexandrescu"));
+
+
+ void assertPlease()
+ {
+ assert(1 == 0);
+ }
+
+ assert(collectExceptionMsg(assertNotThrown!AssertError(assertPlease())) ==
+ "assertNotThrown failed: AssertError was thrown.");
+
+ assert(collectExceptionMsg(assertNotThrown!AssertError(assertPlease(), "error!")) ==
+ "assertNotThrown failed: AssertError was thrown: error!");
+}
+
+
+void assertPred(string func, string expected, L, R)
+ (L lhs, R rhs, lazy string msg = null, string file = __FILE__, size_t line = __LINE__)
+ if(func == "opCmp" &&
+ (expected == "<" ||
+ expected == "==" ||
+ expected == ">") &&
+ __traits(compiles, lhs.opCmp(rhs)) &&
+ isPrintable!L &&
+ isPrintable!R)
+{
+ immutable result = lhs.opCmp(rhs);
+
+ static if(expected == "<")
+ {
+ if(result < 0)
+ return;
+
+ if(result == 0)
+ {
+ if(msg.empty)
+ throw new AssertError(format(`assertPred!("opCmp", "<") failed: [%s] == [%s].`, lhs, rhs), file, line);
+ else
+ throw new AssertError(format(`assertPred!("opCmp", "<") failed: [%s] == [%s]: %s`, lhs, rhs, msg), file, line);
+ }
+ else
+ {
+ if(msg.empty)
+ throw new AssertError(format(`assertPred!("opCmp", "<") failed: [%s] > [%s].`, lhs, rhs), file, line);
+ else
+ throw new AssertError(format(`assertPred!("opCmp", "<") failed: [%s] > [%s]: %s`, lhs, rhs, msg), file, line);
+ }
+ }
+ else static if(expected == "==")
+ {
+ if(result == 0)
+ return;
+
+ if(result < 0)
+ {
+ if(msg.empty)
+ throw new AssertError(format(`assertPred!("opCmp", "==") failed: [%s] < [%s].`, lhs, rhs), file, line);
+ else
+ throw new AssertError(format(`assertPred!("opCmp", "==") failed: [%s] < [%s]: %s`, lhs, rhs, msg), file, line);
+ }
+ else
+ {
+ if(msg.empty)
+ throw new AssertError(format(`assertPred!("opCmp", "==") failed: [%s] > [%s].`, lhs, rhs), file, line);
+ else
+ throw new AssertError(format(`assertPred!("opCmp", "==") failed: [%s] > [%s]: %s`, lhs, rhs, msg), file, line);
+ }
+ }
+ else static if(expected == ">")
+ {
+ if(result > 0)
+ return;
+
+ if(result < 0)
+ {
+ if(msg.empty)
+ throw new AssertError(format(`assertPred!("opCmp", ">") failed: [%s] < [%s].`, lhs, rhs), file, line);
+ else
+ throw new AssertError(format(`assertPred!("opCmp", ">") failed: [%s] < [%s]: %s`, lhs, rhs, msg), file, line);
+ }
+ else
+ {
+ if(msg.empty)
+ throw new AssertError(format(`assertPred!("opCmp", ">") failed: [%s] == [%s].`, lhs, rhs), file, line);
+ else
+ throw new AssertError(format(`assertPred!("opCmp", ">") failed: [%s] == [%s]: %s`, lhs, rhs, msg), file, line);
+ }
+ }
+ else
+ static assert(0);
+}
+
+
+void assertPred(string op, L, R, E)
+ (L lhs, R rhs, E expected, lazy string msg = null, string file = __FILE__, size_t line = __LINE__)
+ if((op == "+=" ||
+ op == "-=" ||
+ op == "*=" ||
+ op == "/=" ||
+ op == "%=" ||
+ op == "^^=" ||
+ op == "&=" ||
+ op == "|=" ||
+ op == "^=" ||
+ op == "<<=" ||
+ op == ">>=" ||
+ op == ">>>=" ||
+ op == "~=") &&
+ __traits(compiles, mixin("lhs " ~ op ~ " rhs")) &&
+ __traits(compiles, mixin("(lhs " ~ op ~ " rhs) == expected")) &&
+ isPrintable!L &&
+ isPrintable!R)
+{
+ immutable origLHSStr = to!string(lhs);
+ const result = mixin("lhs " ~ op ~ " rhs");
+
+ if(lhs != expected)
+ {
+ if(msg.empty)
+ {
+ throw new AssertError(format(`assertPred!"%s" failed: After [%s] %s [%s], lhs was assigned to [%s] instead of [%s].`,
+ op,
+ origLHSStr,
+ op,
+ rhs,
+ lhs,
+ expected),
+ file,
+ line);
+ }
+ else
+ {
+ throw new AssertError(format(`assertPred!"%s" failed: After [%s] %s [%s], lhs was assigned to [%s] instead of [%s]: %s`,
+ op,
+ origLHSStr,
+ op,
+ rhs,
+ lhs,
+ expected,
+ msg),
+ file,
+ line);
+ }
+ }
+
+ if(result != expected)
+ {
+ if(msg.empty)
+ {
+ throw new AssertError(format(`assertPred!"%s" failed: Return value of [%s] %s [%s] was [%s] instead of [%s].`,
+ op,
+ origLHSStr,
+ op,
+ rhs,
+ result,
+ expected),
+ file,
+ line);
+ }
+ else
+ {
+ throw new AssertError(format(`assertPred!"%s" failed: Return value of [%s] %s [%s] was [%s] instead of [%s]: %s`,
+ op,
+ origLHSStr,
+ op,
+ rhs,
+ result,
+ expected,
+ msg),
+ file,
+ line);
+ }
+ }
+}
+
+unittest
+{
+ assertNotThrown!AssertError(assertPred!"+="(7, 5, 12));
+ assertNotThrown!AssertError(assertPred!"-="(7, 5, 2));
+ assertNotThrown!AssertError(assertPred!"*="(7, 5, 35));
+ assertNotThrown!AssertError(assertPred!"/="(7, 5, 1));
+ assertNotThrown!AssertError(assertPred!"%="(7, 5, 2));
+ assertNotThrown!AssertError(assertPred!"^^="(7, 5, 16_807));
+ assertNotThrown!AssertError(assertPred!"&="(7, 5, 5));
+ assertNotThrown!AssertError(assertPred!"|="(7, 5, 7));
+ assertNotThrown!AssertError(assertPred!"^="(7, 5, 2));
+ assertNotThrown!AssertError(assertPred!"<<="(7, 1, 14));
+ assertNotThrown!AssertError(assertPred!">>="(7, 1, 3));
+ assertNotThrown!AssertError(assertPred!">>>="(-7, 1, 2_147_483_644));
+ assertNotThrown!AssertError(assertPred!"~="("hello ", "world", "hello world"));
+
+ assertThrown!AssertError(assertPred!"+="(7, 5, 0));
+ assertThrown!AssertError(assertPred!"-="(7, 5, 0));
+ assertThrown!AssertError(assertPred!"*="(7, 5, 0));
+ assertThrown!AssertError(assertPred!"/="(7, 5, 0));
+ assertThrown!AssertError(assertPred!"%="(7, 5, 0));
+ assertThrown!AssertError(assertPred!"^^="(7, 5, 0));
+ assertThrown!AssertError(assertPred!"&="(7, 5, 0));
+ assertThrown!AssertError(assertPred!"|="(7, 5, 0));
+ assertThrown!AssertError(assertPred!"^="(7, 5, 0));
+ assertThrown!AssertError(assertPred!"<<="(7, 1, 0));
+ assertThrown!AssertError(assertPred!">>="(7, 1, 0));
+ assertThrown!AssertError(assertPred!">>>="(-7, 1, 0));
+ assertThrown!AssertError(assertPred!"~="("hello ", "world", "goodbye world"));
+
+ assertPred!"=="(collectExceptionMsg(assertPred!"+="(7, 5, 11)),
+ `assertPred!"+=" failed: After [7] += [5], lhs was assigned to [12] instead of [11].`);
+ assertPred!"=="(collectExceptionMsg(assertPred!"+="(7, 5, 11, "It failed!")),
+ `assertPred!"+=" failed: After [7] += [5], lhs was assigned to [12] instead of [11]: It failed!`);
+
+ assertPred!"=="(collectExceptionMsg(assertPred!"^^="(7, 5, 42)),
+ `assertPred!"^^=" failed: After [7] ^^= [5], lhs was assigned to [16807] instead of [42].`);
+ assertPred!"=="(collectExceptionMsg(assertPred!"^^="(7, 5, 42, "It failed!")),
+ `assertPred!"^^=" failed: After [7] ^^= [5], lhs was assigned to [16807] instead of [42]: It failed!`);
+
+ assertPred!"=="(collectExceptionMsg(assertPred!"~="("hello ", "world", "goodbye world")),
+ `assertPred!"~=" failed: After [hello ] ~= [world], lhs was assigned to [hello world] instead of [goodbye world].`);
+ assertPred!"=="(collectExceptionMsg(assertPred!"~="("hello ", "world", "goodbye world", "It failed!")),
+ `assertPred!"~=" failed: After [hello ] ~= [world], lhs was assigned to [hello world] instead of [goodbye world]: It failed!`);
+
+ struct IntWrapper
+ {
+ int value;
+
+ this(int value)
+ {
+ this.value = value;
+ }
+
+ IntWrapper opOpAssign(string op)(IntWrapper rhs)
+ {
+ mixin("this.value " ~ op ~ "= rhs.value;");
+
+ return this;
+ }
+
+ string toString()
+ {
+ return to!string(value);
+ }
+ }
+
+ struct IntWrapper_BadAssign
+ {
+ int value;
+
+ this(int value)
+ {
+ this.value = value;
+ }
+
+ IntWrapper_BadAssign opOpAssign(string op)(IntWrapper_BadAssign rhs)
+ {
+ auto old = this.value;
+
+ mixin("this.value " ~ op ~ "= -rhs.value;");
+
+ return IntWrapper_BadAssign(mixin("old " ~ op ~ " rhs.value"));
+ }
+
+ string toString()
+ {
+ return to!string(value);
+ }
+ }
+
+ struct IntWrapper_BadReturn
+ {
+ int value;
+
+ this(int value)
+ {
+ this.value = value;
+ }
+
+ IntWrapper_BadReturn opOpAssign(string op)(IntWrapper_BadReturn rhs)
+ {
+ mixin("this.value " ~ op ~ "= rhs.value;");
+
+ return IntWrapper_BadReturn(rhs.value);
+ }
+
+ string toString()
+ {
+ return to!string(value);
+ }
+ }
+
+ assertNotThrown!AssertError(assertPred!"+="(IntWrapper(5), IntWrapper(2), IntWrapper(7)));
+ assertNotThrown!AssertError(assertPred!"*="(IntWrapper(5), IntWrapper(2), IntWrapper(10)));
+
+ assertThrown!AssertError(assertPred!"+="(IntWrapper_BadAssign(5), IntWrapper_BadAssign(2), IntWrapper_BadAssign(7)));
+ assertThrown!AssertError(assertPred!"+="(IntWrapper_BadReturn(5), IntWrapper_BadReturn(2), IntWrapper_BadReturn(7)));
+ assertThrown!AssertError(assertPred!"*="(IntWrapper_BadAssign(5), IntWrapper_BadAssign(2), IntWrapper_BadAssign(10)));
+ assertThrown!AssertError(assertPred!"*="(IntWrapper_BadReturn(5), IntWrapper_BadReturn(2), IntWrapper_BadReturn(10)));
+
+ assertPred!"=="(collectExceptionMsg(assertPred!"+="(IntWrapper_BadAssign(5), IntWrapper_BadAssign(2), IntWrapper_BadAssign(7))),
+ `assertPred!"+=" failed: After [5] += [2], lhs was assigned to [3] instead of [7].`);
+ assertPred!"=="(collectExceptionMsg(assertPred!"+="(IntWrapper_BadAssign(5), IntWrapper_BadAssign(2), IntWrapper_BadAssign(7), "It failed!")),
+ `assertPred!"+=" failed: After [5] += [2], lhs was assigned to [3] instead of [7]: It failed!`);
+
+ assertPred!"=="(collectExceptionMsg(assertPred!"+="(IntWrapper_BadReturn(5), IntWrapper_BadReturn(2), IntWrapper_BadReturn(7))),
+ `assertPred!"+=" failed: Return value of [5] += [2] was [2] instead of [7].`);
+ assertPred!"=="(collectExceptionMsg(assertPred!"+="(IntWrapper_BadReturn(5), IntWrapper_BadReturn(2), IntWrapper_BadReturn(7), "It failed!")),
+ `assertPred!"+=" failed: Return value of [5] += [2] was [2] instead of [7]: It failed!`);
+
+ assertPred!"=="(collectExceptionMsg(assertPred!"*="(IntWrapper_BadAssign(5), IntWrapper_BadAssign(2), IntWrapper_BadAssign(10))),
+ `assertPred!"*=" failed: After [5] *= [2], lhs was assigned to [-10] instead of [10].`);
+ assertPred!"=="(collectExceptionMsg(assertPred!"*="(IntWrapper_BadAssign(5), IntWrapper_BadAssign(2), IntWrapper_BadAssign(10), "It failed!")),
+ `assertPred!"*=" failed: After [5] *= [2], lhs was assigned to [-10] instead of [10]: It failed!`);
+
+ assertPred!"=="(collectExceptionMsg(assertPred!"*="(IntWrapper_BadReturn(5), IntWrapper_BadReturn(2), IntWrapper_BadReturn(10))),
+ `assertPred!"*=" failed: Return value of [5] *= [2] was [2] instead of [10].`);
+ assertPred!"=="(collectExceptionMsg(assertPred!"*="(IntWrapper_BadReturn(5), IntWrapper_BadReturn(2), IntWrapper_BadReturn(10), "It failed!")),
+ `assertPred!"*=" failed: Return value of [5] *= [2] was [2] instead of [10]: It failed!`);
+}
+
+
+string collectExceptionMsg(T)(lazy T funcCall)
+{
+ try
+ {
+ funcCall();
+
+ return cast(string)null;
+ }
+ catch(Throwable t)
+ return t.msg;
+}
+
+unittest
+{
+ //Verify Example.
+ void throwFunc() {throw new Exception("My Message.");}
+ assert(collectExceptionMsg(throwFunc()) == "My Message.");
+
+ void nothrowFunc() {}
+ assert(collectExceptionMsg(nothrowFunc()) is null);
+}
+
+
+template isPrintable(T...)
+{
+ static if(T.length == 0)
+ enum isPrintable = true;
+ else static if(T.length == 1)
+ {
+ enum isPrintable = (!isArray!(T[0]) && __traits(compiles, to!string(T[0].init))) ||
+ (isArray!(T[0]) && __traits(compiles, to!string(T[0].init[0])));
+ }
+ else
+ {
+ enum isPrintable = isPrintable!(T[0]) && isPrintable!(T[1 .. $]);
+ }
+}