mirror of
https://github.com/dlang/phobos.git
synced 2025-04-27 05:30:33 +03:00
33594 lines
1.4 MiB
33594 lines
1.4 MiB
//Written in the D programming language
|
|
|
|
/++
|
|
Module containing Date/Time functionality.
|
|
|
|
This module provides:
|
|
$(UL
|
|
$(LI Types to represent points in time: $(LREF SysTime), $(LREF Date),
|
|
$(LREF TimeOfDay), and $(LREF2 .DateTime, DateTime).)
|
|
$(LI Types to represent intervals of time.)
|
|
$(LI Types to represent ranges over intervals of time.)
|
|
$(LI Types to represent time zones (used by $(LREF SysTime)).)
|
|
$(LI A platform-independent, high precision stopwatch type:
|
|
$(LREF StopWatch))
|
|
$(LI Benchmarking functions.)
|
|
$(LI Various helper functions.)
|
|
)
|
|
|
|
Closely related to std.datetime is <a href="core_time.html">$(D core.time)</a>,
|
|
and some of the time types used in std.datetime come from there - such as
|
|
$(CXREF time, Duration), $(CXREF time, TickDuration), and
|
|
$(CXREF time, FracSec).
|
|
core.time is publically imported into std.datetime, it isn't necessary
|
|
to import it separately.
|
|
|
|
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. 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
|
|
$(LREF Date) (if they want dates but don't care about time), $(LREF DateTime)
|
|
(if they want dates and times but don't care about time zones), $(LREF 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).
|
|
$(LREF Date) and $(LREF DateTime) are optimized for calendar-based operations,
|
|
while $(LREF SysTime) is designed for dealing with time from the OS. Check out
|
|
their specific documentation for more details.
|
|
|
|
To get the current time, use $(LREF2 .Clock.currTime, Clock.currTime).
|
|
It will return the current
|
|
time as a $(LREF SysTime). To print it, $(D toString) is
|
|
sufficient, but if using $(D toISOString), $(D toISOExtString), or
|
|
$(D toSimpleString), use the corresponding $(D fromISOString),
|
|
$(D fromISOExtString), or $(D fromSimpleString) to create a
|
|
$(LREF SysTime) from the string.
|
|
|
|
--------------------
|
|
auto currentTime = Clock.currTime();
|
|
auto timeString = currentTime.toISOExtString();
|
|
auto restoredTime = SysTime.fromISOExtString(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 $(D "years"), $(D "months"), $(D "weeks"),
|
|
$(D "days"), $(D "hours"), $(D "minutes"), $(D "seconds"),
|
|
$(D "msecs") (milliseconds), $(D "usecs") (microseconds),
|
|
$(D "hnsecs") (hecto-nanoseconds - i.e. 100 ns), or some subset thereof.
|
|
There are a few functions in core.time which take $(D "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 $(D "nsecs").
|
|
To remember which units are abbreviated and which aren't,
|
|
all units seconds and greater use their full names, and all
|
|
sub-second units are abbreviated (since they'd be rather long if they
|
|
weren't).
|
|
|
|
Note:
|
|
$(LREF DateTimeException) is an alias for $(CXREF time, TimeException),
|
|
so you don't need to worry about core.time functions and std.datetime
|
|
functions throwing different exception types (except in the rare case
|
|
that they throw something other than $(CXREF time, TimeException) or
|
|
$(LREF DateTimeException)).
|
|
|
|
See_Also:
|
|
<a href="../intro-to-datetime.html">Introduction to std._datetime </a><br>
|
|
$(WEB en.wikipedia.org/wiki/ISO_8601, ISO 8601)<br>
|
|
$(WEB en.wikipedia.org/wiki/Tz_database,
|
|
Wikipedia entry on TZ Database)<br>
|
|
$(WEB en.wikipedia.org/wiki/List_of_tz_database_time_zones,
|
|
List of Time Zones)<br>
|
|
|
|
Copyright: Copyright 2010 - 2011
|
|
License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
|
|
Authors: Jonathan M Davis and Kato Shoichi
|
|
Source: $(PHOBOSSRC std/_datetime.d)
|
|
Macros:
|
|
LREF2=<a href="#$1">$(D $2)</a>
|
|
+/
|
|
module std.datetime;
|
|
|
|
public import core.time;
|
|
|
|
import core.exception;
|
|
import core.stdc.time;
|
|
|
|
import std.exception;
|
|
import std.range.primitives;
|
|
import std.traits;
|
|
// FIXME
|
|
import std.functional; //: unaryFun;
|
|
|
|
version(Windows)
|
|
{
|
|
import core.sys.windows.windows;
|
|
import core.sys.windows.winsock2;
|
|
import std.windows.registry;
|
|
}
|
|
else version(Posix)
|
|
{
|
|
import core.sys.posix.stdlib;
|
|
import core.sys.posix.sys.time;
|
|
}
|
|
|
|
version(unittest)
|
|
{
|
|
import std.stdio;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
initializeTests();
|
|
}
|
|
|
|
//Verify module example.
|
|
unittest
|
|
{
|
|
auto currentTime = Clock.currTime();
|
|
auto timeString = currentTime.toISOExtString();
|
|
auto restoredTime = SysTime.fromISOExtString(timeString);
|
|
}
|
|
|
|
//Verify Examples for core.time.Duration which couldn't be in core.time.
|
|
unittest
|
|
{
|
|
assert(std.datetime.Date(2010, 9, 7) + dur!"days"(5) ==
|
|
std.datetime.Date(2010, 9, 12));
|
|
|
|
assert(std.datetime.Date(2010, 9, 7) - std.datetime.Date(2010, 10, 3) ==
|
|
dur!"days"(-26));
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
// 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 $(LREF2 .Interval, Interval)'s
|
|
$(LREF expand, 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,
|
|
|
|
/// 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. To get the first time point
|
|
in the range to match what the function generates, then 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. Using
|
|
$(D PopFirst.yes) would tell the function which returned the
|
|
range that $(D popFront) was to be called so that front would then be
|
|
an Easter - the next one generated by the function (which when
|
|
iterating forward would be the Easter following the original $(D front),
|
|
while when 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 is desired -
|
|
e.g. if 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 $(D "nsecs").
|
|
|
|
Includes $(D "hnsecs") (hecto-nanoseconds (100 ns)),
|
|
$(D "usecs") (microseconds), $(D "msecs") (milliseconds), $(D "seconds"),
|
|
$(D "minutes"), $(D "hours"), $(D "days"), $(D "weeks"), $(D "months"), and
|
|
$(D "years")
|
|
+/
|
|
immutable string[] timeStrings = ["hnsecs", "usecs", "msecs", "seconds", "minutes",
|
|
"hours", "days", "weeks", "months", "years"];
|
|
|
|
|
|
//==============================================================================
|
|
// Section with other types.
|
|
//==============================================================================
|
|
|
|
/++
|
|
Exception type used by std.datetime. It's an alias to $(CXREF time, TimeException).
|
|
Either can be caught without concern about which
|
|
module it came from.
|
|
+/
|
|
alias TimeException DateTimeException;
|
|
|
|
/++
|
|
Effectively a namespace to make it clear that the methods it contains are
|
|
getting the time from the system clock. It cannot be instantiated.
|
|
+/
|
|
final class Clock
|
|
{
|
|
public:
|
|
|
|
/++
|
|
Returns the current time in the given time zone.
|
|
|
|
Throws:
|
|
$(XREF exception, ErrnoException) (on Posix) or $(XREF exception, Exception) (on Windows)
|
|
if it fails to get the time of day.
|
|
+/
|
|
static SysTime currTime(immutable TimeZone tz = LocalTime()) @safe
|
|
{
|
|
return SysTime(currStdTime, tz);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(currTime(UTC()).timezone is UTC());
|
|
|
|
//I have no idea why, but for some reason, Windows/Wine likes to get
|
|
//time_t wrong when getting it with core.stdc.time.time. On one box
|
|
//I have (which has its local time set to UTC), it always gives time_t
|
|
//in the real local time (America/Los_Angeles), and after the most recent
|
|
//DST switch, every Windows box that I've tried it in is reporting
|
|
//time_t as being 1 hour off of where it's supposed to be. So, I really
|
|
//don't know what the deal is, but given what I'm seeing, I don't trust
|
|
//core.stdc.time.time on Windows, so I'm just going to disable this test
|
|
//on Windows.
|
|
version(Posix)
|
|
{
|
|
immutable unixTimeD = currTime().toUnixTime();
|
|
immutable unixTimeC = core.stdc.time.time(null);
|
|
immutable diff = unixTimeC - unixTimeD;
|
|
|
|
assert(diff >= -2);
|
|
assert(diff <= 2);
|
|
}
|
|
}
|
|
|
|
/++
|
|
Returns the number of hnsecs since midnight, January 1st, 1 A.D. for the
|
|
current time.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if it fails to get the time.
|
|
+/
|
|
static @property long currStdTime() @trusted
|
|
{
|
|
version(Windows)
|
|
{
|
|
FILETIME fileTime;
|
|
GetSystemTimeAsFileTime(&fileTime);
|
|
|
|
return FILETIMEToStdTime(&fileTime);
|
|
}
|
|
else version(Posix)
|
|
{
|
|
enum hnsecsToUnixEpoch = 621_355_968_000_000_000L;
|
|
|
|
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. currSystemTick 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 Linux.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if it fails to get the time.
|
|
+/
|
|
static @property TickDuration currSystemTick() @safe nothrow
|
|
{
|
|
return TickDuration.currSystemTick;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(Clock.currSystemTick.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:
|
|
$(LREF DateTimeException) if it fails to get the time.
|
|
+/
|
|
static @property TickDuration currAppTick() @safe
|
|
{
|
|
return currSystemTick - TickDuration.appOrigin;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto a = Clock.currSystemTick;
|
|
auto b = Clock.currAppTick;
|
|
assert(a.length);
|
|
assert(b.length);
|
|
assert(a > b);
|
|
}
|
|
|
|
private:
|
|
|
|
@disable this() {}
|
|
}
|
|
|
|
//==============================================================================
|
|
// Section with time points.
|
|
//==============================================================================
|
|
|
|
/++
|
|
$(D SysTime) is the type used to get the current time from the
|
|
system or doing anything that involves time zones. Unlike
|
|
$(LREF DateTime), the time zone is an integral part of $(D SysTime) (though for
|
|
local time applications, time zones can be ignored 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
|
|
$(LREF DateTime), it is not optimized for calendar-based operations, and
|
|
getting individual units from it such as years or days is going to involve
|
|
conversions and be less efficient.
|
|
|
|
For calendar-based operations that don't
|
|
care about time zones, then $(LREF DateTime) would be the type to
|
|
use. For system time, use $(D SysTime).
|
|
|
|
$(LREF2 .Clock.currTime, Clock.currTime) will return the current time as a $(D SysTime).
|
|
To convert a $(D SysTime) to a $(LREF Date) or $(LREF DateTime), simply cast
|
|
it. To convert a $(LREF Date) or $(LREF DateTime) to a
|
|
$(D SysTime), use $(D SysTime)'s constructor, and pass in the
|
|
intended time zone with it (or don't pass in a $(LREF2 .TimeZone, TimeZone), and the local
|
|
time zone will be used). Be aware, however, that converting from a
|
|
$(LREF DateTime) to a $(D SysTime) will not necessarily be 100% accurate due to
|
|
DST (one hour of the year doesn't exist and another occurs twice).
|
|
To not risk any conversion errors, keep times as
|
|
$(D SysTime)s. Aside from DST though, there shouldn't be any conversion
|
|
problems.
|
|
|
|
For using time zones other than local time or UTC, use
|
|
$(LREF PosixTimeZone) on Posix systems (or on Windows, if providing the TZ
|
|
Database files), and use $(LREF WindowsTimeZone) on Windows systems.
|
|
The time in $(D SysTime) is kept internally in hnsecs from midnight,
|
|
January 1st, 1 A.D. UTC. Conversion error cannot happen when changing
|
|
the time zone of a $(D SysTime). $(LREF LocalTime) is the $(LREF2 .TimeZone, TimeZone) class
|
|
which represents the local time, and $(D UTC) is the $(LREF2 .TimeZone, TimeZone) class
|
|
which represents UTC. $(D SysTime) uses $(LREF LocalTime) if no $(LREF2 .TimeZone, TimeZone)
|
|
is provided. For more details on time zones, see the documentation for
|
|
$(LREF2 .TimeZone, TimeZone), $(LREF PosixTimeZone), and $(LREF WindowsTimeZone).
|
|
|
|
$(D SysTime)'s range is from approximately 29,000 B.C. to approximately
|
|
29,000 A.D.
|
|
+/
|
|
struct SysTime
|
|
{
|
|
import std.typecons : Rebindable;
|
|
|
|
public:
|
|
|
|
/++
|
|
Params:
|
|
dateTime = The $(LREF DateTime) to use to set this $(LREF SysTime)'s
|
|
internal std time. As $(LREF DateTime) has no concept of
|
|
time zone, tz is used as its time zone.
|
|
tz = The $(LREF2 .TimeZone, TimeZone) to use for this $(LREF SysTime). If null,
|
|
$(LREF LocalTime) will be used. The given $(LREF DateTime) is
|
|
assumed to be in the given time zone.
|
|
+/
|
|
this(in DateTime dateTime, immutable TimeZone tz = null) @safe nothrow
|
|
{
|
|
try
|
|
this(dateTime, Duration.zero, tz);
|
|
catch(Exception e)
|
|
assert(0, "SysTime's constructor threw when it shouldn't have.");
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.format : format;
|
|
static void test(DateTime dt, immutable TimeZone tz, long expected)
|
|
{
|
|
auto sysTime = SysTime(dt, tz);
|
|
assert(sysTime._stdTime == expected);
|
|
assert(sysTime._timezone is (tz is null ? LocalTime() : tz),
|
|
format("Given DateTime: %s", dt));
|
|
}
|
|
|
|
test(DateTime.init, UTC(), 0);
|
|
test(DateTime(1, 1, 1, 12, 30, 33), UTC(), 450_330_000_000L);
|
|
test(DateTime(0, 12, 31, 12, 30, 33), UTC(), -413_670_000_000L);
|
|
test(DateTime(1, 1, 1, 0, 0, 0), UTC(), 0);
|
|
test(DateTime(1, 1, 1, 0, 0, 1), UTC(), 10_000_000L);
|
|
test(DateTime(0, 12, 31, 23, 59, 59), UTC(), -10_000_000L);
|
|
|
|
test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(dur!"minutes"(-60)), 36_000_000_000L);
|
|
test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(Duration.zero), 0);
|
|
test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(dur!"minutes"(60)), -36_000_000_000L);
|
|
}
|
|
|
|
/++
|
|
Params:
|
|
dateTime = The $(LREF DateTime) to use to set this $(LREF SysTime)'s
|
|
internal std time. As $(LREF DateTime) has no concept of
|
|
time zone, tz is used as its time zone.
|
|
fracSecs = The fractional seconds portion of the time.
|
|
tz = The $(LREF2 .TimeZone, TimeZone) to use for this $(LREF SysTime). If null,
|
|
$(LREF LocalTime) will be used. The given $(LREF DateTime) is
|
|
assumed to be in the given time zone.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if $(D fracSecs) is negative or if it's
|
|
greater than or equal to one second.
|
|
+/
|
|
this(in DateTime dateTime, in Duration fracSecs, immutable TimeZone tz = null) @safe
|
|
{
|
|
enforce(fracSecs >= Duration.zero, new DateTimeException("A SysTime cannot have negative fractional seconds."));
|
|
enforce(fracSecs < seconds(1), new DateTimeException("Fractional seconds must be less than one second."));
|
|
auto nonNullTZ = tz is null ? LocalTime() : tz;
|
|
|
|
immutable dateDiff = dateTime.date - Date.init;
|
|
immutable todDiff = dateTime.timeOfDay - TimeOfDay.init;
|
|
|
|
immutable adjustedTime = dateDiff + todDiff + fracSecs;
|
|
immutable standardTime = nonNullTZ.tzToUTC(adjustedTime.total!"hnsecs");
|
|
|
|
this(standardTime, nonNullTZ);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.format : format;
|
|
static void test(DateTime dt, Duration fracSecs, immutable TimeZone tz, long expected)
|
|
{
|
|
auto sysTime = SysTime(dt, fracSecs, tz);
|
|
assert(sysTime._stdTime == expected);
|
|
assert(sysTime._timezone is (tz is null ? LocalTime() : tz),
|
|
format("Given DateTime: %s, Given Duration: %s", dt, fracSecs));
|
|
}
|
|
|
|
test(DateTime.init, Duration.zero, UTC(), 0);
|
|
test(DateTime(1, 1, 1, 12, 30, 33), Duration.zero, UTC(), 450_330_000_000L);
|
|
test(DateTime(0, 12, 31, 12, 30, 33), Duration.zero, UTC(), -413_670_000_000L);
|
|
test(DateTime(1, 1, 1, 0, 0, 0), msecs(1), UTC(), 10_000L);
|
|
test(DateTime(0, 12, 31, 23, 59, 59), msecs(999), UTC(), -10_000L);
|
|
|
|
test(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC(), -1);
|
|
test(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC(), -9_999_999);
|
|
test(DateTime(0, 12, 31, 23, 59, 59), Duration.zero, UTC(), -10_000_000);
|
|
|
|
assertThrown!DateTimeException(SysTime(DateTime.init, hnsecs(-1), UTC()));
|
|
assertThrown!DateTimeException(SysTime(DateTime.init, seconds(1), UTC()));
|
|
}
|
|
|
|
/++
|
|
$(RED Scheduled for deprecation. Please use the overload which takes a
|
|
$(CXREF time, Duration) for the fractional seconds. This overload
|
|
will be deprecated in 2.068).
|
|
|
|
Params:
|
|
dateTime = The $(LREF DateTime) to use to set this $(LREF SysTime)'s
|
|
internal std time. As $(LREF DateTime) has no concept of
|
|
time zone, tz is used as its time zone.
|
|
fracSec = The fractional seconds portion of the time.
|
|
tz = The $(LREF2 .TimeZone, TimeZone) to use for this $(LREF SysTime). If null,
|
|
$(LREF LocalTime) will be used. The given $(LREF DateTime) is
|
|
assumed to be in the given time zone.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if $(D fracSec) is negative.
|
|
+/
|
|
//deprecated("Please use the overload which takes a Duration instead of a FracSec.")
|
|
this(in DateTime dateTime, in FracSec fracSec, immutable TimeZone tz = null) @safe
|
|
{
|
|
immutable fracHNSecs = fracSec.hnsecs;
|
|
enforce(fracHNSecs >= 0, new DateTimeException("A SysTime cannot have negative fractional seconds."));
|
|
_timezone = tz is null ? LocalTime() : 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 + fracHNSecs;
|
|
immutable standardTime = _timezone.tzToUTC(adjustedTime);
|
|
|
|
this(standardTime, _timezone);
|
|
}
|
|
catch(Exception e)
|
|
assert(0, "Date, TimeOfDay, or DateTime's constructor threw when it shouldn't have.");
|
|
}
|
|
|
|
/+deprecated+/ unittest
|
|
{
|
|
import std.format : format;
|
|
|
|
static void test(DateTime dt,
|
|
FracSec fracSec,
|
|
immutable TimeZone tz,
|
|
long expected)
|
|
{
|
|
auto sysTime = SysTime(dt, fracSec, tz);
|
|
assert(sysTime._stdTime == expected);
|
|
assert(sysTime._timezone is (tz is null ? LocalTime() : tz),
|
|
format("Given DateTime: %s, Given FracSec: %s", dt, fracSec));
|
|
}
|
|
|
|
test(DateTime.init, FracSec.init, UTC(), 0);
|
|
test(DateTime(1, 1, 1, 12, 30, 33), FracSec.init, UTC(), 450_330_000_000L);
|
|
test(DateTime(0, 12, 31, 12, 30, 33), FracSec.init, UTC(), -413_670_000_000L);
|
|
test(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"msecs"(1), UTC(), 10_000L);
|
|
test(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"msecs"(999), UTC(), -10_000L);
|
|
|
|
test(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999), UTC(), -1);
|
|
test(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1), UTC(), -9_999_999);
|
|
test(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(0), UTC(), -10_000_000);
|
|
|
|
assertThrown!DateTimeException(SysTime(DateTime.init, FracSec.from!"hnsecs"(-1), UTC()));
|
|
}
|
|
|
|
/++
|
|
Params:
|
|
date = The $(LREF Date) to use to set this $(LREF SysTime)'s internal std
|
|
time. As $(LREF Date) has no concept of time zone, tz is used as
|
|
its time zone.
|
|
tz = The $(LREF2 .TimeZone, TimeZone) to use for this $(LREF SysTime). If null,
|
|
$(LREF LocalTime) will be used. The given $(LREF Date) is assumed
|
|
to be in the given time zone.
|
|
+/
|
|
this(in Date date, immutable TimeZone tz = null) @safe nothrow
|
|
{
|
|
_timezone = tz is null ? LocalTime() : tz;
|
|
|
|
try
|
|
{
|
|
immutable adjustedTime = (date - Date(1, 1, 1)).total!"hnsecs";
|
|
immutable standardTime = _timezone.tzToUTC(adjustedTime);
|
|
|
|
this(standardTime, _timezone);
|
|
}
|
|
catch(Exception e)
|
|
assert(0, "Date's constructor through when it shouldn't have.");
|
|
}
|
|
|
|
unittest
|
|
{
|
|
static void test(Date d, immutable TimeZone tz, long expected)
|
|
{
|
|
import std.format : format;
|
|
auto sysTime = SysTime(d, tz);
|
|
assert(sysTime._stdTime == expected);
|
|
assert(sysTime._timezone is (tz is null ? LocalTime() : tz),
|
|
format("Given Date: %s", d));
|
|
}
|
|
|
|
test(Date.init, UTC(), 0);
|
|
test(Date(1, 1, 1), UTC(), 0);
|
|
test(Date(1, 1, 2), UTC(), 864000000000);
|
|
test(Date(0, 12, 31), UTC(), -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 $(LREF2 .TimeZone, TimeZone) to use for this $(LREF SysTime). If null,
|
|
$(LREF LocalTime) will be used.
|
|
+/
|
|
this(long stdTime, immutable TimeZone tz = null) @safe pure nothrow
|
|
{
|
|
_stdTime = stdTime;
|
|
_timezone = tz is null ? LocalTime() : tz;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
static void test(long stdTime, immutable TimeZone tz)
|
|
{
|
|
import std.format : format;
|
|
auto sysTime = SysTime(stdTime, tz);
|
|
assert(sysTime._stdTime == stdTime);
|
|
assert(sysTime._timezone is (tz is null ? LocalTime() : tz),
|
|
format("Given stdTime: %s", stdTime));
|
|
}
|
|
|
|
foreach(stdTime; [-1234567890L, -250, 0, 250, 1235657390L])
|
|
{
|
|
foreach(tz; testTZs)
|
|
test(stdTime, tz);
|
|
}
|
|
}
|
|
|
|
/++
|
|
Params:
|
|
rhs = The $(LREF SysTime) to assign to this one.
|
|
+/
|
|
ref SysTime opAssign(const ref SysTime rhs) return @safe pure nothrow
|
|
{
|
|
_stdTime = rhs._stdTime;
|
|
_timezone = rhs._timezone;
|
|
|
|
return this;
|
|
}
|
|
|
|
/++
|
|
Params:
|
|
rhs = The $(LREF SysTime) to assign to this one.
|
|
+/
|
|
ref SysTime opAssign(SysTime rhs) return @safe pure nothrow
|
|
{
|
|
_stdTime = rhs._stdTime;
|
|
_timezone = rhs._timezone;
|
|
|
|
return this;
|
|
}
|
|
|
|
/++
|
|
Checks for equality between this $(LREF SysTime) and the given
|
|
$(LREF SysTime).
|
|
|
|
Note that the time zone is ignored. Only the internal
|
|
std times (which are in UTC) are compared.
|
|
+/
|
|
bool opEquals(const SysTime rhs) @safe const pure nothrow
|
|
{
|
|
return opEquals(rhs);
|
|
}
|
|
|
|
/// ditto
|
|
bool opEquals(const ref SysTime rhs) @safe const pure nothrow
|
|
{
|
|
return _stdTime == rhs._stdTime;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.range;
|
|
assert(SysTime(DateTime.init, UTC()) == SysTime(0, UTC()));
|
|
assert(SysTime(DateTime.init, UTC()) == SysTime(0));
|
|
assert(SysTime(Date.init, UTC()) == SysTime(0));
|
|
assert(SysTime(0) == SysTime(0));
|
|
|
|
static void test(DateTime dt,
|
|
immutable TimeZone tz1,
|
|
immutable TimeZone tz2)
|
|
{
|
|
auto st1 = SysTime(dt);
|
|
st1.timezone = tz1;
|
|
|
|
auto st2 = SysTime(dt);
|
|
st2.timezone = tz2;
|
|
|
|
assert(st1 == st2);
|
|
}
|
|
|
|
foreach(tz1; testTZs)
|
|
{
|
|
foreach(tz2; testTZs)
|
|
{
|
|
foreach(dt; chain(testDateTimesBC, testDateTimesAD))
|
|
test(dt, tz1, tz2);
|
|
}
|
|
}
|
|
|
|
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 $(LREF SysTime) with the given $(LREF SysTime).
|
|
|
|
Time zone is irrelevant when comparing $(LREF SysTime)s.
|
|
|
|
Returns:
|
|
$(BOOKTABLE,
|
|
$(TR $(TD this < rhs) $(TD < 0))
|
|
$(TR $(TD this == rhs) $(TD 0))
|
|
$(TR $(TD this > rhs) $(TD > 0))
|
|
)
|
|
+/
|
|
int opCmp(in SysTime rhs) @safe const pure nothrow
|
|
{
|
|
if(_stdTime < rhs._stdTime)
|
|
return -1;
|
|
if(_stdTime > rhs._stdTime)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.range;
|
|
assert(SysTime(DateTime.init, UTC()).opCmp(SysTime(0, UTC())) == 0);
|
|
assert(SysTime(DateTime.init, UTC()).opCmp(SysTime(0)) == 0);
|
|
assert(SysTime(Date.init, UTC()).opCmp(SysTime(0)) == 0);
|
|
assert(SysTime(0).opCmp(SysTime(0)) == 0);
|
|
|
|
static void testEqual(SysTime st,
|
|
immutable TimeZone tz1,
|
|
immutable TimeZone tz2)
|
|
{
|
|
auto st1 = st;
|
|
st1.timezone = tz1;
|
|
|
|
auto st2 = st;
|
|
st2.timezone = tz2;
|
|
|
|
assert(st1.opCmp(st2) == 0);
|
|
}
|
|
|
|
auto sts = array(map!SysTime(chain(testDateTimesBC, testDateTimesAD)));
|
|
|
|
foreach(st; sts)
|
|
foreach(tz1; testTZs)
|
|
foreach(tz2; testTZs)
|
|
testEqual(st, tz1, tz2);
|
|
|
|
static void testCmp(SysTime st1,
|
|
immutable TimeZone tz1,
|
|
SysTime st2,
|
|
immutable TimeZone tz2)
|
|
{
|
|
st1.timezone = tz1;
|
|
st2.timezone = tz2;
|
|
assert(st1.opCmp(st2) < 0);
|
|
assert(st2.opCmp(st1) > 0);
|
|
}
|
|
|
|
foreach(si, st1; sts)
|
|
foreach(st2; sts[si+1 .. $])
|
|
foreach(tz1; testTZs)
|
|
foreach(tz2; testTZs)
|
|
testCmp(st1, tz1, st2, tz2);
|
|
|
|
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() @safe const nothrow
|
|
{
|
|
return (cast(Date)this).year;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.range;
|
|
static void test(SysTime sysTime, long expected)
|
|
{
|
|
import std.format : format;
|
|
assert(sysTime.year == expected,
|
|
format("Value given: %s", sysTime));
|
|
}
|
|
|
|
test(SysTime(0, UTC()), 1);
|
|
test(SysTime(1, UTC()), 1);
|
|
test(SysTime(-1, UTC()), 0);
|
|
|
|
foreach(year; chain(testYearsBC, testYearsAD))
|
|
{
|
|
foreach(md; testMonthDays)
|
|
{
|
|
foreach(tod; testTODs)
|
|
{
|
|
auto dt = DateTime(Date(year, md.month, md.day), tod);
|
|
|
|
foreach(tz; testTZs)
|
|
{
|
|
foreach(fs; testFracSecs)
|
|
test(SysTime(dt, fs, tz), year);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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 $(LREF SysTime)'s year to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the new year is not a leap year and the
|
|
resulting date would be on February 29th.
|
|
+/
|
|
@property void year(int year) @safe
|
|
{
|
|
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
|
|
{
|
|
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);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.range;
|
|
static void test(SysTime st, int year, in SysTime expected)
|
|
{
|
|
st.year = year;
|
|
assert(st == expected);
|
|
}
|
|
|
|
foreach(st; chain(testSysTimesBC, testSysTimesAD))
|
|
{
|
|
auto dt = cast(DateTime)st;
|
|
|
|
foreach(year; chain(testYearsBC, testYearsAD))
|
|
{
|
|
auto e = SysTime(DateTime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second),
|
|
st.fracSecs,
|
|
st.timezone);
|
|
test(st, year, e);
|
|
}
|
|
}
|
|
|
|
foreach(fs; testFracSecs)
|
|
{
|
|
foreach(tz; testTZs)
|
|
{
|
|
foreach(tod; testTODs)
|
|
{
|
|
test(SysTime(DateTime(Date(1999, 2, 28), tod), fs, tz), 2000,
|
|
SysTime(DateTime(Date(2000, 2, 28), tod), fs, tz));
|
|
test(SysTime(DateTime(Date(2000, 2, 28), tod), fs, tz), 1999,
|
|
SysTime(DateTime(Date(1999, 2, 28), tod), fs, tz));
|
|
}
|
|
|
|
foreach(tod; testTODsThrown)
|
|
{
|
|
auto st = SysTime(DateTime(Date(2000, 2, 29), tod), fs, tz);
|
|
assertThrown!DateTimeException(st.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 = 7));
|
|
//static assert(!__traits(compiles, ist.year = 7));
|
|
}
|
|
|
|
/++
|
|
Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if $(D isAD) is true.
|
|
+/
|
|
@property ushort yearBC() @safe const
|
|
{
|
|
return (cast(Date)this).yearBC;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.format : format;
|
|
foreach(st; testSysTimesBC)
|
|
{
|
|
auto msg = format("SysTime: %s", st);
|
|
assertNotThrown!DateTimeException(st.yearBC, msg);
|
|
assert(st.yearBC == (st.year * -1) + 1, msg);
|
|
}
|
|
|
|
foreach(st; [testSysTimesAD[0], testSysTimesAD[$/2], testSysTimesAD[$-1]])
|
|
assertThrown!DateTimeException(st.yearBC, format("SysTime: %s", st));
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
/++
|
|
Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
|
|
|
|
Params:
|
|
year = The year B.C. to set this $(LREF SysTime)'s year to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if a non-positive value is given.
|
|
+/
|
|
@property void yearBC(int year) @safe
|
|
{
|
|
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
|
|
{
|
|
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)));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.range;
|
|
static void test(SysTime st, int year, in SysTime expected)
|
|
{
|
|
import std.format : format;
|
|
st.yearBC = year;
|
|
assert(st == expected, format("SysTime: %s", st));
|
|
}
|
|
|
|
foreach(st; chain(testSysTimesBC, testSysTimesAD))
|
|
{
|
|
auto dt = cast(DateTime)st;
|
|
|
|
foreach(year; testYearsBC)
|
|
{
|
|
auto e = SysTime(DateTime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second),
|
|
st.fracSecs,
|
|
st.timezone);
|
|
test(st, (year * -1) + 1, e);
|
|
}
|
|
}
|
|
|
|
foreach(st; [testSysTimesBC[0], testSysTimesBC[$ - 1],
|
|
testSysTimesAD[0], testSysTimesAD[$ - 1]])
|
|
{
|
|
foreach(year; testYearsBC)
|
|
assertThrown!DateTimeException(st.yearBC = year);
|
|
}
|
|
|
|
foreach(fs; testFracSecs)
|
|
{
|
|
foreach(tz; testTZs)
|
|
{
|
|
foreach(tod; testTODs)
|
|
{
|
|
test(SysTime(DateTime(Date(-1999, 2, 28), tod), fs, tz), 2001,
|
|
SysTime(DateTime(Date(-2000, 2, 28), tod), fs, tz));
|
|
test(SysTime(DateTime(Date(-2000, 2, 28), tod), fs, tz), 2000,
|
|
SysTime(DateTime(Date(-1999, 2, 28), tod), fs, tz));
|
|
}
|
|
|
|
foreach(tod; testTODsThrown)
|
|
{
|
|
auto st = SysTime(DateTime(Date(-2000, 2, 29), tod), fs, tz);
|
|
assertThrown!DateTimeException(st.year = -1999);
|
|
}
|
|
}
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
/++
|
|
Month of a Gregorian Year.
|
|
+/
|
|
@property Month month() @safe const nothrow
|
|
{
|
|
return (cast(Date)this).month;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.range;
|
|
static void test(SysTime sysTime, Month expected)
|
|
{
|
|
import std.format : format;
|
|
assert(sysTime.month == expected,
|
|
format("Value given: %s", sysTime));
|
|
}
|
|
|
|
test(SysTime(0, UTC()), Month.jan);
|
|
test(SysTime(1, UTC()), Month.jan);
|
|
test(SysTime(-1, UTC()), Month.dec);
|
|
|
|
foreach(year; chain(testYearsBC, testYearsAD))
|
|
{
|
|
foreach(md; testMonthDays)
|
|
{
|
|
foreach(tod; testTODs)
|
|
{
|
|
auto dt = DateTime(Date(year, md.month, md.day), tod);
|
|
|
|
foreach(fs; testFracSecs)
|
|
{
|
|
foreach(tz; testTZs)
|
|
test(SysTime(dt, fs, tz), md.month);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
/++
|
|
Month of a Gregorian Year.
|
|
|
|
Params:
|
|
month = The month to set this $(LREF SysTime)'s month to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given month is not a valid month.
|
|
+/
|
|
@property void month(Month month) @safe
|
|
{
|
|
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
|
|
{
|
|
import std.range;
|
|
|
|
static void test(SysTime st, Month month, in SysTime expected)
|
|
{
|
|
st.month = cast(Month)month;
|
|
assert(st == expected);
|
|
}
|
|
|
|
foreach(st; chain(testSysTimesBC, testSysTimesAD))
|
|
{
|
|
auto dt = cast(DateTime)st;
|
|
|
|
foreach(md; testMonthDays)
|
|
{
|
|
if(st.day > maxDay(dt.year, md.month))
|
|
continue;
|
|
auto e = SysTime(DateTime(dt.year, md.month, dt.day, dt.hour, dt.minute, dt.second),
|
|
st.fracSecs,
|
|
st.timezone);
|
|
test(st, md.month, e);
|
|
}
|
|
}
|
|
|
|
foreach(fs; testFracSecs)
|
|
{
|
|
foreach(tz; testTZs)
|
|
{
|
|
foreach(tod; testTODs)
|
|
{
|
|
foreach(year; filter!((a){return yearIsLeapYear(a);})
|
|
(chain(testYearsBC, testYearsAD)))
|
|
{
|
|
test(SysTime(DateTime(Date(year, 1, 29), tod), fs, tz),
|
|
Month.feb,
|
|
SysTime(DateTime(Date(year, 2, 29), tod), fs, tz));
|
|
}
|
|
|
|
foreach(year; chain(testYearsBC, testYearsAD))
|
|
{
|
|
test(SysTime(DateTime(Date(year, 1, 28), tod), fs, tz),
|
|
Month.feb,
|
|
SysTime(DateTime(Date(year, 2, 28), tod), fs, tz));
|
|
test(SysTime(DateTime(Date(year, 7, 30), tod), fs, tz),
|
|
Month.jun,
|
|
SysTime(DateTime(Date(year, 6, 30), tod), fs, tz));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach(fs; [testFracSecs[0], testFracSecs[$-1]])
|
|
{
|
|
foreach(tz; testTZs)
|
|
{
|
|
foreach(tod; testTODsThrown)
|
|
{
|
|
foreach(year; [testYearsBC[$-3], testYearsBC[$-2],
|
|
testYearsBC[$-2], testYearsAD[0],
|
|
testYearsAD[$-2], testYearsAD[$-1]])
|
|
{
|
|
auto day = yearIsLeapYear(year) ? 30 : 29;
|
|
auto st1 = SysTime(DateTime(Date(year, 1, day), tod), fs, tz);
|
|
assertThrown!DateTimeException(st1.month = Month.feb);
|
|
|
|
auto st2 = SysTime(DateTime(Date(year, 7, 31), tod), fs, tz);
|
|
assertThrown!DateTimeException(st2.month = Month.jun);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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.
|
|
+/
|
|
@property ubyte day() @safe const nothrow
|
|
{
|
|
return (cast(Date)this).day;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.range;
|
|
|
|
static void test(SysTime sysTime, int expected)
|
|
{
|
|
import std.format : format;
|
|
assert(sysTime.day == expected,
|
|
format("Value given: %s", sysTime));
|
|
}
|
|
|
|
test(SysTime(0, UTC()), 1);
|
|
test(SysTime(1, UTC()), 1);
|
|
test(SysTime(-1, UTC()), 31);
|
|
|
|
foreach(year; chain(testYearsBC, testYearsAD))
|
|
{
|
|
foreach(md; testMonthDays)
|
|
{
|
|
foreach(tod; testTODs)
|
|
{
|
|
auto dt = DateTime(Date(year, md.month, md.day), tod);
|
|
|
|
foreach(tz; testTZs)
|
|
{
|
|
foreach(fs; testFracSecs)
|
|
test(SysTime(dt, fs, tz), md.day);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
/++
|
|
Day of a Gregorian Month.
|
|
|
|
Params:
|
|
day = The day of the month to set this $(LREF SysTime)'s day to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given day is not a valid day of the
|
|
current month.
|
|
+/
|
|
@property void day(int day) @safe
|
|
{
|
|
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
|
|
{
|
|
import std.format : format;
|
|
import std.range;
|
|
|
|
foreach(day; chain(testDays))
|
|
{
|
|
foreach(st; chain(testSysTimesBC, testSysTimesAD))
|
|
{
|
|
auto dt = cast(DateTime)st;
|
|
|
|
if(day > maxDay(dt.year, dt.month))
|
|
continue;
|
|
auto expected = SysTime(DateTime(dt.year, dt.month, day, dt.hour, dt.minute, dt.second),
|
|
st.fracSecs,
|
|
st.timezone);
|
|
st.day = day;
|
|
assert(st == expected, format("[%s] [%s]", st, expected));
|
|
}
|
|
}
|
|
|
|
foreach(tz; testTZs)
|
|
{
|
|
foreach(tod; testTODs)
|
|
{
|
|
foreach(fs; testFracSecs)
|
|
{
|
|
foreach(year; chain(testYearsBC, testYearsAD))
|
|
{
|
|
foreach(month; EnumMembers!Month)
|
|
{
|
|
auto st = SysTime(DateTime(Date(year, month, 1), tod), fs, tz);
|
|
immutable max = maxDay(year, month);
|
|
auto expected = SysTime(DateTime(Date(year, month, max), tod), fs, tz);
|
|
|
|
st.day = max;
|
|
assert(st == expected, format("[%s] [%s]", st, expected));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach(tz; testTZs)
|
|
{
|
|
foreach(tod; testTODsThrown)
|
|
{
|
|
foreach(fs; [testFracSecs[0], testFracSecs[$-1]])
|
|
{
|
|
foreach(year; [testYearsBC[$-3], testYearsBC[$-2],
|
|
testYearsBC[$-2], testYearsAD[0],
|
|
testYearsAD[$-2], testYearsAD[$-1]])
|
|
{
|
|
foreach(month; EnumMembers!Month)
|
|
{
|
|
auto st = SysTime(DateTime(Date(year, month, 1), tod), fs, tz);
|
|
immutable max = maxDay(year, month);
|
|
|
|
assertThrown!DateTimeException(st.day = max + 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, cst.day = 27));
|
|
//static assert(!__traits(compiles, ist.day = 27));
|
|
}
|
|
|
|
|
|
/++
|
|
Hours past midnight.
|
|
+/
|
|
@property ubyte hour() @safe 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
|
|
{
|
|
import std.range;
|
|
import std.format : format;
|
|
|
|
static void test(SysTime sysTime, int expected)
|
|
{
|
|
assert(sysTime.hour == expected,
|
|
format("Value given: %s", sysTime));
|
|
}
|
|
|
|
test(SysTime(0, UTC()), 0);
|
|
test(SysTime(1, UTC()), 0);
|
|
test(SysTime(-1, UTC()), 23);
|
|
|
|
foreach(tz; testTZs)
|
|
{
|
|
foreach(year; chain(testYearsBC, testYearsAD))
|
|
{
|
|
foreach(md; testMonthDays)
|
|
{
|
|
foreach(hour; testHours)
|
|
{
|
|
foreach(minute; testMinSecs)
|
|
{
|
|
foreach(second; testMinSecs)
|
|
{
|
|
auto dt = DateTime(Date(year, md.month, md.day),
|
|
TimeOfDay(hour, minute, second));
|
|
|
|
foreach(fs; testFracSecs)
|
|
test(SysTime(dt, fs, tz), hour);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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 $(LREF SysTime)'s hour to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given hour are not a valid hour of
|
|
the day.
|
|
+/
|
|
@property void hour(int hour) @safe
|
|
{
|
|
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
|
|
{
|
|
import std.range;
|
|
import std.format : format;
|
|
|
|
foreach(hour; chain(testHours))
|
|
{
|
|
foreach(st; chain(testSysTimesBC, testSysTimesAD))
|
|
{
|
|
auto dt = cast(DateTime)st;
|
|
auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, hour, dt.minute, dt.second),
|
|
st.fracSecs,
|
|
st.timezone);
|
|
st.hour = hour;
|
|
assert(st == expected, format("[%s] [%s]", st, expected));
|
|
}
|
|
}
|
|
|
|
auto st = testSysTimesAD[0];
|
|
assertThrown!DateTimeException(st.hour = -1);
|
|
assertThrown!DateTimeException(st.hour = 60);
|
|
|
|
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() @safe 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
|
|
{
|
|
import std.range;
|
|
import std.format : format;
|
|
|
|
static void test(SysTime sysTime, int expected)
|
|
{
|
|
assert(sysTime.minute == expected,
|
|
format("Value given: %s", sysTime));
|
|
}
|
|
|
|
test(SysTime(0, UTC()), 0);
|
|
test(SysTime(1, UTC()), 0);
|
|
test(SysTime(-1, UTC()), 59);
|
|
|
|
foreach(tz; testTZs)
|
|
{
|
|
foreach(year; chain(testYearsBC, testYearsAD))
|
|
{
|
|
foreach(md; testMonthDays)
|
|
{
|
|
foreach(hour; testHours)
|
|
{
|
|
foreach(minute; testMinSecs)
|
|
{
|
|
foreach(second; testMinSecs)
|
|
{
|
|
auto dt = DateTime(Date(year, md.month, md.day),
|
|
TimeOfDay(hour, minute, second));
|
|
|
|
foreach(fs; testFracSecs)
|
|
test(SysTime(dt, fs, tz), minute);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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:
|
|
minute = The minute to set this $(LREF SysTime)'s minute to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given minute are not a valid minute
|
|
of an hour.
|
|
+/
|
|
@property void minute(int minute) @safe
|
|
{
|
|
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
|
|
{
|
|
import std.range;
|
|
import std.format : format;
|
|
|
|
foreach(minute; testMinSecs)
|
|
{
|
|
foreach(st; chain(testSysTimesBC, testSysTimesAD))
|
|
{
|
|
auto dt = cast(DateTime)st;
|
|
auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, dt.hour, minute, dt.second),
|
|
st.fracSecs,
|
|
st.timezone);
|
|
st.minute = minute;
|
|
assert(st == expected, format("[%s] [%s]", st, expected));
|
|
}
|
|
}
|
|
|
|
auto st = testSysTimesAD[0];
|
|
assertThrown!DateTimeException(st.minute = -1);
|
|
assertThrown!DateTimeException(st.minute = 60);
|
|
|
|
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() @safe 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
|
|
{
|
|
import std.range;
|
|
import std.format : format;
|
|
|
|
static void test(SysTime sysTime, int expected)
|
|
{
|
|
assert(sysTime.second == expected,
|
|
format("Value given: %s", sysTime));
|
|
}
|
|
|
|
test(SysTime(0, UTC()), 0);
|
|
test(SysTime(1, UTC()), 0);
|
|
test(SysTime(-1, UTC()), 59);
|
|
|
|
foreach(tz; testTZs)
|
|
{
|
|
foreach(year; chain(testYearsBC, testYearsAD))
|
|
{
|
|
foreach(md; testMonthDays)
|
|
{
|
|
foreach(hour; testHours)
|
|
{
|
|
foreach(minute; testMinSecs)
|
|
{
|
|
foreach(second; testMinSecs)
|
|
{
|
|
auto dt = DateTime(Date(year, md.month, md.day),
|
|
TimeOfDay(hour, minute, second));
|
|
|
|
foreach(fs; testFracSecs)
|
|
test(SysTime(dt, fs, tz), second);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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 $(LREF SysTime)'s second to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given second are not a valid second
|
|
of a minute.
|
|
+/
|
|
@property void second(int second) @safe
|
|
{
|
|
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
|
|
{
|
|
import std.range;
|
|
import std.format : format;
|
|
|
|
foreach(second; testMinSecs)
|
|
{
|
|
foreach(st; chain(testSysTimesBC, testSysTimesAD))
|
|
{
|
|
auto dt = cast(DateTime)st;
|
|
auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, second),
|
|
st.fracSecs,
|
|
st.timezone);
|
|
st.second = second;
|
|
assert(st == expected, format("[%s] [%s]", st, expected));
|
|
}
|
|
}
|
|
|
|
auto st = testSysTimesAD[0];
|
|
assertThrown!DateTimeException(st.second = -1);
|
|
assertThrown!DateTimeException(st.second = 60);
|
|
|
|
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 past the second (i.e. the portion of a
|
|
$(LREF SysTime) which is less than a second).
|
|
+/
|
|
@property Duration fracSecs() @safe const nothrow
|
|
{
|
|
auto hnsecs = removeUnitsFromHNSecs!"days"(adjTime);
|
|
|
|
if(hnsecs < 0)
|
|
hnsecs += convert!("hours", "hnsecs")(24);
|
|
|
|
return dur!"hnsecs"(removeUnitsFromHNSecs!"seconds"(hnsecs));
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
auto dt = DateTime(1982, 4, 1, 20, 59, 22);
|
|
assert(SysTime(dt, msecs(213)).fracSecs == msecs(213));
|
|
assert(SysTime(dt, usecs(5202)).fracSecs == usecs(5202));
|
|
assert(SysTime(dt, hnsecs(1234567)).fracSecs == hnsecs(1234567));
|
|
|
|
// SysTime and Duration both have a precision of hnsecs (100 ns),
|
|
// so nsecs are going to be truncated.
|
|
assert(SysTime(dt, nsecs(123456789)).fracSecs == nsecs(123456700));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.range;
|
|
|
|
assert(SysTime(0, UTC()).fracSecs == Duration.zero);
|
|
assert(SysTime(1, UTC()).fracSecs == hnsecs(1));
|
|
assert(SysTime(-1, UTC()).fracSecs == hnsecs(9_999_999));
|
|
|
|
foreach(tz; testTZs)
|
|
{
|
|
foreach(year; chain(testYearsBC, testYearsAD))
|
|
{
|
|
foreach(md; testMonthDays)
|
|
{
|
|
foreach(hour; testHours)
|
|
{
|
|
foreach(minute; testMinSecs)
|
|
{
|
|
foreach(second; testMinSecs)
|
|
{
|
|
auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
|
|
foreach(fs; testFracSecs)
|
|
assert(SysTime(dt, fs, tz).fracSecs == fs);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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.fracSecs));
|
|
//static assert(__traits(compiles, ist.fracSecs));
|
|
}
|
|
|
|
|
|
/++
|
|
Fractional seconds past the second (i.e. the portion of a
|
|
$(LREF SysTime) which is less than a second).
|
|
|
|
Params:
|
|
fracSecs = The duration to set this $(LREF SysTime)'s fractional
|
|
seconds to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given duration is negative or if
|
|
it's greater than or equal to one second.
|
|
+/
|
|
@property void fracSecs(Duration fracSecs) @safe
|
|
{
|
|
enforce(fracSecs >= Duration.zero, new DateTimeException("A SysTime cannot have negative fractional seconds."));
|
|
enforce(fracSecs < seconds(1), new DateTimeException("Fractional seconds must be less than one second."));
|
|
|
|
auto oldHNSecs = adjTime;
|
|
auto days = splitUnitsFromHNSecs!"days"(oldHNSecs);
|
|
immutable daysHNSecs = convert!("days", "hnsecs")(days);
|
|
immutable negative = oldHNSecs < 0;
|
|
|
|
if(negative)
|
|
oldHNSecs += convert!("hours", "hnsecs")(24);
|
|
|
|
immutable seconds = splitUnitsFromHNSecs!"seconds"(oldHNSecs);
|
|
immutable secondsHNSecs = convert!("seconds", "hnsecs")(seconds);
|
|
auto newHNSecs = fracSecs.total!"hnsecs" + secondsHNSecs;
|
|
|
|
if(negative)
|
|
newHNSecs -= convert!("hours", "hnsecs")(24);
|
|
|
|
adjTime = daysHNSecs + newHNSecs;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
auto st = SysTime(DateTime(1982, 4, 1, 20, 59, 22));
|
|
assert(st.fracSecs == Duration.zero);
|
|
|
|
st.fracSecs = msecs(213);
|
|
assert(st.fracSecs == msecs(213));
|
|
|
|
st.fracSecs = hnsecs(1234567);
|
|
assert(st.fracSecs == hnsecs(1234567));
|
|
|
|
// SysTime has a precision of hnsecs (100 ns), so nsecs are
|
|
// going to be truncated.
|
|
st.fracSecs = nsecs(123456789);
|
|
assert(st.fracSecs == hnsecs(1234567));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.range;
|
|
import std.format : format;
|
|
|
|
foreach(fracSec; testFracSecs)
|
|
{
|
|
foreach(st; chain(testSysTimesBC, testSysTimesAD))
|
|
{
|
|
auto dt = cast(DateTime)st;
|
|
auto expected = SysTime(dt, fracSec, st.timezone);
|
|
st.fracSecs = fracSec;
|
|
assert(st == expected, format("[%s] [%s]", st, expected));
|
|
}
|
|
}
|
|
|
|
auto st = testSysTimesAD[0];
|
|
assertThrown!DateTimeException(st.fracSecs = hnsecs(-1));
|
|
assertThrown!DateTimeException(st.fracSecs = seconds(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, cst.fracSecs = msecs(7)));
|
|
//static assert(!__traits(compiles, ist.fracSecs = msecs(7)));
|
|
}
|
|
|
|
|
|
/++
|
|
$(RED Scheduled for deprecation. Please use $(LREF fracSecs) instead of
|
|
fracSec. It uses a $(CXREF time, Duration) to represent the
|
|
fractional seconds instead of a $(CXREF time, FracSec). This
|
|
overload will be deprecated in 2.068).
|
|
|
|
Fractional seconds past the second.
|
|
+/
|
|
//deprecated("Please use fracSecs (with an s) rather than fracSec (without an s). It returns a Duration instead of a FracSec, as FracSec is being deprecated.")
|
|
@property FracSec fracSec() @safe 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.");
|
|
}
|
|
|
|
/+deprecated+/ unittest
|
|
{
|
|
import std.range;
|
|
import std.format : format;
|
|
|
|
static void test(SysTime sysTime, FracSec expected, size_t line = __LINE__)
|
|
{
|
|
if(sysTime.fracSec != expected)
|
|
throw new AssertError(format("Value given: %s", sysTime.fracSec), __FILE__, line);
|
|
}
|
|
|
|
test(SysTime(0, UTC()), FracSec.from!"hnsecs"(0));
|
|
test(SysTime(1, UTC()), FracSec.from!"hnsecs"(1));
|
|
test(SysTime(-1, UTC()), FracSec.from!"hnsecs"(9_999_999));
|
|
|
|
foreach(tz; testTZs)
|
|
{
|
|
foreach(year; chain(testYearsBC, testYearsAD))
|
|
{
|
|
foreach(md; testMonthDays)
|
|
{
|
|
foreach(hour; testHours)
|
|
{
|
|
foreach(minute; testMinSecs)
|
|
{
|
|
foreach(second; testMinSecs)
|
|
{
|
|
auto dt = DateTime(Date(year, md.month, md.day),
|
|
TimeOfDay(hour, minute, second));
|
|
|
|
foreach(fs; testFracSecs)
|
|
test(SysTime(dt, fs, tz), FracSec.from!"hnsecs"(fs.total!"hnsecs"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
/++
|
|
$(RED Scheduled for deprecation. Please use $(LREF fracSecs) instead of
|
|
fracSec. It uses a $(CXREF time, Duration) to represent the
|
|
fractional seconds instead of a $(CXREF time, FracSec). This
|
|
overload will be deprecated in 2.068).
|
|
|
|
Fractional seconds past the second.
|
|
|
|
Params:
|
|
fracSec = The fractional seconds to set this $(LREF SysTime)'s
|
|
fractional seconds to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if $(D fracSec) is negative.
|
|
+/
|
|
//deprecated("Please use fracSecs (with an s) rather than fracSec (without an s). It takes a Duration instead of a FracSec, as FracSec is being deprecated.")
|
|
@property void fracSec(FracSec fracSec) @safe
|
|
{
|
|
immutable fracHNSecs = fracSec.hnsecs;
|
|
enforce(fracHNSecs >= 0, new DateTimeException("A SysTime cannot have negative fractional seconds."));
|
|
|
|
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 = fracHNSecs;
|
|
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;
|
|
}
|
|
|
|
/+deprecated+/ unittest
|
|
{
|
|
import std.range;
|
|
import std.format : format;
|
|
|
|
foreach(fracSec; testFracSecs)
|
|
{
|
|
foreach(st; chain(testSysTimesBC, testSysTimesAD))
|
|
{
|
|
auto dt = cast(DateTime)st;
|
|
auto expected = SysTime(dt, fracSec, st.timezone);
|
|
st.fracSec = FracSec.from!"hnsecs"(fracSec.total!"hnsecs");
|
|
assert(st == expected, format("[%s] [%s]", st, expected));
|
|
}
|
|
}
|
|
|
|
auto st = testSysTimesAD[0];
|
|
assertThrown!DateTimeException(st.fracSec = FracSec.from!"hnsecs"(-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, 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 $(LREF SysTime).
|
|
+/
|
|
@property long stdTime() @safe const pure nothrow
|
|
{
|
|
return _stdTime;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(SysTime(0).stdTime == 0);
|
|
assert(SysTime(1).stdTime == 1);
|
|
assert(SysTime(-1).stdTime == -1);
|
|
assert(SysTime(DateTime(1, 1, 1, 0, 0, 33), hnsecs(502), UTC()).stdTime == 330000502L);
|
|
assert(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 $(LREF SysTime).
|
|
|
|
Params:
|
|
stdTime = The number of hnsecs since January 1st, 1 A.D. UTC.
|
|
+/
|
|
@property void stdTime(long stdTime) @safe pure nothrow
|
|
{
|
|
_stdTime = stdTime;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
static void test(long stdTime, in SysTime expected, size_t line = __LINE__)
|
|
{
|
|
auto st = SysTime(0, UTC());
|
|
st.stdTime = stdTime;
|
|
assert(st == expected);
|
|
}
|
|
|
|
test(0, SysTime(Date(1, 1, 1), UTC()));
|
|
test(1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()));
|
|
test(-1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()));
|
|
test(330_000_502L, SysTime(DateTime(1, 1, 1, 0, 0, 33), hnsecs(502), UTC()));
|
|
test(621_355_968_000_000_000L, 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 $(LREF 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 $(LREF SysTime)'s time zone before returning.
|
|
+/
|
|
@property immutable(TimeZone) timezone() @safe const pure nothrow
|
|
{
|
|
return _timezone;
|
|
}
|
|
|
|
|
|
/++
|
|
The current time zone of this $(LREF 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 $(LREF SysTime)'s time zone before returning.
|
|
|
|
Params:
|
|
timezone = The $(LREF2 .TimeZone, TimeZone) to set this $(LREF SysTime)'s time zone to.
|
|
+/
|
|
@property void timezone(immutable TimeZone timezone) @safe pure nothrow
|
|
{
|
|
if(timezone is null)
|
|
_timezone = LocalTime();
|
|
else
|
|
_timezone = timezone;
|
|
}
|
|
|
|
|
|
/++
|
|
Returns whether DST is in effect for this $(LREF SysTime).
|
|
+/
|
|
@property bool dstInEffect() @safe const nothrow
|
|
{
|
|
return _timezone.dstInEffect(_stdTime);
|
|
//This function's unit testing is done in the time zone classes.
|
|
}
|
|
|
|
|
|
/++
|
|
Returns what the offset from UTC is for this $(LREF SysTime).
|
|
It includes the DST offset in effect at that time (if any).
|
|
+/
|
|
@property Duration utcOffset() @safe const nothrow
|
|
{
|
|
return _timezone.utcOffsetAt(_stdTime);
|
|
}
|
|
|
|
|
|
/++
|
|
Returns a $(LREF SysTime) with the same std time as this one, but with
|
|
$(LREF LocalTime) as its time zone.
|
|
+/
|
|
SysTime toLocalTime() @safe const pure nothrow
|
|
{
|
|
return SysTime(_stdTime, LocalTime());
|
|
}
|
|
|
|
unittest
|
|
{
|
|
{
|
|
auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
|
|
assert(sysTime == sysTime.toLocalTime());
|
|
assert(sysTime._stdTime == sysTime.toLocalTime()._stdTime);
|
|
assert(sysTime.toLocalTime().timezone is LocalTime());
|
|
assert(sysTime.toLocalTime().timezone is sysTime.timezone);
|
|
assert(sysTime.toLocalTime().timezone !is UTC());
|
|
}
|
|
|
|
{
|
|
auto stz = new immutable SimpleTimeZone(dur!"minutes"(-3 * 60));
|
|
auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27), stz);
|
|
assert(sysTime == sysTime.toLocalTime());
|
|
assert(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 $(LREF SysTime) with the same std time as this one, but with
|
|
$(D UTC) as its time zone.
|
|
+/
|
|
SysTime toUTC() @safe const pure nothrow
|
|
{
|
|
return SysTime(_stdTime, UTC());
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
|
|
assert(sysTime == sysTime.toUTC());
|
|
assert(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 $(LREF SysTime) with the same std time as this one, but with
|
|
given time zone as its time zone.
|
|
+/
|
|
SysTime toOtherTZ(immutable TimeZone tz) @safe const pure nothrow
|
|
{
|
|
if(tz is null)
|
|
return SysTime(_stdTime, LocalTime());
|
|
else
|
|
return SysTime(_stdTime, tz);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto stz = new immutable SimpleTimeZone(dur!"minutes"(11 * 60));
|
|
auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
|
|
assert(sysTime == sysTime.toOtherTZ(stz));
|
|
assert(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 $(D time_t) which represents the same time as this
|
|
$(LREF SysTime).
|
|
|
|
Note that like all conversions in std.datetime, this is a truncating
|
|
conversion.
|
|
|
|
If $(D 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 $(D time_t.max) if it goes over and $(D time_t.min) if it goes
|
|
under).
|
|
+/
|
|
time_t toUnixTime() @safe const pure nothrow
|
|
{
|
|
return stdTimeToUnixTime(_stdTime);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime() == 0);
|
|
assert(SysTime(DateTime(1970, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toUnixTime() == 0);
|
|
assert(SysTime(DateTime(1970, 1, 1, 0, 0, 0), usecs(1), UTC()).toUnixTime() == 0);
|
|
assert(SysTime(DateTime(1970, 1, 1, 0, 0, 0), msecs(1), UTC()).toUnixTime() == 0);
|
|
assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toUnixTime() == 1);
|
|
assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toUnixTime() == 0);
|
|
assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toUnixTime() == 0);
|
|
assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toUnixTime() == 0);
|
|
assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toUnixTime() == -1);
|
|
}
|
|
|
|
|
|
/++
|
|
Returns a $(D timeval) which represents this $(LREF SysTime).
|
|
|
|
Note that like all conversions in std.datetime, this is a truncating
|
|
conversion.
|
|
|
|
If $(D 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 for $(D tv_sec). (so $(D time_t.max) if it goes over and
|
|
$(D time_t.min) if it goes under).
|
|
+/
|
|
timeval toTimeVal() @safe const pure nothrow
|
|
{
|
|
immutable tv_sec = toUnixTime();
|
|
|
|
immutable fracHNSecs = removeUnitsFromHNSecs!"seconds"(_stdTime - 621355968000000000L);
|
|
immutable tv_usec = cast(int)convert!("hnsecs", "usecs")(fracHNSecs);
|
|
|
|
return timeval(tv_sec, tv_usec);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(SysTime(DateTime(1970, 1, 1), UTC()).toTimeVal() == timeval(0, 0));
|
|
assert(SysTime(DateTime(1970, 1, 1), hnsecs(9), UTC()).toTimeVal() == timeval(0, 0));
|
|
assert(SysTime(DateTime(1970, 1, 1), hnsecs(10), UTC()).toTimeVal() == timeval(0, 1));
|
|
assert(SysTime(DateTime(1970, 1, 1), usecs(7), UTC()).toTimeVal() == timeval(0, 7));
|
|
|
|
assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toTimeVal() == timeval(1, 0));
|
|
assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(9), UTC()).toTimeVal() == timeval(1, 0));
|
|
assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(10), UTC()).toTimeVal() == timeval(1, 1));
|
|
assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), usecs(7), UTC()).toTimeVal() == timeval(1, 7));
|
|
|
|
assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toTimeVal() == timeval(0, 0));
|
|
assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_990), UTC()).toTimeVal() == timeval(0, -1));
|
|
|
|
assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toTimeVal() == timeval(0, -1));
|
|
assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999), UTC()).toTimeVal() == timeval(0, -999_001));
|
|
assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toTimeVal() == timeval(0, -1000));
|
|
assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toTimeVal() == timeval(-1, 0));
|
|
assert(SysTime(DateTime(1969, 12, 31, 23, 59, 58), usecs(17), UTC()).toTimeVal() == timeval(-1, -999_983));
|
|
}
|
|
|
|
|
|
/++
|
|
Returns a $(D tm) which represents this $(LREF SysTime).
|
|
+/
|
|
tm toTM() @safe const nothrow
|
|
{
|
|
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)
|
|
{
|
|
import std.utf : toUTFz;
|
|
timeInfo.tm_gmtoff = cast(int)convert!("hnsecs", "seconds")(adjTime - _stdTime);
|
|
auto zone = (timeInfo.tm_isdst ? _timezone.dstName : _timezone.stdName);
|
|
timeInfo.tm_zone = zone.toUTFz!(char*)();
|
|
}
|
|
|
|
return timeInfo;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.conv : to;
|
|
version(Posix)
|
|
{
|
|
scope(exit) clearTZEnvVar();
|
|
setTZEnvVar("America/Los_Angeles");
|
|
}
|
|
|
|
{
|
|
auto timeInfo = SysTime(DateTime(1970, 1, 1)).toTM();
|
|
|
|
assert(timeInfo.tm_sec == 0);
|
|
assert(timeInfo.tm_min == 0);
|
|
assert(timeInfo.tm_hour == 0);
|
|
assert(timeInfo.tm_mday == 1);
|
|
assert(timeInfo.tm_mon == 0);
|
|
assert(timeInfo.tm_year == 70);
|
|
assert(timeInfo.tm_wday == 4);
|
|
assert(timeInfo.tm_yday == 0);
|
|
|
|
version(Posix)
|
|
assert(timeInfo.tm_isdst == 0);
|
|
else version(Windows)
|
|
assert(timeInfo.tm_isdst == 0 || timeInfo.tm_isdst == 1);
|
|
|
|
version(Posix)
|
|
{
|
|
assert(timeInfo.tm_gmtoff == -8 * 60 * 60);
|
|
assert(to!string(timeInfo.tm_zone) == "PST");
|
|
}
|
|
}
|
|
|
|
{
|
|
auto timeInfo = SysTime(DateTime(2010, 7, 4, 12, 15, 7), hnsecs(15)).toTM();
|
|
|
|
assert(timeInfo.tm_sec == 7);
|
|
assert(timeInfo.tm_min == 15);
|
|
assert(timeInfo.tm_hour == 12);
|
|
assert(timeInfo.tm_mday == 4);
|
|
assert(timeInfo.tm_mon == 6);
|
|
assert(timeInfo.tm_year == 110);
|
|
assert(timeInfo.tm_wday == 0);
|
|
assert(timeInfo.tm_yday == 184);
|
|
|
|
version(Posix)
|
|
assert(timeInfo.tm_isdst == 1);
|
|
else version(Windows)
|
|
assert(timeInfo.tm_isdst == 0 || timeInfo.tm_isdst == 1);
|
|
|
|
version(Posix)
|
|
{
|
|
assert(timeInfo.tm_gmtoff == -7 * 60 * 60);
|
|
assert(to!string(timeInfo.tm_zone) == "PDT");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
Adds the given number of years or months to this $(LREF 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 day 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
|
|
$(LREF SysTime).
|
|
allowOverflow = Whether the days should be allowed to overflow,
|
|
causing the month to increment.
|
|
+/
|
|
ref SysTime add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe 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(value, 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;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
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.yes
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 6));
|
|
sysTime.add!"years"(7);
|
|
assert(sysTime == SysTime(Date(2006, 7, 6)));
|
|
sysTime.add!"years"(-9);
|
|
assert(sysTime == SysTime(Date(1997, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 2, 28));
|
|
sysTime.add!"years"(1);
|
|
assert(sysTime == SysTime(Date(2000, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(2000, 2, 29));
|
|
sysTime.add!"years"(-1);
|
|
assert(sysTime == SysTime(Date(1999, 3, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 7, 3), msecs(234));
|
|
sysTime.add!"years"(7);
|
|
assert(sysTime == SysTime(DateTime(2006, 7, 6, 12, 7, 3), msecs(234)));
|
|
sysTime.add!"years"(-9);
|
|
assert(sysTime == SysTime(DateTime(1997, 7, 6, 12, 7, 3), msecs(234)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207));
|
|
sysTime.add!"years"(1);
|
|
assert(sysTime == SysTime(DateTime(2000, 2, 28, 0, 7, 2), usecs(1207)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(2000, 2, 29, 0, 7, 2), usecs(1207));
|
|
sysTime.add!"years"(-1);
|
|
assert(sysTime == SysTime(DateTime(1999, 3, 1, 0, 7, 2), usecs(1207)));
|
|
}
|
|
|
|
//Test B.C.
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 6));
|
|
sysTime.add!"years"(-7);
|
|
assert(sysTime == SysTime(Date(-2006, 7, 6)));
|
|
sysTime.add!"years"(9);
|
|
assert(sysTime == SysTime(Date(-1997, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 2, 28));
|
|
sysTime.add!"years"(-1);
|
|
assert(sysTime == SysTime(Date(-2000, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-2000, 2, 29));
|
|
sysTime.add!"years"(1);
|
|
assert(sysTime == SysTime(Date(-1999, 3, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 7, 3), msecs(234));
|
|
sysTime.add!"years"(-7);
|
|
assert(sysTime == SysTime(DateTime(-2006, 7, 6, 12, 7, 3), msecs(234)));
|
|
sysTime.add!"years"(9);
|
|
assert(sysTime == SysTime(DateTime(-1997, 7, 6, 12, 7, 3), msecs(234)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3));
|
|
sysTime.add!"years"(-1);
|
|
assert(sysTime == SysTime(DateTime(-2000, 2, 28, 3, 3, 3), hnsecs(3)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-2000, 2, 29, 3, 3, 3), hnsecs(3));
|
|
sysTime.add!"years"(1);
|
|
assert(sysTime == SysTime(DateTime(-1999, 3, 1, 3, 3, 3), hnsecs(3)));
|
|
}
|
|
|
|
//Test Both
|
|
{
|
|
auto sysTime = SysTime(Date(4, 7, 6));
|
|
sysTime.add!"years"(-5);
|
|
assert(sysTime == SysTime(Date(-1, 7, 6)));
|
|
sysTime.add!"years"(5);
|
|
assert(sysTime == SysTime(Date(4, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-4, 7, 6));
|
|
sysTime.add!"years"(5);
|
|
assert(sysTime == SysTime(Date(1, 7, 6)));
|
|
sysTime.add!"years"(-5);
|
|
assert(sysTime == SysTime(Date(-4, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(4, 7, 6));
|
|
sysTime.add!"years"(-8);
|
|
assert(sysTime == SysTime(Date(-4, 7, 6)));
|
|
sysTime.add!"years"(8);
|
|
assert(sysTime == SysTime(Date(4, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-4, 7, 6));
|
|
sysTime.add!"years"(8);
|
|
assert(sysTime == SysTime(Date(4, 7, 6)));
|
|
sysTime.add!"years"(-8);
|
|
assert(sysTime == SysTime(Date(-4, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-4, 2, 29));
|
|
sysTime.add!"years"(5);
|
|
assert(sysTime == SysTime(Date(1, 3, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(4, 2, 29));
|
|
sysTime.add!"years"(-5);
|
|
assert(sysTime == SysTime(Date(-1, 3, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
|
|
sysTime.add!"years"(-1);
|
|
assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
|
|
sysTime.add!"years"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.add!"years"(-1);
|
|
assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
sysTime.add!"years"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 1, 1, 0, 0, 0));
|
|
sysTime.add!"years"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
sysTime.add!"years"(-1);
|
|
assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.add!"years"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
sysTime.add!"years"(-1);
|
|
assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
|
|
sysTime.add!"years"(-5);
|
|
assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
|
|
sysTime.add!"years"(5);
|
|
assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329));
|
|
sysTime.add!"years"(5);
|
|
assert(sysTime == SysTime(DateTime(1, 7, 6, 14, 7, 1), usecs(54329)));
|
|
sysTime.add!"years"(-5);
|
|
assert(sysTime == SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-4, 2, 29, 5, 5, 5), msecs(555));
|
|
sysTime.add!"years"(5);
|
|
assert(sysTime == SysTime(DateTime(1, 3, 1, 5, 5, 5), msecs(555)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
|
|
sysTime.add!"years"(-5);
|
|
assert(sysTime == SysTime(DateTime(-1, 3, 1, 5, 5, 5), msecs(555)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
|
|
sysTime.add!"years"(-5).add!"years"(7);
|
|
assert(sysTime == SysTime(DateTime(6, 3, 1, 5, 5, 5), 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)));
|
|
}
|
|
|
|
//Test add!"years"() with AllowDayOverlow.no
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 6));
|
|
sysTime.add!"years"(7, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(2006, 7, 6)));
|
|
sysTime.add!"years"(-9, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1997, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 2, 28));
|
|
sysTime.add!"years"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(2000, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(2000, 2, 29));
|
|
sysTime.add!"years"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 7, 3), msecs(234));
|
|
sysTime.add!"years"(7, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(2006, 7, 6, 12, 7, 3), msecs(234)));
|
|
sysTime.add!"years"(-9, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1997, 7, 6, 12, 7, 3), msecs(234)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207));
|
|
sysTime.add!"years"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(2000, 2, 28, 0, 7, 2), usecs(1207)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(2000, 2, 29, 0, 7, 2), usecs(1207));
|
|
sysTime.add!"years"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207)));
|
|
}
|
|
|
|
//Test B.C.
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 6));
|
|
sysTime.add!"years"(-7, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-2006, 7, 6)));
|
|
sysTime.add!"years"(9, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1997, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 2, 28));
|
|
sysTime.add!"years"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-2000, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-2000, 2, 29));
|
|
sysTime.add!"years"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 7, 3), msecs(234));
|
|
sysTime.add!"years"(-7, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-2006, 7, 6, 12, 7, 3), msecs(234)));
|
|
sysTime.add!"years"(9, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-1997, 7, 6, 12, 7, 3), msecs(234)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3));
|
|
sysTime.add!"years"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-2000, 2, 28, 3, 3, 3), hnsecs(3)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-2000, 2, 29, 3, 3, 3), hnsecs(3));
|
|
sysTime.add!"years"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3)));
|
|
}
|
|
|
|
//Test Both
|
|
{
|
|
auto sysTime = SysTime(Date(4, 7, 6));
|
|
sysTime.add!"years"(-5, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1, 7, 6)));
|
|
sysTime.add!"years"(5, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(4, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-4, 7, 6));
|
|
sysTime.add!"years"(5, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1, 7, 6)));
|
|
sysTime.add!"years"(-5, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-4, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(4, 7, 6));
|
|
sysTime.add!"years"(-8, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-4, 7, 6)));
|
|
sysTime.add!"years"(8, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(4, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-4, 7, 6));
|
|
sysTime.add!"years"(8, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(4, 7, 6)));
|
|
sysTime.add!"years"(-8, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-4, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-4, 2, 29));
|
|
sysTime.add!"years"(5, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(4, 2, 29));
|
|
sysTime.add!"years"(-5, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
|
|
sysTime.add!"years"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
|
|
sysTime.add!"years"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.add!"years"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
sysTime.add!"years"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 1, 1, 0, 0, 0));
|
|
sysTime.add!"years"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
sysTime.add!"years"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.add!"years"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
sysTime.add!"years"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
|
|
sysTime.add!"years"(-5);
|
|
assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
|
|
sysTime.add!"years"(5);
|
|
assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
|
|
sysTime.add!"years"(-5, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
|
|
sysTime.add!"years"(5, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329));
|
|
sysTime.add!"years"(5, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1, 7, 6, 14, 7, 1), usecs(54329)));
|
|
sysTime.add!"years"(-5, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-4, 2, 29, 5, 5, 5), msecs(555));
|
|
sysTime.add!"years"(5, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1, 2, 28, 5, 5, 5), msecs(555)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
|
|
sysTime.add!"years"(-5, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-1, 2, 28, 5, 5, 5), msecs(555)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
|
|
sysTime.add!"years"(-5, AllowDayOverflow.no).add!"years"(7, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(6, 2, 28, 5, 5, 5), msecs(555)));
|
|
}
|
|
}
|
|
|
|
//Test add!"months"() with AllowDayOverlow.yes
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 6));
|
|
sysTime.add!"months"(3);
|
|
assert(sysTime == SysTime(Date(1999, 10, 6)));
|
|
sysTime.add!"months"(-4);
|
|
assert(sysTime == SysTime(Date(1999, 6, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 6));
|
|
sysTime.add!"months"(6);
|
|
assert(sysTime == SysTime(Date(2000, 1, 6)));
|
|
sysTime.add!"months"(-6);
|
|
assert(sysTime == SysTime(Date(1999, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 6));
|
|
sysTime.add!"months"(27);
|
|
assert(sysTime == SysTime(Date(2001, 10, 6)));
|
|
sysTime.add!"months"(-28);
|
|
assert(sysTime == SysTime(Date(1999, 6, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 5, 31));
|
|
sysTime.add!"months"(1);
|
|
assert(sysTime == SysTime(Date(1999, 7, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 5, 31));
|
|
sysTime.add!"months"(-1);
|
|
assert(sysTime == SysTime(Date(1999, 5, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 2, 28));
|
|
sysTime.add!"months"(12);
|
|
assert(sysTime == SysTime(Date(2000, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(2000, 2, 29));
|
|
sysTime.add!"months"(12);
|
|
assert(sysTime == SysTime(Date(2001, 3, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 31));
|
|
sysTime.add!"months"(1);
|
|
assert(sysTime == SysTime(Date(1999, 8, 31)));
|
|
sysTime.add!"months"(1);
|
|
assert(sysTime == SysTime(Date(1999, 10, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1998, 8, 31));
|
|
sysTime.add!"months"(13);
|
|
assert(sysTime == SysTime(Date(1999, 10, 1)));
|
|
sysTime.add!"months"(-13);
|
|
assert(sysTime == SysTime(Date(1998, 9, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1997, 12, 31));
|
|
sysTime.add!"months"(13);
|
|
assert(sysTime == SysTime(Date(1999, 1, 31)));
|
|
sysTime.add!"months"(-13);
|
|
assert(sysTime == SysTime(Date(1997, 12, 31)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1997, 12, 31));
|
|
sysTime.add!"months"(14);
|
|
assert(sysTime == SysTime(Date(1999, 3, 3)));
|
|
sysTime.add!"months"(-14);
|
|
assert(sysTime == SysTime(Date(1998, 1, 3)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1998, 12, 31));
|
|
sysTime.add!"months"(14);
|
|
assert(sysTime == SysTime(Date(2000, 3, 2)));
|
|
sysTime.add!"months"(-14);
|
|
assert(sysTime == SysTime(Date(1999, 1, 2)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 12, 31));
|
|
sysTime.add!"months"(14);
|
|
assert(sysTime == SysTime(Date(2001, 3, 3)));
|
|
sysTime.add!"months"(-14);
|
|
assert(sysTime == SysTime(Date(2000, 1, 3)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
|
|
sysTime.add!"months"(3);
|
|
assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
|
|
sysTime.add!"months"(-4);
|
|
assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
|
|
sysTime.add!"months"(14);
|
|
assert(sysTime == SysTime(DateTime(2000, 3, 2, 7, 7, 7), hnsecs(422202)));
|
|
sysTime.add!"months"(-14);
|
|
assert(sysTime == SysTime(DateTime(1999, 1, 2, 7, 7, 7), hnsecs(422202)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
|
|
sysTime.add!"months"(14);
|
|
assert(sysTime == SysTime(DateTime(2001, 3, 3, 7, 7, 7), hnsecs(422202)));
|
|
sysTime.add!"months"(-14);
|
|
assert(sysTime == SysTime(DateTime(2000, 1, 3, 7, 7, 7), hnsecs(422202)));
|
|
}
|
|
|
|
//Test B.C.
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 6));
|
|
sysTime.add!"months"(3);
|
|
assert(sysTime == SysTime(Date(-1999, 10, 6)));
|
|
sysTime.add!"months"(-4);
|
|
assert(sysTime == SysTime(Date(-1999, 6, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 6));
|
|
sysTime.add!"months"(6);
|
|
assert(sysTime == SysTime(Date(-1998, 1, 6)));
|
|
sysTime.add!"months"(-6);
|
|
assert(sysTime == SysTime(Date(-1999, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 6));
|
|
sysTime.add!"months"(-27);
|
|
assert(sysTime == SysTime(Date(-2001, 4, 6)));
|
|
sysTime.add!"months"(28);
|
|
assert(sysTime == SysTime(Date(-1999, 8, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 5, 31));
|
|
sysTime.add!"months"(1);
|
|
assert(sysTime == SysTime(Date(-1999, 7, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 5, 31));
|
|
sysTime.add!"months"(-1);
|
|
assert(sysTime == SysTime(Date(-1999, 5, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 2, 28));
|
|
sysTime.add!"months"(-12);
|
|
assert(sysTime == SysTime(Date(-2000, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-2000, 2, 29));
|
|
sysTime.add!"months"(-12);
|
|
assert(sysTime == SysTime(Date(-2001, 3, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 31));
|
|
sysTime.add!"months"(1);
|
|
assert(sysTime == SysTime(Date(-1999, 8, 31)));
|
|
sysTime.add!"months"(1);
|
|
assert(sysTime == SysTime(Date(-1999, 10, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1998, 8, 31));
|
|
sysTime.add!"months"(13);
|
|
assert(sysTime == SysTime(Date(-1997, 10, 1)));
|
|
sysTime.add!"months"(-13);
|
|
assert(sysTime == SysTime(Date(-1998, 9, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1997, 12, 31));
|
|
sysTime.add!"months"(13);
|
|
assert(sysTime == SysTime(Date(-1995, 1, 31)));
|
|
sysTime.add!"months"(-13);
|
|
assert(sysTime == SysTime(Date(-1997, 12, 31)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1997, 12, 31));
|
|
sysTime.add!"months"(14);
|
|
assert(sysTime == SysTime(Date(-1995, 3, 3)));
|
|
sysTime.add!"months"(-14);
|
|
assert(sysTime == SysTime(Date(-1996, 1, 3)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-2002, 12, 31));
|
|
sysTime.add!"months"(14);
|
|
assert(sysTime == SysTime(Date(-2000, 3, 2)));
|
|
sysTime.add!"months"(-14);
|
|
assert(sysTime == SysTime(Date(-2001, 1, 2)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-2001, 12, 31));
|
|
sysTime.add!"months"(14);
|
|
assert(sysTime == SysTime(Date(-1999, 3, 3)));
|
|
sysTime.add!"months"(-14);
|
|
assert(sysTime == SysTime(Date(-2000, 1, 3)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
|
|
sysTime.add!"months"(3);
|
|
assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
|
|
sysTime.add!"months"(-4);
|
|
assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
|
|
sysTime.add!"months"(14);
|
|
assert(sysTime == SysTime(DateTime(-2000, 3, 2, 7, 7, 7), hnsecs(422202)));
|
|
sysTime.add!"months"(-14);
|
|
assert(sysTime == SysTime(DateTime(-2001, 1, 2, 7, 7, 7), hnsecs(422202)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
|
|
sysTime.add!"months"(14);
|
|
assert(sysTime == SysTime(DateTime(-1999, 3, 3, 7, 7, 7), hnsecs(422202)));
|
|
sysTime.add!"months"(-14);
|
|
assert(sysTime == SysTime(DateTime(-2000, 1, 3, 7, 7, 7), hnsecs(422202)));
|
|
}
|
|
|
|
//Test Both
|
|
{
|
|
auto sysTime = SysTime(Date(1, 1, 1));
|
|
sysTime.add!"months"(-1);
|
|
assert(sysTime == SysTime(Date(0, 12, 1)));
|
|
sysTime.add!"months"(1);
|
|
assert(sysTime == SysTime(Date(1, 1, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(4, 1, 1));
|
|
sysTime.add!"months"(-48);
|
|
assert(sysTime == SysTime(Date(0, 1, 1)));
|
|
sysTime.add!"months"(48);
|
|
assert(sysTime == SysTime(Date(4, 1, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(4, 3, 31));
|
|
sysTime.add!"months"(-49);
|
|
assert(sysTime == SysTime(Date(0, 3, 2)));
|
|
sysTime.add!"months"(49);
|
|
assert(sysTime == SysTime(Date(4, 4, 2)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(4, 3, 31));
|
|
sysTime.add!"months"(-85);
|
|
assert(sysTime == SysTime(Date(-3, 3, 3)));
|
|
sysTime.add!"months"(85);
|
|
assert(sysTime == SysTime(Date(4, 4, 3)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
|
|
sysTime.add!"months"(-1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
|
|
sysTime.add!"months"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.add!"months"(-1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
sysTime.add!"months"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
|
|
sysTime.add!"months"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
sysTime.add!"months"(-1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.add!"months"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
sysTime.add!"months"(-1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
|
|
sysTime.add!"months"(-1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 7, 9), hnsecs(17)));
|
|
sysTime.add!"months"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
|
|
sysTime.add!"months"(-85);
|
|
assert(sysTime == SysTime(DateTime(-3, 3, 3, 12, 11, 10), msecs(9)));
|
|
sysTime.add!"months"(85);
|
|
assert(sysTime == SysTime(DateTime(4, 4, 3, 12, 11, 10), msecs(9)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
|
|
sysTime.add!"months"(85);
|
|
assert(sysTime == SysTime(DateTime(4, 5, 1, 12, 11, 10), msecs(9)));
|
|
sysTime.add!"months"(-85);
|
|
assert(sysTime == SysTime(DateTime(-3, 4, 1, 12, 11, 10), msecs(9)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
|
|
sysTime.add!"months"(85).add!"months"(-83);
|
|
assert(sysTime == SysTime(DateTime(-3, 6, 1, 12, 11, 10), 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)));
|
|
}
|
|
|
|
//Test add!"months"() with AllowDayOverlow.no
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 6));
|
|
sysTime.add!"months"(3, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 10, 6)));
|
|
sysTime.add!"months"(-4, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 6, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 6));
|
|
sysTime.add!"months"(6, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(2000, 1, 6)));
|
|
sysTime.add!"months"(-6, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 6));
|
|
sysTime.add!"months"(27, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(2001, 10, 6)));
|
|
sysTime.add!"months"(-28, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 6, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 5, 31));
|
|
sysTime.add!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 6, 30)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 5, 31));
|
|
sysTime.add!"months"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 4, 30)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 2, 28));
|
|
sysTime.add!"months"(12, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(2000, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(2000, 2, 29));
|
|
sysTime.add!"months"(12, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(2001, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 31));
|
|
sysTime.add!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 8, 31)));
|
|
sysTime.add!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 9, 30)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1998, 8, 31));
|
|
sysTime.add!"months"(13, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 9, 30)));
|
|
sysTime.add!"months"(-13, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1998, 8, 30)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1997, 12, 31));
|
|
sysTime.add!"months"(13, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 1, 31)));
|
|
sysTime.add!"months"(-13, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1997, 12, 31)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1997, 12, 31));
|
|
sysTime.add!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 2, 28)));
|
|
sysTime.add!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1997, 12, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1998, 12, 31));
|
|
sysTime.add!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(2000, 2, 29)));
|
|
sysTime.add!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1998, 12, 29)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 12, 31));
|
|
sysTime.add!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(2001, 2, 28)));
|
|
sysTime.add!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 12, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
|
|
sysTime.add!"months"(3, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
|
|
sysTime.add!"months"(-4, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
|
|
sysTime.add!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(2000, 2, 29, 7, 7, 7), hnsecs(422202)));
|
|
sysTime.add!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1998, 12, 29, 7, 7, 7), hnsecs(422202)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
|
|
sysTime.add!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(2001, 2, 28, 7, 7, 7), hnsecs(422202)));
|
|
sysTime.add!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1999, 12, 28, 7, 7, 7), hnsecs(422202)));
|
|
}
|
|
|
|
//Test B.C.
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 6));
|
|
sysTime.add!"months"(3, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 10, 6)));
|
|
sysTime.add!"months"(-4, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 6, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 6));
|
|
sysTime.add!"months"(6, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1998, 1, 6)));
|
|
sysTime.add!"months"(-6, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 6));
|
|
sysTime.add!"months"(-27, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-2001, 4, 6)));
|
|
sysTime.add!"months"(28, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 8, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 5, 31));
|
|
sysTime.add!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 6, 30)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 5, 31));
|
|
sysTime.add!"months"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 4, 30)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 2, 28));
|
|
sysTime.add!"months"(-12, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-2000, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-2000, 2, 29));
|
|
sysTime.add!"months"(-12, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-2001, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 31));
|
|
sysTime.add!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 8, 31)));
|
|
sysTime.add!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 9, 30)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1998, 8, 31));
|
|
sysTime.add!"months"(13, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1997, 9, 30)));
|
|
sysTime.add!"months"(-13, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1998, 8, 30)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1997, 12, 31));
|
|
sysTime.add!"months"(13, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1995, 1, 31)));
|
|
sysTime.add!"months"(-13, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1997, 12, 31)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1997, 12, 31));
|
|
sysTime.add!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1995, 2, 28)));
|
|
sysTime.add!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1997, 12, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-2002, 12, 31));
|
|
sysTime.add!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-2000, 2, 29)));
|
|
sysTime.add!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-2002, 12, 29)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-2001, 12, 31));
|
|
sysTime.add!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 2, 28)));
|
|
sysTime.add!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-2001, 12, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
|
|
sysTime.add!"months"(3, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
|
|
sysTime.add!"months"(-4, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
|
|
sysTime.add!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-2000, 2, 29, 7, 7, 7), hnsecs(422202)));
|
|
sysTime.add!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-2002, 12, 29, 7, 7, 7), hnsecs(422202)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
|
|
sysTime.add!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-1999, 2, 28, 7, 7, 7), hnsecs(422202)));
|
|
sysTime.add!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-2001, 12, 28, 7, 7, 7), hnsecs(422202)));
|
|
}
|
|
|
|
//Test Both
|
|
{
|
|
auto sysTime = SysTime(Date(1, 1, 1));
|
|
sysTime.add!"months"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(0, 12, 1)));
|
|
sysTime.add!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1, 1, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(4, 1, 1));
|
|
sysTime.add!"months"(-48, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(0, 1, 1)));
|
|
sysTime.add!"months"(48, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(4, 1, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(4, 3, 31));
|
|
sysTime.add!"months"(-49, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(0, 2, 29)));
|
|
sysTime.add!"months"(49, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(4, 3, 29)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(4, 3, 31));
|
|
sysTime.add!"months"(-85, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-3, 2, 28)));
|
|
sysTime.add!"months"(85, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(4, 3, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
|
|
sysTime.add!"months"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
|
|
sysTime.add!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.add!"months"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
sysTime.add!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
|
|
sysTime.add!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
sysTime.add!"months"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.add!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
sysTime.add!"months"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
|
|
sysTime.add!"months"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 7, 9), hnsecs(17)));
|
|
sysTime.add!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
|
|
sysTime.add!"months"(-85, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-3, 2, 28, 12, 11, 10), msecs(9)));
|
|
sysTime.add!"months"(85, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(4, 3, 28, 12, 11, 10), msecs(9)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
|
|
sysTime.add!"months"(85, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(4, 4, 30, 12, 11, 10), msecs(9)));
|
|
sysTime.add!"months"(-85, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-3, 3, 30, 12, 11, 10), msecs(9)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
|
|
sysTime.add!"months"(85, AllowDayOverflow.no).add!"months"(-83, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-3, 5, 30, 12, 11, 10), msecs(9)));
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
Adds the given number of years or months to this $(LREF SysTime). A
|
|
negative number will subtract.
|
|
|
|
The difference between rolling and adding is that rolling does not
|
|
affect larger units. Rolling a $(LREF SysTime) 12 months
|
|
gets the exact same $(LREF SysTime). However, the days can still be affected
|
|
due to the differing number of days in each month.
|
|
|
|
Because there are no units larger than years, there is no difference
|
|
between adding and rolling years.
|
|
|
|
Params:
|
|
units = The type of units to add ("years" or "months").
|
|
value = The number of months or years to add to this
|
|
$(LREF SysTime).
|
|
allowOverflow = Whether the days should be allowed to overflow,
|
|
causing the month to increment.
|
|
+/
|
|
ref SysTime roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow
|
|
if(units == "years")
|
|
{
|
|
return add!"years"(value, allowOverflow);
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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)));
|
|
|
|
auto st5 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
|
|
st5.roll!"years"(1);
|
|
assert(st5 == SysTime(DateTime(2001, 3, 1, 12, 30, 33)));
|
|
|
|
auto st6 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
|
|
st6.roll!"years"(1, AllowDayOverflow.no);
|
|
assert(st6 == SysTime(DateTime(2001, 2, 28, 12, 30, 33)));
|
|
}
|
|
|
|
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)));
|
|
}
|
|
|
|
|
|
//Shares documentation with "years" overload.
|
|
ref SysTime roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe 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"(value, 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 roll!"months"() with AllowDayOverlow.yes
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 6));
|
|
sysTime.roll!"months"(3);
|
|
assert(sysTime == SysTime(Date(1999, 10, 6)));
|
|
sysTime.roll!"months"(-4);
|
|
assert(sysTime == SysTime(Date(1999, 6, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 6));
|
|
sysTime.roll!"months"(6);
|
|
assert(sysTime == SysTime(Date(1999, 1, 6)));
|
|
sysTime.roll!"months"(-6);
|
|
assert(sysTime == SysTime(Date(1999, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 6));
|
|
sysTime.roll!"months"(27);
|
|
assert(sysTime == SysTime(Date(1999, 10, 6)));
|
|
sysTime.roll!"months"(-28);
|
|
assert(sysTime == SysTime(Date(1999, 6, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 5, 31));
|
|
sysTime.roll!"months"(1);
|
|
assert(sysTime == SysTime(Date(1999, 7, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 5, 31));
|
|
sysTime.roll!"months"(-1);
|
|
assert(sysTime == SysTime(Date(1999, 5, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 2, 28));
|
|
sysTime.roll!"months"(12);
|
|
assert(sysTime == SysTime(Date(1999, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(2000, 2, 29));
|
|
sysTime.roll!"months"(12);
|
|
assert(sysTime == SysTime(Date(2000, 2, 29)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 31));
|
|
sysTime.roll!"months"(1);
|
|
assert(sysTime == SysTime(Date(1999, 8, 31)));
|
|
sysTime.roll!"months"(1);
|
|
assert(sysTime == SysTime(Date(1999, 10, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1998, 8, 31));
|
|
sysTime.roll!"months"(13);
|
|
assert(sysTime == SysTime(Date(1998, 10, 1)));
|
|
sysTime.roll!"months"(-13);
|
|
assert(sysTime == SysTime(Date(1998, 9, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1997, 12, 31));
|
|
sysTime.roll!"months"(13);
|
|
assert(sysTime == SysTime(Date(1997, 1, 31)));
|
|
sysTime.roll!"months"(-13);
|
|
assert(sysTime == SysTime(Date(1997, 12, 31)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1997, 12, 31));
|
|
sysTime.roll!"months"(14);
|
|
assert(sysTime == SysTime(Date(1997, 3, 3)));
|
|
sysTime.roll!"months"(-14);
|
|
assert(sysTime == SysTime(Date(1997, 1, 3)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1998, 12, 31));
|
|
sysTime.roll!"months"(14);
|
|
assert(sysTime == SysTime(Date(1998, 3, 3)));
|
|
sysTime.roll!"months"(-14);
|
|
assert(sysTime == SysTime(Date(1998, 1, 3)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 12, 31));
|
|
sysTime.roll!"months"(14);
|
|
assert(sysTime == SysTime(Date(1999, 3, 3)));
|
|
sysTime.roll!"months"(-14);
|
|
assert(sysTime == SysTime(Date(1999, 1, 3)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
|
|
sysTime.roll!"months"(3);
|
|
assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
|
|
sysTime.roll!"months"(-4);
|
|
assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
|
|
sysTime.roll!"months"(14);
|
|
assert(sysTime == SysTime(DateTime(1998, 3, 3, 7, 7, 7), hnsecs(422202)));
|
|
sysTime.roll!"months"(-14);
|
|
assert(sysTime == SysTime(DateTime(1998, 1, 3, 7, 7, 7), hnsecs(422202)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
|
|
sysTime.roll!"months"(14);
|
|
assert(sysTime == SysTime(DateTime(1999, 3, 3, 7, 7, 7), hnsecs(422202)));
|
|
sysTime.roll!"months"(-14);
|
|
assert(sysTime == SysTime(DateTime(1999, 1, 3, 7, 7, 7), hnsecs(422202)));
|
|
}
|
|
|
|
//Test B.C.
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 6));
|
|
sysTime.roll!"months"(3);
|
|
assert(sysTime == SysTime(Date(-1999, 10, 6)));
|
|
sysTime.roll!"months"(-4);
|
|
assert(sysTime == SysTime(Date(-1999, 6, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 6));
|
|
sysTime.roll!"months"(6);
|
|
assert(sysTime == SysTime(Date(-1999, 1, 6)));
|
|
sysTime.roll!"months"(-6);
|
|
assert(sysTime == SysTime(Date(-1999, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 6));
|
|
sysTime.roll!"months"(-27);
|
|
assert(sysTime == SysTime(Date(-1999, 4, 6)));
|
|
sysTime.roll!"months"(28);
|
|
assert(sysTime == SysTime(Date(-1999, 8, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 5, 31));
|
|
sysTime.roll!"months"(1);
|
|
assert(sysTime == SysTime(Date(-1999, 7, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 5, 31));
|
|
sysTime.roll!"months"(-1);
|
|
assert(sysTime == SysTime(Date(-1999, 5, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 2, 28));
|
|
sysTime.roll!"months"(-12);
|
|
assert(sysTime == SysTime(Date(-1999, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-2000, 2, 29));
|
|
sysTime.roll!"months"(-12);
|
|
assert(sysTime == SysTime(Date(-2000, 2, 29)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 31));
|
|
sysTime.roll!"months"(1);
|
|
assert(sysTime == SysTime(Date(-1999, 8, 31)));
|
|
sysTime.roll!"months"(1);
|
|
assert(sysTime == SysTime(Date(-1999, 10, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1998, 8, 31));
|
|
sysTime.roll!"months"(13);
|
|
assert(sysTime == SysTime(Date(-1998, 10, 1)));
|
|
sysTime.roll!"months"(-13);
|
|
assert(sysTime == SysTime(Date(-1998, 9, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1997, 12, 31));
|
|
sysTime.roll!"months"(13);
|
|
assert(sysTime == SysTime(Date(-1997, 1, 31)));
|
|
sysTime.roll!"months"(-13);
|
|
assert(sysTime == SysTime(Date(-1997, 12, 31)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1997, 12, 31));
|
|
sysTime.roll!"months"(14);
|
|
assert(sysTime == SysTime(Date(-1997, 3, 3)));
|
|
sysTime.roll!"months"(-14);
|
|
assert(sysTime == SysTime(Date(-1997, 1, 3)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-2002, 12, 31));
|
|
sysTime.roll!"months"(14);
|
|
assert(sysTime == SysTime(Date(-2002, 3, 3)));
|
|
sysTime.roll!"months"(-14);
|
|
assert(sysTime == SysTime(Date(-2002, 1, 3)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-2001, 12, 31));
|
|
sysTime.roll!"months"(14);
|
|
assert(sysTime == SysTime(Date(-2001, 3, 3)));
|
|
sysTime.roll!"months"(-14);
|
|
assert(sysTime == SysTime(Date(-2001, 1, 3)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
|
|
sysTime.roll!"months"(-1);
|
|
assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 0, 0)));
|
|
sysTime.roll!"months"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.roll!"months"(-1);
|
|
assert(sysTime == SysTime(DateTime(1, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
sysTime.roll!"months"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
|
|
sysTime.roll!"months"(1);
|
|
assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
|
|
sysTime.roll!"months"(-1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.roll!"months"(1);
|
|
assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
sysTime.roll!"months"(-1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), hnsecs(5007));
|
|
sysTime.roll!"months"(3);
|
|
assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), hnsecs(5007)));
|
|
sysTime.roll!"months"(-4);
|
|
assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), hnsecs(5007)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
|
|
sysTime.roll!"months"(14);
|
|
assert(sysTime == SysTime(DateTime(-2002, 3, 3, 7, 7, 7), hnsecs(422202)));
|
|
sysTime.roll!"months"(-14);
|
|
assert(sysTime == SysTime(DateTime(-2002, 1, 3, 7, 7, 7), hnsecs(422202)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
|
|
sysTime.roll!"months"(14);
|
|
assert(sysTime == SysTime(DateTime(-2001, 3, 3, 7, 7, 7), hnsecs(422202)));
|
|
sysTime.roll!"months"(-14);
|
|
assert(sysTime == SysTime(DateTime(-2001, 1, 3, 7, 7, 7), hnsecs(422202)));
|
|
}
|
|
|
|
//Test Both
|
|
{
|
|
auto sysTime = SysTime(Date(1, 1, 1));
|
|
sysTime.roll!"months"(-1);
|
|
assert(sysTime == SysTime(Date(1, 12, 1)));
|
|
sysTime.roll!"months"(1);
|
|
assert(sysTime == SysTime(Date(1, 1, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(4, 1, 1));
|
|
sysTime.roll!"months"(-48);
|
|
assert(sysTime == SysTime(Date(4, 1, 1)));
|
|
sysTime.roll!"months"(48);
|
|
assert(sysTime == SysTime(Date(4, 1, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(4, 3, 31));
|
|
sysTime.roll!"months"(-49);
|
|
assert(sysTime == SysTime(Date(4, 3, 2)));
|
|
sysTime.roll!"months"(49);
|
|
assert(sysTime == SysTime(Date(4, 4, 2)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(4, 3, 31));
|
|
sysTime.roll!"months"(-85);
|
|
assert(sysTime == SysTime(Date(4, 3, 2)));
|
|
sysTime.roll!"months"(85);
|
|
assert(sysTime == SysTime(Date(4, 4, 2)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1, 1, 1));
|
|
sysTime.roll!"months"(-1);
|
|
assert(sysTime == SysTime(Date(-1, 12, 1)));
|
|
sysTime.roll!"months"(1);
|
|
assert(sysTime == SysTime(Date(-1, 1, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-4, 1, 1));
|
|
sysTime.roll!"months"(-48);
|
|
assert(sysTime == SysTime(Date(-4, 1, 1)));
|
|
sysTime.roll!"months"(48);
|
|
assert(sysTime == SysTime(Date(-4, 1, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-4, 3, 31));
|
|
sysTime.roll!"months"(-49);
|
|
assert(sysTime == SysTime(Date(-4, 3, 2)));
|
|
sysTime.roll!"months"(49);
|
|
assert(sysTime == SysTime(Date(-4, 4, 2)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-4, 3, 31));
|
|
sysTime.roll!"months"(-85);
|
|
assert(sysTime == SysTime(Date(-4, 3, 2)));
|
|
sysTime.roll!"months"(85);
|
|
assert(sysTime == SysTime(Date(-4, 4, 2)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
|
|
sysTime.roll!"months"(-1);
|
|
assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 7, 9), hnsecs(17)));
|
|
sysTime.roll!"months"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
|
|
sysTime.roll!"months"(-85);
|
|
assert(sysTime == SysTime(DateTime(4, 3, 2, 12, 11, 10), msecs(9)));
|
|
sysTime.roll!"months"(85);
|
|
assert(sysTime == SysTime(DateTime(4, 4, 2, 12, 11, 10), msecs(9)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
|
|
sysTime.roll!"months"(85);
|
|
assert(sysTime == SysTime(DateTime(-3, 5, 1, 12, 11, 10), msecs(9)));
|
|
sysTime.roll!"months"(-85);
|
|
assert(sysTime == SysTime(DateTime(-3, 4, 1, 12, 11, 10), msecs(9)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
|
|
sysTime.roll!"months"(85).roll!"months"(-83);
|
|
assert(sysTime == SysTime(DateTime(-3, 6, 1, 12, 11, 10), 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)));
|
|
}
|
|
|
|
//Test roll!"months"() with AllowDayOverlow.no
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 6));
|
|
sysTime.roll!"months"(3, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 10, 6)));
|
|
sysTime.roll!"months"(-4, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 6, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 6));
|
|
sysTime.roll!"months"(6, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 1, 6)));
|
|
sysTime.roll!"months"(-6, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 6));
|
|
sysTime.roll!"months"(27, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 10, 6)));
|
|
sysTime.roll!"months"(-28, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 6, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 5, 31));
|
|
sysTime.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 6, 30)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 5, 31));
|
|
sysTime.roll!"months"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 4, 30)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 2, 28));
|
|
sysTime.roll!"months"(12, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(2000, 2, 29));
|
|
sysTime.roll!"months"(12, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(2000, 2, 29)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 31));
|
|
sysTime.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 8, 31)));
|
|
sysTime.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 9, 30)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1998, 8, 31));
|
|
sysTime.roll!"months"(13, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1998, 9, 30)));
|
|
sysTime.roll!"months"(-13, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1998, 8, 30)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1997, 12, 31));
|
|
sysTime.roll!"months"(13, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1997, 1, 31)));
|
|
sysTime.roll!"months"(-13, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1997, 12, 31)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1997, 12, 31));
|
|
sysTime.roll!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1997, 2, 28)));
|
|
sysTime.roll!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1997, 12, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1998, 12, 31));
|
|
sysTime.roll!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1998, 2, 28)));
|
|
sysTime.roll!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1998, 12, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 12, 31));
|
|
sysTime.roll!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 2, 28)));
|
|
sysTime.roll!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1999, 12, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
|
|
sysTime.roll!"months"(3, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
|
|
sysTime.roll!"months"(-4, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
|
|
sysTime.roll!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1998, 2, 28, 7, 7, 7), hnsecs(422202)));
|
|
sysTime.roll!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1998, 12, 28, 7, 7, 7), hnsecs(422202)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
|
|
sysTime.roll!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1999, 2, 28, 7, 7, 7), hnsecs(422202)));
|
|
sysTime.roll!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1999, 12, 28, 7, 7, 7), hnsecs(422202)));
|
|
}
|
|
|
|
//Test B.C.
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 6));
|
|
sysTime.roll!"months"(3, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 10, 6)));
|
|
sysTime.roll!"months"(-4, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 6, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 6));
|
|
sysTime.roll!"months"(6, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 1, 6)));
|
|
sysTime.roll!"months"(-6, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 6));
|
|
sysTime.roll!"months"(-27, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 4, 6)));
|
|
sysTime.roll!"months"(28, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 8, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 5, 31));
|
|
sysTime.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 6, 30)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 5, 31));
|
|
sysTime.roll!"months"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 4, 30)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 2, 28));
|
|
sysTime.roll!"months"(-12, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-2000, 2, 29));
|
|
sysTime.roll!"months"(-12, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-2000, 2, 29)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 31));
|
|
sysTime.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 8, 31)));
|
|
sysTime.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1999, 9, 30)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1998, 8, 31));
|
|
sysTime.roll!"months"(13, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1998, 9, 30)));
|
|
sysTime.roll!"months"(-13, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1998, 8, 30)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1997, 12, 31));
|
|
sysTime.roll!"months"(13, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1997, 1, 31)));
|
|
sysTime.roll!"months"(-13, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1997, 12, 31)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1997, 12, 31));
|
|
sysTime.roll!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1997, 2, 28)));
|
|
sysTime.roll!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1997, 12, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-2002, 12, 31));
|
|
sysTime.roll!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-2002, 2, 28)));
|
|
sysTime.roll!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-2002, 12, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-2001, 12, 31));
|
|
sysTime.roll!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-2001, 2, 28)));
|
|
sysTime.roll!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-2001, 12, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
|
|
sysTime.roll!"months"(3, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
|
|
sysTime.roll!"months"(-4, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
|
|
sysTime.roll!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-2002, 2, 28, 7, 7, 7), hnsecs(422202)));
|
|
sysTime.roll!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-2002, 12, 28, 7, 7, 7), hnsecs(422202)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
|
|
sysTime.roll!"months"(14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-2001, 2, 28, 7, 7, 7), hnsecs(422202)));
|
|
sysTime.roll!"months"(-14, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-2001, 12, 28, 7, 7, 7), hnsecs(422202)));
|
|
}
|
|
|
|
//Test Both
|
|
{
|
|
auto sysTime = SysTime(Date(1, 1, 1));
|
|
sysTime.roll!"months"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1, 12, 1)));
|
|
sysTime.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(1, 1, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(4, 1, 1));
|
|
sysTime.roll!"months"(-48, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(4, 1, 1)));
|
|
sysTime.roll!"months"(48, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(4, 1, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(4, 3, 31));
|
|
sysTime.roll!"months"(-49, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(4, 2, 29)));
|
|
sysTime.roll!"months"(49, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(4, 3, 29)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(4, 3, 31));
|
|
sysTime.roll!"months"(-85, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(4, 2, 29)));
|
|
sysTime.roll!"months"(85, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(4, 3, 29)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1, 1, 1));
|
|
sysTime.roll!"months"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1, 12, 1)));
|
|
sysTime.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-1, 1, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-4, 1, 1));
|
|
sysTime.roll!"months"(-48, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-4, 1, 1)));
|
|
sysTime.roll!"months"(48, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-4, 1, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-4, 3, 31));
|
|
sysTime.roll!"months"(-49, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-4, 2, 29)));
|
|
sysTime.roll!"months"(49, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-4, 3, 29)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-4, 3, 31));
|
|
sysTime.roll!"months"(-85, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-4, 2, 29)));
|
|
sysTime.roll!"months"(85, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(Date(-4, 3, 29)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
|
|
sysTime.roll!"months"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 0, 0)));
|
|
sysTime.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.roll!"months"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
sysTime.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
|
|
sysTime.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
|
|
sysTime.roll!"months"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
sysTime.roll!"months"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
|
|
sysTime.roll!"months"(-1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 7, 9), hnsecs(17)));
|
|
sysTime.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
|
|
sysTime.roll!"months"(-85, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(4, 2, 29, 12, 11, 10), msecs(9)));
|
|
sysTime.roll!"months"(85, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(4, 3, 29, 12, 11, 10), msecs(9)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
|
|
sysTime.roll!"months"(85, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-3, 4, 30, 12, 11, 10), msecs(9)));
|
|
sysTime.roll!"months"(-85, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-3, 3, 30, 12, 11, 10), msecs(9)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
|
|
sysTime.roll!"months"(85, AllowDayOverflow.no).roll!"months"(-83, AllowDayOverflow.no);
|
|
assert(sysTime == SysTime(DateTime(-3, 5, 30, 12, 11, 10), msecs(9)));
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
Adds the given number of units to this $(LREF SysTime). A negative number
|
|
will subtract.
|
|
|
|
The difference between rolling and adding is that rolling does not
|
|
affect larger units. For instance, rolling a $(LREF SysTime) one
|
|
year's worth of days gets the exact same $(LREF SysTime).
|
|
|
|
Accepted units are $(D "days"), $(D "minutes"), $(D "hours"),
|
|
$(D "minutes"), $(D "seconds"), $(D "msecs"), $(D "usecs"), and
|
|
$(D "hnsecs").
|
|
|
|
Note that when rolling msecs, usecs or hnsecs, they all add up to a
|
|
second. So, for example, rolling 1000 msecs is exactly the same as
|
|
rolling 100,000 usecs.
|
|
|
|
Params:
|
|
units = The units to add.
|
|
value = The number of $(D_PARAM units) to add to this $(LREF SysTime).
|
|
+/
|
|
ref SysTime roll(string units)(long value) @safe 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"(value);
|
|
gdays = date.dayOfGregorianCal - 1;
|
|
|
|
if(gdays < 0)
|
|
{
|
|
hnsecs -= convert!("hours", "hnsecs")(24);
|
|
++gdays;
|
|
}
|
|
|
|
immutable newDaysHNSecs = convert!("days", "hnsecs")(gdays);
|
|
adjTime = newDaysHNSecs + hnsecs;
|
|
return this;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
auto st1 = SysTime(DateTime(2010, 1, 1, 11, 23, 12));
|
|
st1.roll!"days"(1);
|
|
assert(st1 == SysTime(DateTime(2010, 1, 2, 11, 23, 12)));
|
|
st1.roll!"days"(365);
|
|
assert(st1 == SysTime(DateTime(2010, 1, 26, 11, 23, 12)));
|
|
st1.roll!"days"(-32);
|
|
assert(st1 == SysTime(DateTime(2010, 1, 25, 11, 23, 12)));
|
|
|
|
auto st2 = SysTime(DateTime(2010, 7, 4, 12, 0, 0));
|
|
st2.roll!"hours"(1);
|
|
assert(st2 == SysTime(DateTime(2010, 7, 4, 13, 0, 0)));
|
|
|
|
auto st3 = SysTime(DateTime(2010, 2, 12, 12, 0, 0));
|
|
st3.roll!"hours"(-1);
|
|
assert(st3 == SysTime(DateTime(2010, 2, 12, 11, 0, 0)));
|
|
|
|
auto st4 = SysTime(DateTime(2009, 12, 31, 0, 0, 0));
|
|
st4.roll!"minutes"(1);
|
|
assert(st4 == SysTime(DateTime(2009, 12, 31, 0, 1, 0)));
|
|
|
|
auto st5 = SysTime(DateTime(2010, 1, 1, 0, 0, 0));
|
|
st5.roll!"minutes"(-1);
|
|
assert(st5 == SysTime(DateTime(2010, 1, 1, 0, 59, 0)));
|
|
|
|
auto st6 = SysTime(DateTime(2009, 12, 31, 0, 0, 0));
|
|
st6.roll!"seconds"(1);
|
|
assert(st6 == SysTime(DateTime(2009, 12, 31, 0, 0, 1)));
|
|
|
|
auto st7 = SysTime(DateTime(2010, 1, 1, 0, 0, 0));
|
|
st7.roll!"seconds"(-1);
|
|
assert(st7 == SysTime(DateTime(2010, 1, 1, 0, 0, 59)));
|
|
|
|
auto dt = DateTime(2010, 1, 1, 0, 0, 0);
|
|
auto st8 = SysTime(dt);
|
|
st8.roll!"msecs"(1);
|
|
assert(st8 == SysTime(dt, msecs(1)));
|
|
|
|
auto st9 = SysTime(dt);
|
|
st9.roll!"msecs"(-1);
|
|
assert(st9 == SysTime(dt, msecs(999)));
|
|
|
|
auto st10 = SysTime(dt);
|
|
st10.roll!"hnsecs"(1);
|
|
assert(st10 == SysTime(dt, hnsecs(1)));
|
|
|
|
auto st11 = SysTime(dt);
|
|
st11.roll!"hnsecs"(-1);
|
|
assert(st11 == SysTime(dt, hnsecs(9_999_999)));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 2, 28));
|
|
sysTime.roll!"days"(1);
|
|
assert(sysTime == SysTime(Date(1999, 2, 1)));
|
|
sysTime.roll!"days"(-1);
|
|
assert(sysTime == SysTime(Date(1999, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(2000, 2, 28));
|
|
sysTime.roll!"days"(1);
|
|
assert(sysTime == SysTime(Date(2000, 2, 29)));
|
|
sysTime.roll!"days"(1);
|
|
assert(sysTime == SysTime(Date(2000, 2, 1)));
|
|
sysTime.roll!"days"(-1);
|
|
assert(sysTime == SysTime(Date(2000, 2, 29)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 6, 30));
|
|
sysTime.roll!"days"(1);
|
|
assert(sysTime == SysTime(Date(1999, 6, 1)));
|
|
sysTime.roll!"days"(-1);
|
|
assert(sysTime == SysTime(Date(1999, 6, 30)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 31));
|
|
sysTime.roll!"days"(1);
|
|
assert(sysTime == SysTime(Date(1999, 7, 1)));
|
|
sysTime.roll!"days"(-1);
|
|
assert(sysTime == SysTime(Date(1999, 7, 31)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 1, 1));
|
|
sysTime.roll!"days"(-1);
|
|
assert(sysTime == SysTime(Date(1999, 1, 31)));
|
|
sysTime.roll!"days"(1);
|
|
assert(sysTime == SysTime(Date(1999, 1, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 6));
|
|
sysTime.roll!"days"(9);
|
|
assert(sysTime == SysTime(Date(1999, 7, 15)));
|
|
sysTime.roll!"days"(-11);
|
|
assert(sysTime == SysTime(Date(1999, 7, 4)));
|
|
sysTime.roll!"days"(30);
|
|
assert(sysTime == SysTime(Date(1999, 7, 3)));
|
|
sysTime.roll!"days"(-3);
|
|
assert(sysTime == SysTime(Date(1999, 7, 31)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 7, 6));
|
|
sysTime.roll!"days"(365);
|
|
assert(sysTime == SysTime(Date(1999, 7, 30)));
|
|
sysTime.roll!"days"(-365);
|
|
assert(sysTime == SysTime(Date(1999, 7, 6)));
|
|
sysTime.roll!"days"(366);
|
|
assert(sysTime == SysTime(Date(1999, 7, 31)));
|
|
sysTime.roll!"days"(730);
|
|
assert(sysTime == SysTime(Date(1999, 7, 17)));
|
|
sysTime.roll!"days"(-1096);
|
|
assert(sysTime == SysTime(Date(1999, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(1999, 2, 6));
|
|
sysTime.roll!"days"(365);
|
|
assert(sysTime == SysTime(Date(1999, 2, 7)));
|
|
sysTime.roll!"days"(-365);
|
|
assert(sysTime == SysTime(Date(1999, 2, 6)));
|
|
sysTime.roll!"days"(366);
|
|
assert(sysTime == SysTime(Date(1999, 2, 8)));
|
|
sysTime.roll!"days"(730);
|
|
assert(sysTime == SysTime(Date(1999, 2, 10)));
|
|
sysTime.roll!"days"(-1096);
|
|
assert(sysTime == SysTime(Date(1999, 2, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1999, 2, 28, 7, 9, 2), usecs(234578));
|
|
sysTime.roll!"days"(1);
|
|
assert(sysTime == SysTime(DateTime(1999, 2, 1, 7, 9, 2), usecs(234578)));
|
|
sysTime.roll!"days"(-1);
|
|
assert(sysTime == SysTime(DateTime(1999, 2, 28, 7, 9, 2), usecs(234578)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1999, 7, 6, 7, 9, 2), usecs(234578));
|
|
sysTime.roll!"days"(9);
|
|
assert(sysTime == SysTime(DateTime(1999, 7, 15, 7, 9, 2), usecs(234578)));
|
|
sysTime.roll!"days"(-11);
|
|
assert(sysTime == SysTime(DateTime(1999, 7, 4, 7, 9, 2), usecs(234578)));
|
|
sysTime.roll!"days"(30);
|
|
assert(sysTime == SysTime(DateTime(1999, 7, 3, 7, 9, 2), usecs(234578)));
|
|
sysTime.roll!"days"(-3);
|
|
assert(sysTime == SysTime(DateTime(1999, 7, 31, 7, 9, 2), usecs(234578)));
|
|
}
|
|
|
|
//Test B.C.
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 2, 28));
|
|
sysTime.roll!"days"(1);
|
|
assert(sysTime == SysTime(Date(-1999, 2, 1)));
|
|
sysTime.roll!"days"(-1);
|
|
assert(sysTime == SysTime(Date(-1999, 2, 28)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-2000, 2, 28));
|
|
sysTime.roll!"days"(1);
|
|
assert(sysTime == SysTime(Date(-2000, 2, 29)));
|
|
sysTime.roll!"days"(1);
|
|
assert(sysTime == SysTime(Date(-2000, 2, 1)));
|
|
sysTime.roll!"days"(-1);
|
|
assert(sysTime == SysTime(Date(-2000, 2, 29)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 6, 30));
|
|
sysTime.roll!"days"(1);
|
|
assert(sysTime == SysTime(Date(-1999, 6, 1)));
|
|
sysTime.roll!"days"(-1);
|
|
assert(sysTime == SysTime(Date(-1999, 6, 30)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 31));
|
|
sysTime.roll!"days"(1);
|
|
assert(sysTime == SysTime(Date(-1999, 7, 1)));
|
|
sysTime.roll!"days"(-1);
|
|
assert(sysTime == SysTime(Date(-1999, 7, 31)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 1, 1));
|
|
sysTime.roll!"days"(-1);
|
|
assert(sysTime == SysTime(Date(-1999, 1, 31)));
|
|
sysTime.roll!"days"(1);
|
|
assert(sysTime == SysTime(Date(-1999, 1, 1)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 6));
|
|
sysTime.roll!"days"(9);
|
|
assert(sysTime == SysTime(Date(-1999, 7, 15)));
|
|
sysTime.roll!"days"(-11);
|
|
assert(sysTime == SysTime(Date(-1999, 7, 4)));
|
|
sysTime.roll!"days"(30);
|
|
assert(sysTime == SysTime(Date(-1999, 7, 3)));
|
|
sysTime.roll!"days"(-3);
|
|
assert(sysTime == SysTime(Date(-1999, 7, 31)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(Date(-1999, 7, 6));
|
|
sysTime.roll!"days"(365);
|
|
assert(sysTime == SysTime(Date(-1999, 7, 30)));
|
|
sysTime.roll!"days"(-365);
|
|
assert(sysTime == SysTime(Date(-1999, 7, 6)));
|
|
sysTime.roll!"days"(366);
|
|
assert(sysTime == SysTime(Date(-1999, 7, 31)));
|
|
sysTime.roll!"days"(730);
|
|
assert(sysTime == SysTime(Date(-1999, 7, 17)));
|
|
sysTime.roll!"days"(-1096);
|
|
assert(sysTime == SysTime(Date(-1999, 7, 6)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-1999, 2, 28, 7, 9, 2), usecs(234578));
|
|
sysTime.roll!"days"(1);
|
|
assert(sysTime == SysTime(DateTime(-1999, 2, 1, 7, 9, 2), usecs(234578)));
|
|
sysTime.roll!"days"(-1);
|
|
assert(sysTime == SysTime(DateTime(-1999, 2, 28, 7, 9, 2), usecs(234578)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(-1999, 7, 6, 7, 9, 2), usecs(234578));
|
|
sysTime.roll!"days"(9);
|
|
assert(sysTime == SysTime(DateTime(-1999, 7, 15, 7, 9, 2), usecs(234578)));
|
|
sysTime.roll!"days"(-11);
|
|
assert(sysTime == SysTime(DateTime(-1999, 7, 4, 7, 9, 2), usecs(234578)));
|
|
sysTime.roll!"days"(30);
|
|
assert(sysTime == SysTime(DateTime(-1999, 7, 3, 7, 9, 2), usecs(234578)));
|
|
sysTime.roll!"days"(-3);
|
|
}
|
|
|
|
//Test Both
|
|
{
|
|
auto sysTime = SysTime(Date(1, 7, 6));
|
|
sysTime.roll!"days"(-365);
|
|
assert(sysTime == SysTime(Date(1, 7, 13)));
|
|
sysTime.roll!"days"(365);
|
|
assert(sysTime == SysTime(Date(1, 7, 6)));
|
|
sysTime.roll!"days"(-731);
|
|
assert(sysTime == SysTime(Date(1, 7, 19)));
|
|
sysTime.roll!"days"(730);
|
|
assert(sysTime == SysTime(Date(1, 7, 5)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
|
|
sysTime.roll!"days"(-1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 31, 0, 0, 0)));
|
|
sysTime.roll!"days"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.roll!"days"(-1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
sysTime.roll!"days"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 12, 31, 0, 0, 0));
|
|
sysTime.roll!"days"(1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
|
|
sysTime.roll!"days"(-1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 0, 0)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.roll!"days"(1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
sysTime.roll!"days"(-1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 7, 6, 13, 13, 9), msecs(22));
|
|
sysTime.roll!"days"(-365);
|
|
assert(sysTime == SysTime(DateTime(1, 7, 13, 13, 13, 9), msecs(22)));
|
|
sysTime.roll!"days"(365);
|
|
assert(sysTime == SysTime(DateTime(1, 7, 6, 13, 13, 9), msecs(22)));
|
|
sysTime.roll!"days"(-731);
|
|
assert(sysTime == SysTime(DateTime(1, 7, 19, 13, 13, 9), msecs(22)));
|
|
sysTime.roll!"days"(730);
|
|
assert(sysTime == SysTime(DateTime(1, 7, 5, 13, 13, 9), msecs(22)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22));
|
|
sysTime.roll!"days"(-365);
|
|
assert(sysTime == SysTime(DateTime(0, 7, 13, 13, 13, 9), msecs(22)));
|
|
sysTime.roll!"days"(365);
|
|
assert(sysTime == SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22)));
|
|
sysTime.roll!"days"(-731);
|
|
assert(sysTime == SysTime(DateTime(0, 7, 19, 13, 13, 9), msecs(22)));
|
|
sysTime.roll!"days"(730);
|
|
assert(sysTime == SysTime(DateTime(0, 7, 5, 13, 13, 9), msecs(22)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22));
|
|
sysTime.roll!"days"(-365).roll!"days"(362).roll!"days"(-12).roll!"days"(730);
|
|
assert(sysTime == SysTime(DateTime(0, 7, 8, 13, 13, 9), 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)));
|
|
}
|
|
|
|
|
|
//Shares documentation with "days" version.
|
|
ref SysTime roll(string units)(long value) @safe 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;
|
|
return this;
|
|
}
|
|
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__)
|
|
{
|
|
import std.format : format;
|
|
orig.roll!"hours"(hours);
|
|
if(orig != expected)
|
|
throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
|
|
}
|
|
|
|
//Test A.D.
|
|
immutable d = msecs(45);
|
|
auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
|
|
testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
|
|
testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
|
|
testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 15, 30, 33), d));
|
|
testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 16, 30, 33), d));
|
|
testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 17, 30, 33), d));
|
|
testST(beforeAD, 6, SysTime(DateTime(1999, 7, 6, 18, 30, 33), d));
|
|
testST(beforeAD, 7, SysTime(DateTime(1999, 7, 6, 19, 30, 33), d));
|
|
testST(beforeAD, 8, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
|
|
testST(beforeAD, 9, SysTime(DateTime(1999, 7, 6, 21, 30, 33), d));
|
|
testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
|
|
testST(beforeAD, 11, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
|
|
testST(beforeAD, 12, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
|
|
testST(beforeAD, 13, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
|
|
testST(beforeAD, 14, SysTime(DateTime(1999, 7, 6, 2, 30, 33), d));
|
|
testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 3, 30, 33), d));
|
|
testST(beforeAD, 16, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
|
|
testST(beforeAD, 17, SysTime(DateTime(1999, 7, 6, 5, 30, 33), d));
|
|
testST(beforeAD, 18, SysTime(DateTime(1999, 7, 6, 6, 30, 33), d));
|
|
testST(beforeAD, 19, SysTime(DateTime(1999, 7, 6, 7, 30, 33), d));
|
|
testST(beforeAD, 20, SysTime(DateTime(1999, 7, 6, 8, 30, 33), d));
|
|
testST(beforeAD, 21, SysTime(DateTime(1999, 7, 6, 9, 30, 33), d));
|
|
testST(beforeAD, 22, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
|
|
testST(beforeAD, 23, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
|
|
testST(beforeAD, 24, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeAD, 25, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
|
|
testST(beforeAD, 50, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
|
|
testST(beforeAD, 10_000, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
|
|
|
|
testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
|
|
testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
|
|
testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 9, 30, 33), d));
|
|
testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 8, 30, 33), d));
|
|
testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 7, 30, 33), d));
|
|
testST(beforeAD, -6, SysTime(DateTime(1999, 7, 6, 6, 30, 33), d));
|
|
testST(beforeAD, -7, SysTime(DateTime(1999, 7, 6, 5, 30, 33), d));
|
|
testST(beforeAD, -8, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
|
|
testST(beforeAD, -9, SysTime(DateTime(1999, 7, 6, 3, 30, 33), d));
|
|
testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 2, 30, 33), d));
|
|
testST(beforeAD, -11, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
|
|
testST(beforeAD, -12, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
|
|
testST(beforeAD, -13, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
|
|
testST(beforeAD, -14, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
|
|
testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 21, 30, 33), d));
|
|
testST(beforeAD, -16, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
|
|
testST(beforeAD, -17, SysTime(DateTime(1999, 7, 6, 19, 30, 33), d));
|
|
testST(beforeAD, -18, SysTime(DateTime(1999, 7, 6, 18, 30, 33), d));
|
|
testST(beforeAD, -19, SysTime(DateTime(1999, 7, 6, 17, 30, 33), d));
|
|
testST(beforeAD, -20, SysTime(DateTime(1999, 7, 6, 16, 30, 33), d));
|
|
testST(beforeAD, -21, SysTime(DateTime(1999, 7, 6, 15, 30, 33), d));
|
|
testST(beforeAD, -22, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
|
|
testST(beforeAD, -23, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
|
|
testST(beforeAD, -24, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeAD, -25, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
|
|
testST(beforeAD, -50, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
|
|
testST(beforeAD, -10_000, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
|
|
|
|
testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), 1, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
|
|
testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), 0, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
|
|
testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), -1, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
|
|
|
|
testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), 1, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
|
|
testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), 0, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
|
|
testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), -1, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
|
|
|
|
testST(SysTime(DateTime(1999, 7, 31, 23, 30, 33), d), 1, SysTime(DateTime(1999, 7, 31, 0, 30, 33), d));
|
|
testST(SysTime(DateTime(1999, 8, 1, 0, 30, 33), d), -1, SysTime(DateTime(1999, 8, 1, 23, 30, 33), d));
|
|
|
|
testST(SysTime(DateTime(1999, 12, 31, 23, 30, 33), d), 1, SysTime(DateTime(1999, 12, 31, 0, 30, 33), d));
|
|
testST(SysTime(DateTime(2000, 1, 1, 0, 30, 33), d), -1, SysTime(DateTime(2000, 1, 1, 23, 30, 33), d));
|
|
|
|
testST(SysTime(DateTime(1999, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(1999, 2, 28, 0, 30, 33), d));
|
|
testST(SysTime(DateTime(1999, 3, 2, 0, 30, 33), d), -25, SysTime(DateTime(1999, 3, 2, 23, 30, 33), d));
|
|
|
|
testST(SysTime(DateTime(2000, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(2000, 2, 28, 0, 30, 33), d));
|
|
testST(SysTime(DateTime(2000, 3, 1, 0, 30, 33), d), -25, SysTime(DateTime(2000, 3, 1, 23, 30, 33), d));
|
|
|
|
//Test B.C.
|
|
auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
|
|
testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
|
|
testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
|
|
testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 15, 30, 33), d));
|
|
testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 16, 30, 33), d));
|
|
testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 17, 30, 33), d));
|
|
testST(beforeBC, 6, SysTime(DateTime(-1999, 7, 6, 18, 30, 33), d));
|
|
testST(beforeBC, 7, SysTime(DateTime(-1999, 7, 6, 19, 30, 33), d));
|
|
testST(beforeBC, 8, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
|
|
testST(beforeBC, 9, SysTime(DateTime(-1999, 7, 6, 21, 30, 33), d));
|
|
testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
|
|
testST(beforeBC, 11, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
|
|
testST(beforeBC, 12, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
|
|
testST(beforeBC, 13, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
|
|
testST(beforeBC, 14, SysTime(DateTime(-1999, 7, 6, 2, 30, 33), d));
|
|
testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 3, 30, 33), d));
|
|
testST(beforeBC, 16, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
|
|
testST(beforeBC, 17, SysTime(DateTime(-1999, 7, 6, 5, 30, 33), d));
|
|
testST(beforeBC, 18, SysTime(DateTime(-1999, 7, 6, 6, 30, 33), d));
|
|
testST(beforeBC, 19, SysTime(DateTime(-1999, 7, 6, 7, 30, 33), d));
|
|
testST(beforeBC, 20, SysTime(DateTime(-1999, 7, 6, 8, 30, 33), d));
|
|
testST(beforeBC, 21, SysTime(DateTime(-1999, 7, 6, 9, 30, 33), d));
|
|
testST(beforeBC, 22, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
|
|
testST(beforeBC, 23, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
|
|
testST(beforeBC, 24, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeBC, 25, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
|
|
testST(beforeBC, 50, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
|
|
testST(beforeBC, 10_000, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
|
|
|
|
testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
|
|
testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
|
|
testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 9, 30, 33), d));
|
|
testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 8, 30, 33), d));
|
|
testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 7, 30, 33), d));
|
|
testST(beforeBC, -6, SysTime(DateTime(-1999, 7, 6, 6, 30, 33), d));
|
|
testST(beforeBC, -7, SysTime(DateTime(-1999, 7, 6, 5, 30, 33), d));
|
|
testST(beforeBC, -8, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
|
|
testST(beforeBC, -9, SysTime(DateTime(-1999, 7, 6, 3, 30, 33), d));
|
|
testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 2, 30, 33), d));
|
|
testST(beforeBC, -11, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
|
|
testST(beforeBC, -12, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
|
|
testST(beforeBC, -13, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
|
|
testST(beforeBC, -14, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
|
|
testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 21, 30, 33), d));
|
|
testST(beforeBC, -16, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
|
|
testST(beforeBC, -17, SysTime(DateTime(-1999, 7, 6, 19, 30, 33), d));
|
|
testST(beforeBC, -18, SysTime(DateTime(-1999, 7, 6, 18, 30, 33), d));
|
|
testST(beforeBC, -19, SysTime(DateTime(-1999, 7, 6, 17, 30, 33), d));
|
|
testST(beforeBC, -20, SysTime(DateTime(-1999, 7, 6, 16, 30, 33), d));
|
|
testST(beforeBC, -21, SysTime(DateTime(-1999, 7, 6, 15, 30, 33), d));
|
|
testST(beforeBC, -22, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
|
|
testST(beforeBC, -23, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
|
|
testST(beforeBC, -24, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeBC, -25, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
|
|
testST(beforeBC, -50, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
|
|
testST(beforeBC, -10_000, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
|
|
|
|
testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
|
|
testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
|
|
testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
|
|
|
|
testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
|
|
testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
|
|
testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
|
|
|
|
testST(SysTime(DateTime(-1999, 7, 31, 23, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 31, 0, 30, 33), d));
|
|
testST(SysTime(DateTime(-1999, 8, 1, 0, 30, 33), d), -1, SysTime(DateTime(-1999, 8, 1, 23, 30, 33), d));
|
|
|
|
testST(SysTime(DateTime(-2001, 12, 31, 23, 30, 33), d), 1, SysTime(DateTime(-2001, 12, 31, 0, 30, 33), d));
|
|
testST(SysTime(DateTime(-2000, 1, 1, 0, 30, 33), d), -1, SysTime(DateTime(-2000, 1, 1, 23, 30, 33), d));
|
|
|
|
testST(SysTime(DateTime(-2001, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(-2001, 2, 28, 0, 30, 33), d));
|
|
testST(SysTime(DateTime(-2001, 3, 2, 0, 30, 33), d), -25, SysTime(DateTime(-2001, 3, 2, 23, 30, 33), d));
|
|
|
|
testST(SysTime(DateTime(-2000, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(-2000, 2, 28, 0, 30, 33), d));
|
|
testST(SysTime(DateTime(-2000, 3, 1, 0, 30, 33), d), -25, SysTime(DateTime(-2000, 3, 1, 23, 30, 33), d));
|
|
|
|
//Test Both
|
|
testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 17_546, SysTime(DateTime(-1, 1, 1, 13, 30, 33), d));
|
|
testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -17_546, SysTime(DateTime(1, 1, 1, 11, 30, 33), d));
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
|
|
sysTime.roll!"hours"(-1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 0, 0)));
|
|
sysTime.roll!"hours"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999));
|
|
sysTime.roll!"hours"(-1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
sysTime.roll!"hours"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 12, 31, 23, 0, 0));
|
|
sysTime.roll!"hours"(1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 0, 0)));
|
|
sysTime.roll!"hours"(-1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 0)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.roll!"hours"(1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 59, 59), hnsecs(9_999_999)));
|
|
sysTime.roll!"hours"(-1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.roll!"hours"(1).roll!"hours"(-67);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 31, 5, 59, 59), 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)));
|
|
}
|
|
|
|
//Test roll!"minutes"().
|
|
unittest
|
|
{
|
|
static void testST(SysTime orig, int minutes, in SysTime expected, size_t line = __LINE__)
|
|
{
|
|
import std.format : format;
|
|
orig.roll!"minutes"(minutes);
|
|
if(orig != expected)
|
|
throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
|
|
}
|
|
|
|
//Test A.D.
|
|
immutable d = usecs(7203);
|
|
auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
|
|
testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
|
|
testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 32, 33), d));
|
|
testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 12, 33, 33), d));
|
|
testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 12, 34, 33), d));
|
|
testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 12, 35, 33), d));
|
|
testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 40, 33), d));
|
|
testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
|
|
testST(beforeAD, 29, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
|
|
testST(beforeAD, 30, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
|
|
testST(beforeAD, 45, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
|
|
testST(beforeAD, 60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeAD, 75, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
|
|
testST(beforeAD, 90, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
|
|
testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 10, 33), d));
|
|
|
|
testST(beforeAD, 689, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
|
|
testST(beforeAD, 690, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
|
|
testST(beforeAD, 691, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
|
|
testST(beforeAD, 960, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeAD, 1439, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
|
|
testST(beforeAD, 1440, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeAD, 1441, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
|
|
testST(beforeAD, 2880, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
|
|
|
|
testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
|
|
testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 28, 33), d));
|
|
testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 12, 27, 33), d));
|
|
testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 12, 26, 33), d));
|
|
testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 12, 25, 33), d));
|
|
testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 20, 33), d));
|
|
testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
|
|
testST(beforeAD, -29, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
|
|
testST(beforeAD, -30, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
|
|
testST(beforeAD, -45, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
|
|
testST(beforeAD, -60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeAD, -75, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
|
|
testST(beforeAD, -90, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
|
|
testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 50, 33), d));
|
|
|
|
testST(beforeAD, -749, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
|
|
testST(beforeAD, -750, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
|
|
testST(beforeAD, -751, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
|
|
testST(beforeAD, -960, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeAD, -1439, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
|
|
testST(beforeAD, -1440, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeAD, -1441, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
|
|
testST(beforeAD, -2880, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
|
|
|
|
testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), 1, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
|
|
testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), 0, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
|
|
testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), -1, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
|
|
|
|
testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), 1, SysTime(DateTime(1999, 7, 6, 11, 0, 33), d));
|
|
testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), 0, SysTime(DateTime(1999, 7, 6, 11, 59, 33), d));
|
|
testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), -1, SysTime(DateTime(1999, 7, 6, 11, 58, 33), d));
|
|
|
|
testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), 1, SysTime(DateTime(1999, 7, 6, 0, 1, 33), d));
|
|
testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), 0, SysTime(DateTime(1999, 7, 6, 0, 0, 33), d));
|
|
testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), -1, SysTime(DateTime(1999, 7, 6, 0, 59, 33), d));
|
|
|
|
testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), 1, SysTime(DateTime(1999, 7, 5, 23, 0, 33), d));
|
|
testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), 0, SysTime(DateTime(1999, 7, 5, 23, 59, 33), d));
|
|
testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), -1, SysTime(DateTime(1999, 7, 5, 23, 58, 33), d));
|
|
|
|
testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), 1, SysTime(DateTime(1998, 12, 31, 23, 0, 33), d));
|
|
testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), 0, SysTime(DateTime(1998, 12, 31, 23, 59, 33), d));
|
|
testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), -1, SysTime(DateTime(1998, 12, 31, 23, 58, 33), d));
|
|
|
|
//Test B.C.
|
|
auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
|
|
testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
|
|
testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 32, 33), d));
|
|
testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 12, 33, 33), d));
|
|
testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 12, 34, 33), d));
|
|
testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 12, 35, 33), d));
|
|
testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 40, 33), d));
|
|
testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
|
|
testST(beforeBC, 29, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
|
|
testST(beforeBC, 30, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
|
|
testST(beforeBC, 45, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
|
|
testST(beforeBC, 60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeBC, 75, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
|
|
testST(beforeBC, 90, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
|
|
testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 10, 33), d));
|
|
|
|
testST(beforeBC, 689, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
|
|
testST(beforeBC, 690, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
|
|
testST(beforeBC, 691, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
|
|
testST(beforeBC, 960, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeBC, 1439, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
|
|
testST(beforeBC, 1440, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeBC, 1441, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
|
|
testST(beforeBC, 2880, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
|
|
|
|
testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
|
|
testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 28, 33), d));
|
|
testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 12, 27, 33), d));
|
|
testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 12, 26, 33), d));
|
|
testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 12, 25, 33), d));
|
|
testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 20, 33), d));
|
|
testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
|
|
testST(beforeBC, -29, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
|
|
testST(beforeBC, -30, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
|
|
testST(beforeBC, -45, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
|
|
testST(beforeBC, -60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeBC, -75, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
|
|
testST(beforeBC, -90, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
|
|
testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 50, 33), d));
|
|
|
|
testST(beforeBC, -749, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
|
|
testST(beforeBC, -750, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
|
|
testST(beforeBC, -751, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
|
|
testST(beforeBC, -960, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeBC, -1439, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
|
|
testST(beforeBC, -1440, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeBC, -1441, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
|
|
testST(beforeBC, -2880, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
|
|
|
|
testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
|
|
testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
|
|
testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
|
|
|
|
testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 11, 0, 33), d));
|
|
testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d));
|
|
testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 11, 58, 33), d));
|
|
|
|
testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 1, 33), d));
|
|
testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d));
|
|
testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 0, 59, 33), d));
|
|
|
|
testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), 1, SysTime(DateTime(-1999, 7, 5, 23, 0, 33), d));
|
|
testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), 0, SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d));
|
|
testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), -1, SysTime(DateTime(-1999, 7, 5, 23, 58, 33), d));
|
|
|
|
testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), 1, SysTime(DateTime(-2000, 12, 31, 23, 0, 33), d));
|
|
testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), 0, SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d));
|
|
testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), -1, SysTime(DateTime(-2000, 12, 31, 23, 58, 33), d));
|
|
|
|
//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), d), 1_052_760, SysTime(DateTime(-1, 1, 1, 11, 30, 33), d));
|
|
testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -1_052_760, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
|
|
|
|
testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 1_052_782, SysTime(DateTime(-1, 1, 1, 11, 52, 33), d));
|
|
testST(SysTime(DateTime(1, 1, 1, 13, 52, 33), d), -1_052_782, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
|
|
sysTime.roll!"minutes"(-1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 0)));
|
|
sysTime.roll!"minutes"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999));
|
|
sysTime.roll!"minutes"(-1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999)));
|
|
sysTime.roll!"minutes"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 0));
|
|
sysTime.roll!"minutes"(1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 0)));
|
|
sysTime.roll!"minutes"(-1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.roll!"minutes"(1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 59), hnsecs(9_999_999)));
|
|
sysTime.roll!"minutes"(-1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.roll!"minutes"(1).roll!"minutes"(-79);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 41, 59), 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__)
|
|
{
|
|
import std.format : format;
|
|
orig.roll!"seconds"(seconds);
|
|
if(orig != expected)
|
|
throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
|
|
}
|
|
|
|
//Test A.D.
|
|
immutable d = msecs(274);
|
|
auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
|
|
testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
|
|
testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 35), d));
|
|
testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 12, 30, 36), d));
|
|
testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 12, 30, 37), d));
|
|
testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 12, 30, 38), d));
|
|
testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 43), d));
|
|
testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 12, 30, 48), d));
|
|
testST(beforeAD, 26, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
|
|
testST(beforeAD, 27, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
|
|
testST(beforeAD, 30, SysTime(DateTime(1999, 7, 6, 12, 30, 3), d));
|
|
testST(beforeAD, 59, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
|
|
testST(beforeAD, 60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeAD, 61, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
|
|
|
|
testST(beforeAD, 1766, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
|
|
testST(beforeAD, 1767, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
|
|
testST(beforeAD, 1768, SysTime(DateTime(1999, 7, 6, 12, 30, 1), d));
|
|
testST(beforeAD, 2007, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
|
|
testST(beforeAD, 3599, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
|
|
testST(beforeAD, 3600, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeAD, 3601, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
|
|
testST(beforeAD, 7200, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
|
|
|
|
testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
|
|
testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 31), d));
|
|
testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 12, 30, 30), d));
|
|
testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 12, 30, 29), d));
|
|
testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 12, 30, 28), d));
|
|
testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 23), d));
|
|
testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 12, 30, 18), d));
|
|
testST(beforeAD, -33, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
|
|
testST(beforeAD, -34, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
|
|
testST(beforeAD, -35, SysTime(DateTime(1999, 7, 6, 12, 30, 58), d));
|
|
testST(beforeAD, -59, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
|
|
testST(beforeAD, -60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeAD, -61, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
|
|
|
|
testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), 1, SysTime(DateTime(1999, 7, 6, 12, 30, 1), d));
|
|
testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), 0, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
|
|
testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), -1, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
|
|
|
|
testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), 1, SysTime(DateTime(1999, 7, 6, 12, 0, 1), d));
|
|
testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), 0, SysTime(DateTime(1999, 7, 6, 12, 0, 0), d));
|
|
testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), -1, SysTime(DateTime(1999, 7, 6, 12, 0, 59), d));
|
|
|
|
testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), 1, SysTime(DateTime(1999, 7, 6, 0, 0, 1), d));
|
|
testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), 0, SysTime(DateTime(1999, 7, 6, 0, 0, 0), d));
|
|
testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), -1, SysTime(DateTime(1999, 7, 6, 0, 0, 59), d));
|
|
|
|
testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), 1, SysTime(DateTime(1999, 7, 5, 23, 59, 0), d));
|
|
testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), 0, SysTime(DateTime(1999, 7, 5, 23, 59, 59), d));
|
|
testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), -1, SysTime(DateTime(1999, 7, 5, 23, 59, 58), d));
|
|
|
|
testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(1998, 12, 31, 23, 59, 0), d));
|
|
testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), 0, SysTime(DateTime(1998, 12, 31, 23, 59, 59), d));
|
|
testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), -1, SysTime(DateTime(1998, 12, 31, 23, 59, 58), d));
|
|
|
|
//Test B.C.
|
|
auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
|
|
testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
|
|
testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 35), d));
|
|
testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 12, 30, 36), d));
|
|
testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 12, 30, 37), d));
|
|
testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 12, 30, 38), d));
|
|
testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 43), d));
|
|
testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 12, 30, 48), d));
|
|
testST(beforeBC, 26, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
|
|
testST(beforeBC, 27, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
|
|
testST(beforeBC, 30, SysTime(DateTime(-1999, 7, 6, 12, 30, 3), d));
|
|
testST(beforeBC, 59, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
|
|
testST(beforeBC, 60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeBC, 61, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
|
|
|
|
testST(beforeBC, 1766, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
|
|
testST(beforeBC, 1767, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
|
|
testST(beforeBC, 1768, SysTime(DateTime(-1999, 7, 6, 12, 30, 1), d));
|
|
testST(beforeBC, 2007, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
|
|
testST(beforeBC, 3599, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
|
|
testST(beforeBC, 3600, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeBC, 3601, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
|
|
testST(beforeBC, 7200, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
|
|
|
|
testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
|
|
testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 31), d));
|
|
testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 12, 30, 30), d));
|
|
testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 12, 30, 29), d));
|
|
testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 12, 30, 28), d));
|
|
testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 23), d));
|
|
testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 12, 30, 18), d));
|
|
testST(beforeBC, -33, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
|
|
testST(beforeBC, -34, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
|
|
testST(beforeBC, -35, SysTime(DateTime(-1999, 7, 6, 12, 30, 58), d));
|
|
testST(beforeBC, -59, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
|
|
testST(beforeBC, -60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
|
|
testST(beforeBC, -61, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
|
|
|
|
testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 1), d));
|
|
testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
|
|
testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
|
|
|
|
testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 0, 1), d));
|
|
testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d));
|
|
testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 0, 59), d));
|
|
|
|
testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 0, 1), d));
|
|
testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d));
|
|
testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 0, 0, 59), d));
|
|
|
|
testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), 1, SysTime(DateTime(-1999, 7, 5, 23, 59, 0), d));
|
|
testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), 0, SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d));
|
|
testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), -1, SysTime(DateTime(-1999, 7, 5, 23, 59, 58), d));
|
|
|
|
testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(-2000, 12, 31, 23, 59, 0), d));
|
|
testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), 0, SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d));
|
|
testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), -1, SysTime(DateTime(-2000, 12, 31, 23, 59, 58), d));
|
|
|
|
//Test Both
|
|
testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), d), -1, SysTime(DateTime(1, 1, 1, 0, 0, 59), d));
|
|
testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(0, 12, 31, 23, 59, 0), d));
|
|
|
|
testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), d), -1, SysTime(DateTime(0, 1, 1, 0, 0, 59), d));
|
|
testST(SysTime(DateTime(-1, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(-1, 12, 31, 23, 59, 0), d));
|
|
|
|
testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 63_165_600L, SysTime(DateTime(-1, 1, 1, 11, 30, 33), d));
|
|
testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -63_165_600L, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
|
|
|
|
testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 63_165_617L, SysTime(DateTime(-1, 1, 1, 11, 30, 50), d));
|
|
testST(SysTime(DateTime(1, 1, 1, 13, 30, 50), d), -63_165_617L, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
|
|
sysTime.roll!"seconds"(-1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59)));
|
|
sysTime.roll!"seconds"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999));
|
|
sysTime.roll!"seconds"(-1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999)));
|
|
sysTime.roll!"seconds"(1);
|
|
assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59));
|
|
sysTime.roll!"seconds"(1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0)));
|
|
sysTime.roll!"seconds"(-1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.roll!"seconds"(1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0), hnsecs(9_999_999)));
|
|
sysTime.roll!"seconds"(-1);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
}
|
|
|
|
{
|
|
auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
|
|
sysTime.roll!"seconds"(1).roll!"seconds"(-102);
|
|
assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 18), 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)));
|
|
}
|
|
|
|
|
|
//Shares documentation with "days" version.
|
|
ref SysTime roll(string units)(long value) @safe 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;
|
|
return this;
|
|
}
|
|
|
|
|
|
//Test roll!"msecs"().
|
|
unittest
|
|
{
|
|
static void testST(SysTime orig, int milliseconds, in SysTime expected, size_t line = __LINE__)
|
|
{
|
|
import std.format : format;
|
|
orig.roll!"msecs"(milliseconds);
|
|
if(orig != expected)
|
|
throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
|
|
}
|
|
|
|
//Test A.D.
|
|
auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274));
|
|
testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
|
|
testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(275)));
|
|
testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(276)));
|
|
testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(284)));
|
|
testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(374)));
|
|
testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
|
|
testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
|
|
testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(275)));
|
|
testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
|
|
testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
|
|
testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(1)));
|
|
testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
|
|
testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
|
|
testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(273)));
|
|
testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(272)));
|
|
testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(264)));
|
|
testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(174)));
|
|
testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
|
|
testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
|
|
testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(273)));
|
|
testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
|
|
testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
|
|
testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
|
|
|
|
//Test B.C.
|
|
auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274));
|
|
testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
|
|
testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(275)));
|
|
testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(276)));
|
|
testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(284)));
|
|
testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(374)));
|
|
testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
|
|
testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
|
|
testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
|
|
testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(275)));
|
|
testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
|
|
testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
|
|
testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
|
|
testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(1)));
|
|
testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
|
|
testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
|
|
|
|
testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(273)));
|
|
testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(272)));
|
|
testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(264)));
|
|
testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(174)));
|
|
testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
|
|
testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
|
|
testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
|
|
testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(273)));
|
|
testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
|
|
testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
|
|
testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
|
|
testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
|
|
testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
|
|
|
|
//Test Both
|
|
auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
|
|
testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(1)));
|
|
testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
testST(beforeBoth1, -1, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(999)));
|
|
testST(beforeBoth1, -2, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(998)));
|
|
testST(beforeBoth1, -1000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
testST(beforeBoth1, -2000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
testST(beforeBoth1, -2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(445)));
|
|
|
|
auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
|
|
testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_989_999)));
|
|
testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
testST(beforeBoth2, 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9999)));
|
|
testST(beforeBoth2, 2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19_999)));
|
|
testST(beforeBoth2, 1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
testST(beforeBoth2, 2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
testST(beforeBoth2, 2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(5_549_999)));
|
|
|
|
{
|
|
auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
|
|
st.roll!"msecs"(1202).roll!"msecs"(-703);
|
|
assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(4_989_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__)
|
|
{
|
|
import std.format : format;
|
|
orig.roll!"usecs"(microseconds);
|
|
if(orig != expected)
|
|
throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
|
|
}
|
|
|
|
//Test A.D.
|
|
auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274));
|
|
testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
|
|
testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(275)));
|
|
testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(276)));
|
|
testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(284)));
|
|
testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(374)));
|
|
testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999)));
|
|
testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1000)));
|
|
testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1274)));
|
|
testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1275)));
|
|
testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(2274)));
|
|
testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(26_999)));
|
|
testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(27_000)));
|
|
testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(27_001)));
|
|
testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(766_999)));
|
|
testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(767_000)));
|
|
testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
|
|
testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
|
|
testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
|
|
|
|
testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(273)));
|
|
testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(272)));
|
|
testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(264)));
|
|
testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(174)));
|
|
testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_999)));
|
|
testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_274)));
|
|
testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_273)));
|
|
testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(998_274)));
|
|
testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(967_000)));
|
|
testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(966_999)));
|
|
testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(167_000)));
|
|
testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(166_999)));
|
|
testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
|
|
testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
|
|
testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
|
|
|
|
//Test B.C.
|
|
auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274));
|
|
testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
|
|
testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(275)));
|
|
testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(276)));
|
|
testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(284)));
|
|
testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(374)));
|
|
testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999)));
|
|
testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1000)));
|
|
testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1274)));
|
|
testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1275)));
|
|
testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(2274)));
|
|
testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(26_999)));
|
|
testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(27_000)));
|
|
testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(27_001)));
|
|
testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(766_999)));
|
|
testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(767_000)));
|
|
testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
|
|
testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
|
|
testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
|
|
|
|
testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(273)));
|
|
testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(272)));
|
|
testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(264)));
|
|
testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(174)));
|
|
testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
|
|
testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_999)));
|
|
testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_274)));
|
|
testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_273)));
|
|
testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(998_274)));
|
|
testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(967_000)));
|
|
testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(966_999)));
|
|
testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(167_000)));
|
|
testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(166_999)));
|
|
testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
|
|
testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
|
|
testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
|
|
|
|
//Test Both
|
|
auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
|
|
testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(1)));
|
|
testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
testST(beforeBoth1, -1, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_999)));
|
|
testST(beforeBoth1, -2, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_998)));
|
|
testST(beforeBoth1, -1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_000)));
|
|
testST(beforeBoth1, -2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(998_000)));
|
|
testST(beforeBoth1, -2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(997_445)));
|
|
testST(beforeBoth1, -1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
testST(beforeBoth1, -2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
testST(beforeBoth1, -2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(666_667)));
|
|
|
|
auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
|
|
testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_989)));
|
|
testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
testST(beforeBoth2, 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9)));
|
|
testST(beforeBoth2, 2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19)));
|
|
testST(beforeBoth2, 1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9999)));
|
|
testST(beforeBoth2, 2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19_999)));
|
|
testST(beforeBoth2, 2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(25_549)));
|
|
testST(beforeBoth2, 1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
testST(beforeBoth2, 2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
testST(beforeBoth2, 2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(3_333_329)));
|
|
|
|
{
|
|
auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
|
|
st.roll!"usecs"(9_020_027);
|
|
assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(200_269)));
|
|
}
|
|
|
|
{
|
|
auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
|
|
st.roll!"usecs"(9_020_027).roll!"usecs"(-70_034);
|
|
assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_499_929)));
|
|
}
|
|
|
|
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__)
|
|
{
|
|
import std.format : format;
|
|
orig.roll!"hnsecs"(hnsecs);
|
|
if(orig != expected)
|
|
throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
|
|
}
|
|
|
|
//Test A.D.
|
|
auto dtAD = DateTime(1999, 7, 6, 12, 30, 33);
|
|
auto beforeAD = SysTime(dtAD, hnsecs(274));
|
|
testST(beforeAD, 0, SysTime(dtAD, hnsecs(274)));
|
|
testST(beforeAD, 1, SysTime(dtAD, hnsecs(275)));
|
|
testST(beforeAD, 2, SysTime(dtAD, hnsecs(276)));
|
|
testST(beforeAD, 10, SysTime(dtAD, hnsecs(284)));
|
|
testST(beforeAD, 100, SysTime(dtAD, hnsecs(374)));
|
|
testST(beforeAD, 725, SysTime(dtAD, hnsecs(999)));
|
|
testST(beforeAD, 726, SysTime(dtAD, hnsecs(1000)));
|
|
testST(beforeAD, 1000, SysTime(dtAD, hnsecs(1274)));
|
|
testST(beforeAD, 1001, SysTime(dtAD, hnsecs(1275)));
|
|
testST(beforeAD, 2000, SysTime(dtAD, hnsecs(2274)));
|
|
testST(beforeAD, 26_725, SysTime(dtAD, hnsecs(26_999)));
|
|
testST(beforeAD, 26_726, SysTime(dtAD, hnsecs(27_000)));
|
|
testST(beforeAD, 26_727, SysTime(dtAD, hnsecs(27_001)));
|
|
testST(beforeAD, 1_766_725, SysTime(dtAD, hnsecs(1_766_999)));
|
|
testST(beforeAD, 1_766_726, SysTime(dtAD, hnsecs(1_767_000)));
|
|
testST(beforeAD, 1_000_000, SysTime(dtAD, hnsecs(1_000_274)));
|
|
testST(beforeAD, 60_000_000L, SysTime(dtAD, hnsecs(274)));
|
|
testST(beforeAD, 3_600_000_000L, SysTime(dtAD, hnsecs(274)));
|
|
testST(beforeAD, 600_000_000L, SysTime(dtAD, hnsecs(274)));
|
|
testST(beforeAD, 36_000_000_000L, SysTime(dtAD, hnsecs(274)));
|
|
|
|
testST(beforeAD, -1, SysTime(dtAD, hnsecs(273)));
|
|
testST(beforeAD, -2, SysTime(dtAD, hnsecs(272)));
|
|
testST(beforeAD, -10, SysTime(dtAD, hnsecs(264)));
|
|
testST(beforeAD, -100, SysTime(dtAD, hnsecs(174)));
|
|
testST(beforeAD, -274, SysTime(dtAD));
|
|
testST(beforeAD, -275, SysTime(dtAD, hnsecs(9_999_999)));
|
|
testST(beforeAD, -1000, SysTime(dtAD, hnsecs(9_999_274)));
|
|
testST(beforeAD, -1001, SysTime(dtAD, hnsecs(9_999_273)));
|
|
testST(beforeAD, -2000, SysTime(dtAD, hnsecs(9_998_274)));
|
|
testST(beforeAD, -33_274, SysTime(dtAD, hnsecs(9_967_000)));
|
|
testST(beforeAD, -33_275, SysTime(dtAD, hnsecs(9_966_999)));
|
|
testST(beforeAD, -1_833_274, SysTime(dtAD, hnsecs(8_167_000)));
|
|
testST(beforeAD, -1_833_275, SysTime(dtAD, hnsecs(8_166_999)));
|
|
testST(beforeAD, -1_000_000, SysTime(dtAD, hnsecs(9_000_274)));
|
|
testST(beforeAD, -60_000_000L, SysTime(dtAD, hnsecs(274)));
|
|
testST(beforeAD, -3_600_000_000L, SysTime(dtAD, hnsecs(274)));
|
|
testST(beforeAD, -600_000_000L, SysTime(dtAD, hnsecs(274)));
|
|
testST(beforeAD, -36_000_000_000L, SysTime(dtAD, hnsecs(274)));
|
|
|
|
//Test B.C.
|
|
auto dtBC = DateTime(-1999, 7, 6, 12, 30, 33);
|
|
auto beforeBC = SysTime(dtBC, hnsecs(274));
|
|
testST(beforeBC, 0, SysTime(dtBC, hnsecs(274)));
|
|
testST(beforeBC, 1, SysTime(dtBC, hnsecs(275)));
|
|
testST(beforeBC, 2, SysTime(dtBC, hnsecs(276)));
|
|
testST(beforeBC, 10, SysTime(dtBC, hnsecs(284)));
|
|
testST(beforeBC, 100, SysTime(dtBC, hnsecs(374)));
|
|
testST(beforeBC, 725, SysTime(dtBC, hnsecs(999)));
|
|
testST(beforeBC, 726, SysTime(dtBC, hnsecs(1000)));
|
|
testST(beforeBC, 1000, SysTime(dtBC, hnsecs(1274)));
|
|
testST(beforeBC, 1001, SysTime(dtBC, hnsecs(1275)));
|
|
testST(beforeBC, 2000, SysTime(dtBC, hnsecs(2274)));
|
|
testST(beforeBC, 26_725, SysTime(dtBC, hnsecs(26_999)));
|
|
testST(beforeBC, 26_726, SysTime(dtBC, hnsecs(27_000)));
|
|
testST(beforeBC, 26_727, SysTime(dtBC, hnsecs(27_001)));
|
|
testST(beforeBC, 1_766_725, SysTime(dtBC, hnsecs(1_766_999)));
|
|
testST(beforeBC, 1_766_726, SysTime(dtBC, hnsecs(1_767_000)));
|
|
testST(beforeBC, 1_000_000, SysTime(dtBC, hnsecs(1_000_274)));
|
|
testST(beforeBC, 60_000_000L, SysTime(dtBC, hnsecs(274)));
|
|
testST(beforeBC, 3_600_000_000L, SysTime(dtBC, hnsecs(274)));
|
|
testST(beforeBC, 600_000_000L, SysTime(dtBC, hnsecs(274)));
|
|
testST(beforeBC, 36_000_000_000L, SysTime(dtBC, hnsecs(274)));
|
|
|
|
testST(beforeBC, -1, SysTime(dtBC, hnsecs(273)));
|
|
testST(beforeBC, -2, SysTime(dtBC, hnsecs(272)));
|
|
testST(beforeBC, -10, SysTime(dtBC, hnsecs(264)));
|
|
testST(beforeBC, -100, SysTime(dtBC, hnsecs(174)));
|
|
testST(beforeBC, -274, SysTime(dtBC));
|
|
testST(beforeBC, -275, SysTime(dtBC, hnsecs(9_999_999)));
|
|
testST(beforeBC, -1000, SysTime(dtBC, hnsecs(9_999_274)));
|
|
testST(beforeBC, -1001, SysTime(dtBC, hnsecs(9_999_273)));
|
|
testST(beforeBC, -2000, SysTime(dtBC, hnsecs(9_998_274)));
|
|
testST(beforeBC, -33_274, SysTime(dtBC, hnsecs(9_967_000)));
|
|
testST(beforeBC, -33_275, SysTime(dtBC, hnsecs(9_966_999)));
|
|
testST(beforeBC, -1_833_274, SysTime(dtBC, hnsecs(8_167_000)));
|
|
testST(beforeBC, -1_833_275, SysTime(dtBC, hnsecs(8_166_999)));
|
|
testST(beforeBC, -1_000_000, SysTime(dtBC, hnsecs(9_000_274)));
|
|
testST(beforeBC, -60_000_000L, SysTime(dtBC, hnsecs(274)));
|
|
testST(beforeBC, -3_600_000_000L, SysTime(dtBC, hnsecs(274)));
|
|
testST(beforeBC, -600_000_000L, SysTime(dtBC, hnsecs(274)));
|
|
testST(beforeBC, -36_000_000_000L, SysTime(dtBC, hnsecs(274)));
|
|
|
|
//Test Both
|
|
auto dtBoth1 = DateTime(1, 1, 1, 0, 0, 0);
|
|
auto beforeBoth1 = SysTime(dtBoth1);
|
|
testST(beforeBoth1, 1, SysTime(dtBoth1, hnsecs(1)));
|
|
testST(beforeBoth1, 0, SysTime(dtBoth1));
|
|
testST(beforeBoth1, -1, SysTime(dtBoth1, hnsecs(9_999_999)));
|
|
testST(beforeBoth1, -2, SysTime(dtBoth1, hnsecs(9_999_998)));
|
|
testST(beforeBoth1, -1000, SysTime(dtBoth1, hnsecs(9_999_000)));
|
|
testST(beforeBoth1, -2000, SysTime(dtBoth1, hnsecs(9_998_000)));
|
|
testST(beforeBoth1, -2555, SysTime(dtBoth1, hnsecs(9_997_445)));
|
|
testST(beforeBoth1, -1_000_000, SysTime(dtBoth1, hnsecs(9_000_000)));
|
|
testST(beforeBoth1, -2_000_000, SysTime(dtBoth1, hnsecs(8_000_000)));
|
|
testST(beforeBoth1, -2_333_333, SysTime(dtBoth1, hnsecs(7_666_667)));
|
|
testST(beforeBoth1, -10_000_000, SysTime(dtBoth1));
|
|
testST(beforeBoth1, -20_000_000, SysTime(dtBoth1));
|
|
testST(beforeBoth1, -20_888_888, SysTime(dtBoth1, hnsecs(9_111_112)));
|
|
|
|
auto dtBoth2 = DateTime(0, 12, 31, 23, 59, 59);
|
|
auto beforeBoth2 = SysTime(dtBoth2, hnsecs(9_999_999));
|
|
testST(beforeBoth2, -1, SysTime(dtBoth2, hnsecs(9_999_998)));
|
|
testST(beforeBoth2, 0, SysTime(dtBoth2, hnsecs(9_999_999)));
|
|
testST(beforeBoth2, 1, SysTime(dtBoth2));
|
|
testST(beforeBoth2, 2, SysTime(dtBoth2, hnsecs(1)));
|
|
testST(beforeBoth2, 1000, SysTime(dtBoth2, hnsecs(999)));
|
|
testST(beforeBoth2, 2000, SysTime(dtBoth2, hnsecs(1999)));
|
|
testST(beforeBoth2, 2555, SysTime(dtBoth2, hnsecs(2554)));
|
|
testST(beforeBoth2, 1_000_000, SysTime(dtBoth2, hnsecs(999_999)));
|
|
testST(beforeBoth2, 2_000_000, SysTime(dtBoth2, hnsecs(1_999_999)));
|
|
testST(beforeBoth2, 2_333_333, SysTime(dtBoth2, hnsecs(2_333_332)));
|
|
testST(beforeBoth2, 10_000_000, SysTime(dtBoth2, hnsecs(9_999_999)));
|
|
testST(beforeBoth2, 20_000_000, SysTime(dtBoth2, hnsecs(9_999_999)));
|
|
testST(beforeBoth2, 20_888_888, SysTime(dtBoth2, hnsecs(888_887)));
|
|
|
|
{
|
|
auto st = SysTime(dtBoth2, hnsecs(9_999_999));
|
|
st.roll!"hnsecs"(70_777_222).roll!"hnsecs"(-222_555_292);
|
|
assert(st == SysTime(dtBoth2, hnsecs(8_221_929)));
|
|
}
|
|
|
|
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)));
|
|
}
|
|
|
|
|
|
/++
|
|
Gives the result of adding or subtracting a duration from this
|
|
$(LREF SysTime).
|
|
|
|
The legal types of arithmetic for $(LREF SysTime) using this operator are
|
|
|
|
$(BOOKTABLE,
|
|
$(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
|
|
$(LREF SysTime).
|
|
+/
|
|
SysTime opBinary(string op, D)(in D duration) @safe const pure nothrow
|
|
if((op == "+" || op == "-") &&
|
|
(is(Unqual!D == Duration) ||
|
|
is(Unqual!D == TickDuration)))
|
|
{
|
|
import std.format : format;
|
|
|
|
SysTime retval = SysTime(this._stdTime, this._timezone);
|
|
|
|
static if(is(Unqual!D == Duration))
|
|
immutable hnsecs = duration.total!"hnsecs";
|
|
else static if(is(Unqual!D == TickDuration))
|
|
immutable hnsecs = duration.hnsecs;
|
|
|
|
mixin(format("retval._stdTime %s= hnsecs;", op));
|
|
return retval;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_678));
|
|
|
|
assert(st + dur!"weeks"(7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33), hnsecs(2_345_678)));
|
|
assert(st + dur!"weeks"(-7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33), hnsecs(2_345_678)));
|
|
assert(st + dur!"days"(7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33), hnsecs(2_345_678)));
|
|
assert(st + dur!"days"(-7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33), hnsecs(2_345_678)));
|
|
assert(st + dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33), hnsecs(2_345_678)));
|
|
assert(st + dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33), hnsecs(2_345_678)));
|
|
assert(st + dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33), hnsecs(2_345_678)));
|
|
assert(st + dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33), hnsecs(2_345_678)));
|
|
assert(st + dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40), hnsecs(2_345_678)));
|
|
assert(st + dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26), hnsecs(2_345_678)));
|
|
assert(st + dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_415_678)));
|
|
assert(st + dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_275_678)));
|
|
assert(st + dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748)));
|
|
assert(st + dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608)));
|
|
assert(st + dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_685)));
|
|
assert(st + dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), 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)
|
|
{
|
|
assert(st + TickDuration.from!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748)));
|
|
assert(st + TickDuration.from!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608)));
|
|
}
|
|
|
|
assert(st - dur!"weeks"(-7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33), hnsecs(2_345_678)));
|
|
assert(st - dur!"weeks"(7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33), hnsecs(2_345_678)));
|
|
assert(st - dur!"days"(-7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33), hnsecs(2_345_678)));
|
|
assert(st - dur!"days"(7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33), hnsecs(2_345_678)));
|
|
assert(st - dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33), hnsecs(2_345_678)));
|
|
assert(st - dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33), hnsecs(2_345_678)));
|
|
assert(st - dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33), hnsecs(2_345_678)));
|
|
assert(st - dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33), hnsecs(2_345_678)));
|
|
assert(st - dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40), hnsecs(2_345_678)));
|
|
assert(st - dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26), hnsecs(2_345_678)));
|
|
assert(st - dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_415_678)));
|
|
assert(st - dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_275_678)));
|
|
assert(st - dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748)));
|
|
assert(st - dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608)));
|
|
assert(st - dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_685)));
|
|
assert(st - dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), 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)
|
|
{
|
|
assert(st - TickDuration.from!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748)));
|
|
assert(st - TickDuration.from!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608)));
|
|
}
|
|
|
|
static void testST(in SysTime orig, long hnsecs, in SysTime expected, size_t line = __LINE__)
|
|
{
|
|
import std.format : format;
|
|
auto result = orig + dur!"hnsecs"(hnsecs);
|
|
if(result != expected)
|
|
throw new AssertError(format("Failed. actual [%s] != expected [%s]", result, expected), __FILE__, line);
|
|
}
|
|
|
|
//Test A.D.
|
|
auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274));
|
|
testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274)));
|
|
testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(275)));
|
|
testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(276)));
|
|
testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(284)));
|
|
testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(374)));
|
|
testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(999)));
|
|
testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1000)));
|
|
testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1274)));
|
|
testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1275)));
|
|
testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2274)));
|
|
testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
|
|
testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
|
|
testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
|
|
testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
|
|
testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
|
|
testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
|
|
testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), hnsecs(274)));
|
|
testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), hnsecs(274)));
|
|
testST(beforeAD, 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), hnsecs(274)));
|
|
testST(beforeAD, 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), hnsecs(274)));
|
|
|
|
testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(273)));
|
|
testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(272)));
|
|
testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(264)));
|
|
testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(174)));
|
|
testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
|
|
testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
|
|
testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
|
|
testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
|
|
testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
|
|
testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
|
|
testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
|
|
testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
|
|
testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
|
|
testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), hnsecs(274)));
|
|
testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), hnsecs(274)));
|
|
testST(beforeAD, -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), hnsecs(274)));
|
|
testST(beforeAD, -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), hnsecs(274)));
|
|
|
|
//Test B.C.
|
|
auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274));
|
|
testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274)));
|
|
testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(275)));
|
|
testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(276)));
|
|
testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(284)));
|
|
testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(374)));
|
|
testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(999)));
|
|
testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1000)));
|
|
testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1274)));
|
|
testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1275)));
|
|
testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(2274)));
|
|
testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
|
|
testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
|
|
testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
|
|
testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
|
|
testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
|
|
testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
|
|
testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), hnsecs(274)));
|
|
testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), hnsecs(274)));
|
|
testST(beforeBC, 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), hnsecs(274)));
|
|
testST(beforeBC, 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), hnsecs(274)));
|
|
|
|
testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(273)));
|
|
testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(272)));
|
|
testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(264)));
|
|
testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(174)));
|
|
testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
|
|
testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
|
|
testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
|
|
testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
|
|
testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
|
|
testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
|
|
testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
|
|
testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
|
|
testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
|
|
testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
|
|
testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), hnsecs(274)));
|
|
testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), hnsecs(274)));
|
|
testST(beforeBC, -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), hnsecs(274)));
|
|
testST(beforeBC, -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), hnsecs(274)));
|
|
|
|
//Test Both
|
|
auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
|
|
testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
|
|
testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
testST(beforeBoth1, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
testST(beforeBoth1, -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
|
|
testST(beforeBoth1, -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_000)));
|
|
testST(beforeBoth1, -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_998_000)));
|
|
testST(beforeBoth1, -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_997_445)));
|
|
testST(beforeBoth1, -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_000_000)));
|
|
testST(beforeBoth1, -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(8_000_000)));
|
|
testST(beforeBoth1, -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(7_666_667)));
|
|
testST(beforeBoth1, -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
|
|
testST(beforeBoth1, -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58)));
|
|
testST(beforeBoth1, -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), hnsecs(9_111_112)));
|
|
|
|
auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
|
|
testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
|
|
testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
testST(beforeBoth2, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
testST(beforeBoth2, 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
|
|
testST(beforeBoth2, 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999)));
|
|
testST(beforeBoth2, 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1999)));
|
|
testST(beforeBoth2, 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2554)));
|
|
testST(beforeBoth2, 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999_999)));
|
|
testST(beforeBoth2, 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1_999_999)));
|
|
testST(beforeBoth2, 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2_333_332)));
|
|
testST(beforeBoth2, 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
|
|
testST(beforeBoth2, 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), hnsecs(9_999_999)));
|
|
testST(beforeBoth2, 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), 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
|
|
$(LREF SysTime), as well as assigning the result to this $(LREF SysTime).
|
|
|
|
The legal types of arithmetic for $(LREF SysTime) using this operator are
|
|
|
|
$(BOOKTABLE,
|
|
$(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
|
|
$(LREF SysTime).
|
|
+/
|
|
ref SysTime opOpAssign(string op, D)(in D duration) @safe pure nothrow
|
|
if((op == "+" || op == "-") &&
|
|
(is(Unqual!D == Duration) ||
|
|
is(Unqual!D == TickDuration)))
|
|
{
|
|
import std.format : format;
|
|
|
|
static if(is(Unqual!D == Duration))
|
|
auto hnsecs = duration.total!"hnsecs";
|
|
else static if(is(Unqual!D == TickDuration))
|
|
auto hnsecs = duration.hnsecs;
|
|
|
|
mixin(format("_stdTime %s= hnsecs;", op));
|
|
return this;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto before = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
|
|
assert(before + dur!"weeks"(7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33)));
|
|
assert(before + dur!"weeks"(-7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33)));
|
|
assert(before + dur!"days"(7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33)));
|
|
assert(before + dur!"days"(-7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33)));
|
|
|
|
assert(before + dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33)));
|
|
assert(before + dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33)));
|
|
assert(before + dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33)));
|
|
assert(before + dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33)));
|
|
assert(before + dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40)));
|
|
assert(before + dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26)));
|
|
assert(before + dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(7)));
|
|
assert(before + dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), msecs(993)));
|
|
assert(before + dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(7)));
|
|
assert(before + dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), usecs(999_993)));
|
|
assert(before + dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(7)));
|
|
assert(before + dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_993)));
|
|
|
|
assert(before - dur!"weeks"(-7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33)));
|
|
assert(before - dur!"weeks"(7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33)));
|
|
assert(before - dur!"days"(-7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33)));
|
|
assert(before - dur!"days"(7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33)));
|
|
|
|
assert(before - dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33)));
|
|
assert(before - dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33)));
|
|
assert(before - dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33)));
|
|
assert(before - dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33)));
|
|
assert(before - dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40)));
|
|
assert(before - dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26)));
|
|
assert(before - dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(7)));
|
|
assert(before - dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), msecs(993)));
|
|
assert(before - dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(7)));
|
|
assert(before - dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), usecs(999_993)));
|
|
assert(before - dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(7)));
|
|
assert(before - dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_993)));
|
|
|
|
static void testST(SysTime orig, long hnsecs, in SysTime expected, size_t line = __LINE__)
|
|
{
|
|
import std.format : format;
|
|
|
|
auto r = orig += dur!"hnsecs"(hnsecs);
|
|
if(orig != expected)
|
|
throw new AssertError(format("Failed 1. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
|
|
if(r != expected)
|
|
throw new AssertError(format("Failed 2. actual [%s] != expected [%s]", r, expected), __FILE__, line);
|
|
}
|
|
|
|
//Test A.D.
|
|
auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274));
|
|
testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274)));
|
|
testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(275)));
|
|
testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(276)));
|
|
testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(284)));
|
|
testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(374)));
|
|
testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(999)));
|
|
testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1000)));
|
|
testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1274)));
|
|
testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1275)));
|
|
testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2274)));
|
|
testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
|
|
testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
|
|
testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
|
|
testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
|
|
testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
|
|
testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
|
|
testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), hnsecs(274)));
|
|
testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), hnsecs(274)));
|
|
testST(beforeAD, 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), hnsecs(274)));
|
|
testST(beforeAD, 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), hnsecs(274)));
|
|
|
|
testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(273)));
|
|
testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(272)));
|
|
testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(264)));
|
|
testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(174)));
|
|
testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
|
|
testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
|
|
testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
|
|
testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
|
|
testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
|
|
testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
|
|
testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
|
|
testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
|
|
testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
|
|
testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), hnsecs(274)));
|
|
testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), hnsecs(274)));
|
|
testST(beforeAD, -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), hnsecs(274)));
|
|
testST(beforeAD, -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), hnsecs(274)));
|
|
|
|
//Test B.C.
|
|
auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274));
|
|
testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274)));
|
|
testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(275)));
|
|
testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(276)));
|
|
testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(284)));
|
|
testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(374)));
|
|
testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(999)));
|
|
testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1000)));
|
|
testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1274)));
|
|
testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1275)));
|
|
testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(2274)));
|
|
testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
|
|
testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
|
|
testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
|
|
testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
|
|
testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
|
|
testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
|
|
testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), hnsecs(274)));
|
|
testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), hnsecs(274)));
|
|
testST(beforeBC, 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), hnsecs(274)));
|
|
testST(beforeBC, 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), hnsecs(274)));
|
|
|
|
testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(273)));
|
|
testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(272)));
|
|
testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(264)));
|
|
testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(174)));
|
|
testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
|
|
testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
|
|
testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
|
|
testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
|
|
testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
|
|
testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
|
|
testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
|
|
testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
|
|
testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
|
|
testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
|
|
testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), hnsecs(274)));
|
|
testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), hnsecs(274)));
|
|
testST(beforeBC, -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), hnsecs(274)));
|
|
testST(beforeBC, -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), hnsecs(274)));
|
|
|
|
//Test Both
|
|
auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
|
|
testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
|
|
testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
testST(beforeBoth1, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
testST(beforeBoth1, -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
|
|
testST(beforeBoth1, -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_000)));
|
|
testST(beforeBoth1, -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_998_000)));
|
|
testST(beforeBoth1, -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_997_445)));
|
|
testST(beforeBoth1, -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_000_000)));
|
|
testST(beforeBoth1, -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(8_000_000)));
|
|
testST(beforeBoth1, -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(7_666_667)));
|
|
testST(beforeBoth1, -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
|
|
testST(beforeBoth1, -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58)));
|
|
testST(beforeBoth1, -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), hnsecs(9_111_112)));
|
|
|
|
auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
|
|
testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
|
|
testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
testST(beforeBoth2, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
testST(beforeBoth2, 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
|
|
testST(beforeBoth2, 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999)));
|
|
testST(beforeBoth2, 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1999)));
|
|
testST(beforeBoth2, 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2554)));
|
|
testST(beforeBoth2, 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999_999)));
|
|
testST(beforeBoth2, 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1_999_999)));
|
|
testST(beforeBoth2, 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2_333_332)));
|
|
testST(beforeBoth2, 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
|
|
testST(beforeBoth2, 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), hnsecs(9_999_999)));
|
|
testST(beforeBoth2, 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), hnsecs(888_887)));
|
|
|
|
{
|
|
auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
|
|
(st += dur!"hnsecs"(52)) += dur!"seconds"(-907);
|
|
assert(st == SysTime(DateTime(0, 12, 31, 23, 44, 53), hnsecs(51)));
|
|
}
|
|
|
|
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 $(LREF SysTime)s.
|
|
|
|
The legal types of arithmetic for $(LREF SysTime) using this operator are
|
|
|
|
$(BOOKTABLE,
|
|
$(TR $(TD SysTime) $(TD -) $(TD SysTime) $(TD -->) $(TD duration))
|
|
)
|
|
+/
|
|
Duration opBinary(string op)(in SysTime rhs) @safe const pure nothrow
|
|
if(op == "-")
|
|
{
|
|
return dur!"hnsecs"(_stdTime - rhs._stdTime);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1998, 7, 6, 12, 30, 33)) ==
|
|
dur!"seconds"(31_536_000));
|
|
assert(SysTime(DateTime(1998, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
|
|
dur!"seconds"(-31_536_000));
|
|
|
|
assert(SysTime(DateTime(1999, 8, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
|
|
dur!"seconds"(26_78_400));
|
|
assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 8, 6, 12, 30, 33)) ==
|
|
dur!"seconds"(-26_78_400));
|
|
|
|
assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 5, 12, 30, 33)) ==
|
|
dur!"seconds"(86_400));
|
|
assert(SysTime(DateTime(1999, 7, 5, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
|
|
dur!"seconds"(-86_400));
|
|
|
|
assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 11, 30, 33)) ==
|
|
dur!"seconds"(3600));
|
|
assert(SysTime(DateTime(1999, 7, 6, 11, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
|
|
dur!"seconds"(-3600));
|
|
|
|
assert(SysTime(DateTime(1999, 7, 6, 12, 31, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
|
|
dur!"seconds"(60));
|
|
assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 31, 33)) ==
|
|
dur!"seconds"(-60));
|
|
|
|
assert(SysTime(DateTime(1999, 7, 6, 12, 30, 34)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
|
|
dur!"seconds"(1));
|
|
assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 34)) ==
|
|
dur!"seconds"(-1));
|
|
|
|
{
|
|
auto dt = DateTime(1999, 7, 6, 12, 30, 33);
|
|
assert(SysTime(dt, msecs(532)) - SysTime(dt) == msecs(532));
|
|
assert(SysTime(dt) - SysTime(dt, msecs(532)) == msecs(-532));
|
|
|
|
assert(SysTime(dt, usecs(333_347)) - SysTime(dt) == usecs(333_347));
|
|
assert(SysTime(dt) - SysTime(dt, usecs(333_347)) == usecs(-333_347));
|
|
|
|
assert(SysTime(dt, hnsecs(1_234_567)) - SysTime(dt) == hnsecs(1_234_567));
|
|
assert(SysTime(dt) - SysTime(dt, hnsecs(1_234_567)) == hnsecs(-1_234_567));
|
|
}
|
|
|
|
assert(SysTime(DateTime(1, 1, 1, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) == dur!"seconds"(45033));
|
|
assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(1, 1, 1, 12, 30, 33)) == dur!"seconds"(-45033));
|
|
assert(SysTime(DateTime(0, 12, 31, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) == dur!"seconds"(-41367));
|
|
assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 12, 30, 33)) == dur!"seconds"(41367));
|
|
|
|
assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)) ==
|
|
dur!"hnsecs"(1));
|
|
assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) ==
|
|
dur!"hnsecs"(-1));
|
|
|
|
auto tz = TimeZone.getTimeZone("America/Los_Angeles");
|
|
|
|
{
|
|
auto dt = DateTime(2011, 1, 13, 8, 17, 2);
|
|
auto d = msecs(296);
|
|
assert(SysTime(dt, d, tz) - SysTime(dt, d, tz) == Duration.zero);
|
|
assert(SysTime(dt, d, tz) - SysTime(dt, d, UTC()) == hours(8));
|
|
assert(SysTime(dt, d, UTC()) - SysTime(dt, d, tz) == hours(-8));
|
|
}
|
|
|
|
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 $(LREF SysTime)s in months.
|
|
|
|
To get the difference in years, subtract the year property
|
|
of two $(LREF SysTime)s. To get the difference in days or weeks,
|
|
subtract the $(LREF SysTime)s themselves and use the $(CXREF time, Duration)
|
|
that results. Because converting between months and smaller
|
|
units requires a specific date (which $(CXREF time, Duration)s don't have),
|
|
getting the difference in months requires 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 $(LREF SysTime) to subtract from this one.
|
|
+/
|
|
int diffMonths(in SysTime rhs) @safe const nothrow
|
|
{
|
|
return (cast(Date)this).diffMonths(cast(Date)rhs);
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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);
|
|
}
|
|
|
|
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)));
|
|
}
|
|
|
|
|
|
/++
|
|
Whether this $(LREF SysTime) is in a leap year.
|
|
+/
|
|
@property bool isLeapYear() @safe 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 $(LREF SysTime) is on.
|
|
+/
|
|
@property DayOfWeek dayOfWeek() @safe 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 $(LREF SysTime) is on.
|
|
+/
|
|
@property ushort dayOfYear() @safe const nothrow
|
|
{
|
|
return (cast(Date)this).dayOfYear;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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);
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
/++
|
|
Day of the year.
|
|
|
|
Params:
|
|
day = The day of the year to set which day of the year this
|
|
$(LREF SysTime) is on.
|
|
+/
|
|
@property void dayOfYear(int day) @safe
|
|
{
|
|
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 $(LREF SysTime) is on.
|
|
+/
|
|
@property int dayOfGregorianCal() @safe 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;
|
|
|
|
long hnsecs = adjustedTime;
|
|
immutable days = cast(int)splitUnitsFromHNSecs!"days"(hnsecs);
|
|
|
|
return hnsecs == 0 ? days + 1 : days;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1);
|
|
assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)).dayOfGregorianCal == 1);
|
|
assert(SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == 1);
|
|
|
|
assert(SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1);
|
|
assert(SysTime(DateTime(1, 1, 2, 12, 2, 9), msecs(212)).dayOfGregorianCal == 2);
|
|
assert(SysTime(DateTime(1, 2, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 32);
|
|
assert(SysTime(DateTime(2, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 366);
|
|
assert(SysTime(DateTime(3, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 731);
|
|
assert(SysTime(DateTime(4, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1096);
|
|
assert(SysTime(DateTime(5, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1462);
|
|
assert(SysTime(DateTime(50, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 17_898);
|
|
assert(SysTime(DateTime(97, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 35_065);
|
|
assert(SysTime(DateTime(100, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 36_160);
|
|
assert(SysTime(DateTime(101, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 36_525);
|
|
assert(SysTime(DateTime(105, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 37_986);
|
|
assert(SysTime(DateTime(200, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 72_684);
|
|
assert(SysTime(DateTime(201, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 73_049);
|
|
assert(SysTime(DateTime(300, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 109_208);
|
|
assert(SysTime(DateTime(301, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 109_573);
|
|
assert(SysTime(DateTime(400, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 145_732);
|
|
assert(SysTime(DateTime(401, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 146_098);
|
|
assert(SysTime(DateTime(500, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 182_257);
|
|
assert(SysTime(DateTime(501, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 182_622);
|
|
assert(SysTime(DateTime(1000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 364_878);
|
|
assert(SysTime(DateTime(1001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 365_243);
|
|
assert(SysTime(DateTime(1600, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 584_023);
|
|
assert(SysTime(DateTime(1601, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 584_389);
|
|
assert(SysTime(DateTime(1900, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 693_596);
|
|
assert(SysTime(DateTime(1901, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 693_961);
|
|
assert(SysTime(DateTime(1945, 11, 12, 12, 2, 9), msecs(212)).dayOfGregorianCal == 710_347);
|
|
assert(SysTime(DateTime(1999, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 729_755);
|
|
assert(SysTime(DateTime(2000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 730_120);
|
|
assert(SysTime(DateTime(2001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 730_486);
|
|
|
|
assert(SysTime(DateTime(2010, 1, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_773);
|
|
assert(SysTime(DateTime(2010, 1, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_803);
|
|
assert(SysTime(DateTime(2010, 2, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_804);
|
|
assert(SysTime(DateTime(2010, 2, 28, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_831);
|
|
assert(SysTime(DateTime(2010, 3, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_832);
|
|
assert(SysTime(DateTime(2010, 3, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_862);
|
|
assert(SysTime(DateTime(2010, 4, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_863);
|
|
assert(SysTime(DateTime(2010, 4, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_892);
|
|
assert(SysTime(DateTime(2010, 5, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_893);
|
|
assert(SysTime(DateTime(2010, 5, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_923);
|
|
assert(SysTime(DateTime(2010, 6, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_924);
|
|
assert(SysTime(DateTime(2010, 6, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_953);
|
|
assert(SysTime(DateTime(2010, 7, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_954);
|
|
assert(SysTime(DateTime(2010, 7, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_984);
|
|
assert(SysTime(DateTime(2010, 8, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_985);
|
|
assert(SysTime(DateTime(2010, 8, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_015);
|
|
assert(SysTime(DateTime(2010, 9, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_016);
|
|
assert(SysTime(DateTime(2010, 9, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_045);
|
|
assert(SysTime(DateTime(2010, 10, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_046);
|
|
assert(SysTime(DateTime(2010, 10, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_076);
|
|
assert(SysTime(DateTime(2010, 11, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_077);
|
|
assert(SysTime(DateTime(2010, 11, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_106);
|
|
assert(SysTime(DateTime(2010, 12, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_107);
|
|
assert(SysTime(DateTime(2010, 12, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_137);
|
|
|
|
assert(SysTime(DateTime(2012, 2, 1, 0, 0, 0)).dayOfGregorianCal == 734_534);
|
|
assert(SysTime(DateTime(2012, 2, 28, 0, 0, 0)).dayOfGregorianCal == 734_561);
|
|
assert(SysTime(DateTime(2012, 2, 29, 0, 0, 0)).dayOfGregorianCal == 734_562);
|
|
assert(SysTime(DateTime(2012, 3, 1, 0, 0, 0)).dayOfGregorianCal == 734_563);
|
|
|
|
//Test B.C.
|
|
assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == 0);
|
|
assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)).dayOfGregorianCal == 0);
|
|
assert(SysTime(DateTime(0, 12, 31, 23, 59, 59)).dayOfGregorianCal == 0);
|
|
assert(SysTime(DateTime(0, 12, 31, 0, 0, 0), hnsecs(1)).dayOfGregorianCal == 0);
|
|
assert(SysTime(DateTime(0, 12, 31, 0, 0, 0)).dayOfGregorianCal == 0);
|
|
|
|
assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == -366);
|
|
assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59), hnsecs(9_999_998)).dayOfGregorianCal == -366);
|
|
assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59)).dayOfGregorianCal == -366);
|
|
assert(SysTime(DateTime(-1, 12, 31, 0, 0, 0)).dayOfGregorianCal == -366);
|
|
|
|
assert(SysTime(DateTime(0, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == 0);
|
|
assert(SysTime(DateTime(0, 12, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1);
|
|
assert(SysTime(DateTime(0, 12, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -30);
|
|
assert(SysTime(DateTime(0, 11, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -31);
|
|
|
|
assert(SysTime(DateTime(-1, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -366);
|
|
assert(SysTime(DateTime(-1, 12, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -367);
|
|
assert(SysTime(DateTime(-1, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730);
|
|
assert(SysTime(DateTime(-2, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -731);
|
|
assert(SysTime(DateTime(-2, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1095);
|
|
assert(SysTime(DateTime(-3, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1096);
|
|
assert(SysTime(DateTime(-3, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1460);
|
|
assert(SysTime(DateTime(-4, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1461);
|
|
assert(SysTime(DateTime(-4, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1826);
|
|
assert(SysTime(DateTime(-5, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1827);
|
|
assert(SysTime(DateTime(-5, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -2191);
|
|
assert(SysTime(DateTime(-9, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -3652);
|
|
|
|
assert(SysTime(DateTime(-49, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -18_262);
|
|
assert(SysTime(DateTime(-50, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -18_627);
|
|
assert(SysTime(DateTime(-97, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -35_794);
|
|
assert(SysTime(DateTime(-99, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_160);
|
|
assert(SysTime(DateTime(-99, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_524);
|
|
assert(SysTime(DateTime(-100, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_889);
|
|
assert(SysTime(DateTime(-101, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -37_254);
|
|
assert(SysTime(DateTime(-105, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -38_715);
|
|
assert(SysTime(DateTime(-200, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -73_413);
|
|
assert(SysTime(DateTime(-201, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -73_778);
|
|
assert(SysTime(DateTime(-300, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -109_937);
|
|
assert(SysTime(DateTime(-301, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -110_302);
|
|
assert(SysTime(DateTime(-400, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_097);
|
|
assert(SysTime(DateTime(-400, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_462);
|
|
assert(SysTime(DateTime(-401, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_827);
|
|
assert(SysTime(DateTime(-499, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -182_621);
|
|
assert(SysTime(DateTime(-500, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -182_986);
|
|
assert(SysTime(DateTime(-501, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -183_351);
|
|
assert(SysTime(DateTime(-1000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -365_607);
|
|
assert(SysTime(DateTime(-1001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -365_972);
|
|
assert(SysTime(DateTime(-1599, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_387);
|
|
assert(SysTime(DateTime(-1600, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_388);
|
|
assert(SysTime(DateTime(-1600, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_753);
|
|
assert(SysTime(DateTime(-1601, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -585_118);
|
|
assert(SysTime(DateTime(-1900, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -694_325);
|
|
assert(SysTime(DateTime(-1901, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -694_690);
|
|
assert(SysTime(DateTime(-1999, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_484);
|
|
assert(SysTime(DateTime(-2000, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_485);
|
|
assert(SysTime(DateTime(-2000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_850);
|
|
assert(SysTime(DateTime(-2001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -731_215);
|
|
|
|
assert(SysTime(DateTime(-2010, 1, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_502);
|
|
assert(SysTime(DateTime(-2010, 1, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_472);
|
|
assert(SysTime(DateTime(-2010, 2, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_471);
|
|
assert(SysTime(DateTime(-2010, 2, 28, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_444);
|
|
assert(SysTime(DateTime(-2010, 3, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_443);
|
|
assert(SysTime(DateTime(-2010, 3, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_413);
|
|
assert(SysTime(DateTime(-2010, 4, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_412);
|
|
assert(SysTime(DateTime(-2010, 4, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_383);
|
|
assert(SysTime(DateTime(-2010, 5, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_382);
|
|
assert(SysTime(DateTime(-2010, 5, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_352);
|
|
assert(SysTime(DateTime(-2010, 6, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_351);
|
|
assert(SysTime(DateTime(-2010, 6, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_322);
|
|
assert(SysTime(DateTime(-2010, 7, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_321);
|
|
assert(SysTime(DateTime(-2010, 7, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_291);
|
|
assert(SysTime(DateTime(-2010, 8, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_290);
|
|
assert(SysTime(DateTime(-2010, 8, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_260);
|
|
assert(SysTime(DateTime(-2010, 9, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_259);
|
|
assert(SysTime(DateTime(-2010, 9, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_230);
|
|
assert(SysTime(DateTime(-2010, 10, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_229);
|
|
assert(SysTime(DateTime(-2010, 10, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_199);
|
|
assert(SysTime(DateTime(-2010, 11, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_198);
|
|
assert(SysTime(DateTime(-2010, 11, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_169);
|
|
assert(SysTime(DateTime(-2010, 12, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_168);
|
|
assert(SysTime(DateTime(-2010, 12, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_138);
|
|
|
|
assert(SysTime(DateTime(-2012, 2, 1, 0, 0, 0)).dayOfGregorianCal == -735_202);
|
|
assert(SysTime(DateTime(-2012, 2, 28, 0, 0, 0)).dayOfGregorianCal == -735_175);
|
|
assert(SysTime(DateTime(-2012, 2, 29, 0, 0, 0)).dayOfGregorianCal == -735_174);
|
|
assert(SysTime(DateTime(-2012, 3, 1, 0, 0, 0)).dayOfGregorianCal == -735_173);
|
|
|
|
// Start of Hebrew Calendar
|
|
assert(SysTime(DateTime(-3760, 9, 7, 0, 0, 0)).dayOfGregorianCal == -1_373_427);
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
//Test that the logic for the day of the Gregorian Calendar is consistent
|
|
//between Date and SysTime.
|
|
unittest
|
|
{
|
|
void test(Date date, SysTime st, size_t line = __LINE__)
|
|
{
|
|
import std.format : format;
|
|
|
|
if(date.dayOfGregorianCal != st.dayOfGregorianCal)
|
|
{
|
|
throw new AssertError(format("Date [%s] SysTime [%s]", date.dayOfGregorianCal, st.dayOfGregorianCal),
|
|
__FILE__, line);
|
|
}
|
|
}
|
|
|
|
//Test A.D.
|
|
test(Date(1, 1, 1), SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
test(Date(1, 1, 2), SysTime(DateTime(1, 1, 2, 0, 0, 0), hnsecs(500)));
|
|
test(Date(1, 2, 1), SysTime(DateTime(1, 2, 1, 0, 0, 0), hnsecs(50_000)));
|
|
test(Date(2, 1, 1), SysTime(DateTime(2, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
|
|
test(Date(3, 1, 1), SysTime(DateTime(3, 1, 1, 12, 13, 14)));
|
|
test(Date(4, 1, 1), SysTime(DateTime(4, 1, 1, 12, 13, 14), hnsecs(500)));
|
|
test(Date(5, 1, 1), SysTime(DateTime(5, 1, 1, 12, 13, 14), hnsecs(50_000)));
|
|
test(Date(50, 1, 1), SysTime(DateTime(50, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
|
|
test(Date(97, 1, 1), SysTime(DateTime(97, 1, 1, 23, 59, 59)));
|
|
test(Date(100, 1, 1), SysTime(DateTime(100, 1, 1, 23, 59, 59), hnsecs(500)));
|
|
test(Date(101, 1, 1), SysTime(DateTime(101, 1, 1, 23, 59, 59), hnsecs(50_000)));
|
|
test(Date(105, 1, 1), SysTime(DateTime(105, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
test(Date(200, 1, 1), SysTime(DateTime(200, 1, 1, 0, 0, 0)));
|
|
test(Date(201, 1, 1), SysTime(DateTime(201, 1, 1, 0, 0, 0), hnsecs(500)));
|
|
test(Date(300, 1, 1), SysTime(DateTime(300, 1, 1, 0, 0, 0), hnsecs(50_000)));
|
|
test(Date(301, 1, 1), SysTime(DateTime(301, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
|
|
test(Date(400, 1, 1), SysTime(DateTime(400, 1, 1, 12, 13, 14)));
|
|
test(Date(401, 1, 1), SysTime(DateTime(401, 1, 1, 12, 13, 14), hnsecs(500)));
|
|
test(Date(500, 1, 1), SysTime(DateTime(500, 1, 1, 12, 13, 14), hnsecs(50_000)));
|
|
test(Date(501, 1, 1), SysTime(DateTime(501, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
|
|
test(Date(1000, 1, 1), SysTime(DateTime(1000, 1, 1, 23, 59, 59)));
|
|
test(Date(1001, 1, 1), SysTime(DateTime(1001, 1, 1, 23, 59, 59), hnsecs(500)));
|
|
test(Date(1600, 1, 1), SysTime(DateTime(1600, 1, 1, 23, 59, 59), hnsecs(50_000)));
|
|
test(Date(1601, 1, 1), SysTime(DateTime(1601, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
test(Date(1900, 1, 1), SysTime(DateTime(1900, 1, 1, 0, 0, 0)));
|
|
test(Date(1901, 1, 1), SysTime(DateTime(1901, 1, 1, 0, 0, 0), hnsecs(500)));
|
|
test(Date(1945, 11, 12), SysTime(DateTime(1945, 11, 12, 0, 0, 0), hnsecs(50_000)));
|
|
test(Date(1999, 1, 1), SysTime(DateTime(1999, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
|
|
test(Date(1999, 7, 6), SysTime(DateTime(1999, 7, 6, 12, 13, 14)));
|
|
test(Date(2000, 1, 1), SysTime(DateTime(2000, 1, 1, 12, 13, 14), hnsecs(500)));
|
|
test(Date(2001, 1, 1), SysTime(DateTime(2001, 1, 1, 12, 13, 14), hnsecs(50_000)));
|
|
|
|
test(Date(2010, 1, 1), SysTime(DateTime(2010, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
|
|
test(Date(2010, 1, 31), SysTime(DateTime(2010, 1, 31, 23, 0, 0)));
|
|
test(Date(2010, 2, 1), SysTime(DateTime(2010, 2, 1, 23, 59, 59), hnsecs(500)));
|
|
test(Date(2010, 2, 28), SysTime(DateTime(2010, 2, 28, 23, 59, 59), hnsecs(50_000)));
|
|
test(Date(2010, 3, 1), SysTime(DateTime(2010, 3, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
test(Date(2010, 3, 31), SysTime(DateTime(2010, 3, 31, 0, 0, 0)));
|
|
test(Date(2010, 4, 1), SysTime(DateTime(2010, 4, 1, 0, 0, 0), hnsecs(500)));
|
|
test(Date(2010, 4, 30), SysTime(DateTime(2010, 4, 30, 0, 0, 0), hnsecs(50_000)));
|
|
test(Date(2010, 5, 1), SysTime(DateTime(2010, 5, 1, 0, 0, 0), hnsecs(9_999_999)));
|
|
test(Date(2010, 5, 31), SysTime(DateTime(2010, 5, 31, 12, 13, 14)));
|
|
test(Date(2010, 6, 1), SysTime(DateTime(2010, 6, 1, 12, 13, 14), hnsecs(500)));
|
|
test(Date(2010, 6, 30), SysTime(DateTime(2010, 6, 30, 12, 13, 14), hnsecs(50_000)));
|
|
test(Date(2010, 7, 1), SysTime(DateTime(2010, 7, 1, 12, 13, 14), hnsecs(9_999_999)));
|
|
test(Date(2010, 7, 31), SysTime(DateTime(2010, 7, 31, 23, 59, 59)));
|
|
test(Date(2010, 8, 1), SysTime(DateTime(2010, 8, 1, 23, 59, 59), hnsecs(500)));
|
|
test(Date(2010, 8, 31), SysTime(DateTime(2010, 8, 31, 23, 59, 59), hnsecs(50_000)));
|
|
test(Date(2010, 9, 1), SysTime(DateTime(2010, 9, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
test(Date(2010, 9, 30), SysTime(DateTime(2010, 9, 30, 12, 0, 0)));
|
|
test(Date(2010, 10, 1), SysTime(DateTime(2010, 10, 1, 0, 12, 0), hnsecs(500)));
|
|
test(Date(2010, 10, 31), SysTime(DateTime(2010, 10, 31, 0, 0, 12), hnsecs(50_000)));
|
|
test(Date(2010, 11, 1), SysTime(DateTime(2010, 11, 1, 23, 0, 0), hnsecs(9_999_999)));
|
|
test(Date(2010, 11, 30), SysTime(DateTime(2010, 11, 30, 0, 59, 0)));
|
|
test(Date(2010, 12, 1), SysTime(DateTime(2010, 12, 1, 0, 0, 59), hnsecs(500)));
|
|
test(Date(2010, 12, 31), SysTime(DateTime(2010, 12, 31, 0, 59, 59), hnsecs(50_000)));
|
|
|
|
test(Date(2012, 2, 1), SysTime(DateTime(2012, 2, 1, 23, 0, 59), hnsecs(9_999_999)));
|
|
test(Date(2012, 2, 28), SysTime(DateTime(2012, 2, 28, 23, 59, 0)));
|
|
test(Date(2012, 2, 29), SysTime(DateTime(2012, 2, 29, 7, 7, 7), hnsecs(7)));
|
|
test(Date(2012, 3, 1), SysTime(DateTime(2012, 3, 1, 7, 7, 7), hnsecs(7)));
|
|
|
|
//Test B.C.
|
|
test(Date(0, 12, 31), SysTime(DateTime(0, 12, 31, 0, 0, 0)));
|
|
test(Date(0, 12, 30), SysTime(DateTime(0, 12, 30, 0, 0, 0), hnsecs(500)));
|
|
test(Date(0, 12, 1), SysTime(DateTime(0, 12, 1, 0, 0, 0), hnsecs(50_000)));
|
|
test(Date(0, 11, 30), SysTime(DateTime(0, 11, 30, 0, 0, 0), hnsecs(9_999_999)));
|
|
|
|
test(Date(-1, 12, 31), SysTime(DateTime(-1, 12, 31, 12, 13, 14)));
|
|
test(Date(-1, 12, 30), SysTime(DateTime(-1, 12, 30, 12, 13, 14), hnsecs(500)));
|
|
test(Date(-1, 1, 1), SysTime(DateTime(-1, 1, 1, 12, 13, 14), hnsecs(50_000)));
|
|
test(Date(-2, 12, 31), SysTime(DateTime(-2, 12, 31, 12, 13, 14), hnsecs(9_999_999)));
|
|
test(Date(-2, 1, 1), SysTime(DateTime(-2, 1, 1, 23, 59, 59)));
|
|
test(Date(-3, 12, 31), SysTime(DateTime(-3, 12, 31, 23, 59, 59), hnsecs(500)));
|
|
test(Date(-3, 1, 1), SysTime(DateTime(-3, 1, 1, 23, 59, 59), hnsecs(50_000)));
|
|
test(Date(-4, 12, 31), SysTime(DateTime(-4, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
test(Date(-4, 1, 1), SysTime(DateTime(-4, 1, 1, 0, 0, 0)));
|
|
test(Date(-5, 12, 31), SysTime(DateTime(-5, 12, 31, 0, 0, 0), hnsecs(500)));
|
|
test(Date(-5, 1, 1), SysTime(DateTime(-5, 1, 1, 0, 0, 0), hnsecs(50_000)));
|
|
test(Date(-9, 1, 1), SysTime(DateTime(-9, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
|
|
|
|
test(Date(-49, 1, 1), SysTime(DateTime(-49, 1, 1, 12, 13, 14)));
|
|
test(Date(-50, 1, 1), SysTime(DateTime(-50, 1, 1, 12, 13, 14), hnsecs(500)));
|
|
test(Date(-97, 1, 1), SysTime(DateTime(-97, 1, 1, 12, 13, 14), hnsecs(50_000)));
|
|
test(Date(-99, 12, 31), SysTime(DateTime(-99, 12, 31, 12, 13, 14), hnsecs(9_999_999)));
|
|
test(Date(-99, 1, 1), SysTime(DateTime(-99, 1, 1, 23, 59, 59)));
|
|
test(Date(-100, 1, 1), SysTime(DateTime(-100, 1, 1, 23, 59, 59), hnsecs(500)));
|
|
test(Date(-101, 1, 1), SysTime(DateTime(-101, 1, 1, 23, 59, 59), hnsecs(50_000)));
|
|
test(Date(-105, 1, 1), SysTime(DateTime(-105, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
test(Date(-200, 1, 1), SysTime(DateTime(-200, 1, 1, 0, 0, 0)));
|
|
test(Date(-201, 1, 1), SysTime(DateTime(-201, 1, 1, 0, 0, 0), hnsecs(500)));
|
|
test(Date(-300, 1, 1), SysTime(DateTime(-300, 1, 1, 0, 0, 0), hnsecs(50_000)));
|
|
test(Date(-301, 1, 1), SysTime(DateTime(-301, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
|
|
test(Date(-400, 12, 31), SysTime(DateTime(-400, 12, 31, 12, 13, 14)));
|
|
test(Date(-400, 1, 1), SysTime(DateTime(-400, 1, 1, 12, 13, 14), hnsecs(500)));
|
|
test(Date(-401, 1, 1), SysTime(DateTime(-401, 1, 1, 12, 13, 14), hnsecs(50_000)));
|
|
test(Date(-499, 1, 1), SysTime(DateTime(-499, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
|
|
test(Date(-500, 1, 1), SysTime(DateTime(-500, 1, 1, 23, 59, 59)));
|
|
test(Date(-501, 1, 1), SysTime(DateTime(-501, 1, 1, 23, 59, 59), hnsecs(500)));
|
|
test(Date(-1000, 1, 1), SysTime(DateTime(-1000, 1, 1, 23, 59, 59), hnsecs(50_000)));
|
|
test(Date(-1001, 1, 1), SysTime(DateTime(-1001, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
test(Date(-1599, 1, 1), SysTime(DateTime(-1599, 1, 1, 0, 0, 0)));
|
|
test(Date(-1600, 12, 31), SysTime(DateTime(-1600, 12, 31, 0, 0, 0), hnsecs(500)));
|
|
test(Date(-1600, 1, 1), SysTime(DateTime(-1600, 1, 1, 0, 0, 0), hnsecs(50_000)));
|
|
test(Date(-1601, 1, 1), SysTime(DateTime(-1601, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
|
|
test(Date(-1900, 1, 1), SysTime(DateTime(-1900, 1, 1, 12, 13, 14)));
|
|
test(Date(-1901, 1, 1), SysTime(DateTime(-1901, 1, 1, 12, 13, 14), hnsecs(500)));
|
|
test(Date(-1999, 1, 1), SysTime(DateTime(-1999, 1, 1, 12, 13, 14), hnsecs(50_000)));
|
|
test(Date(-1999, 7, 6), SysTime(DateTime(-1999, 7, 6, 12, 13, 14), hnsecs(9_999_999)));
|
|
test(Date(-2000, 12, 31), SysTime(DateTime(-2000, 12, 31, 23, 59, 59)));
|
|
test(Date(-2000, 1, 1), SysTime(DateTime(-2000, 1, 1, 23, 59, 59), hnsecs(500)));
|
|
test(Date(-2001, 1, 1), SysTime(DateTime(-2001, 1, 1, 23, 59, 59), hnsecs(50_000)));
|
|
|
|
test(Date(-2010, 1, 1), SysTime(DateTime(-2010, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
test(Date(-2010, 1, 31), SysTime(DateTime(-2010, 1, 31, 0, 0, 0)));
|
|
test(Date(-2010, 2, 1), SysTime(DateTime(-2010, 2, 1, 0, 0, 0), hnsecs(500)));
|
|
test(Date(-2010, 2, 28), SysTime(DateTime(-2010, 2, 28, 0, 0, 0), hnsecs(50_000)));
|
|
test(Date(-2010, 3, 1), SysTime(DateTime(-2010, 3, 1, 0, 0, 0), hnsecs(9_999_999)));
|
|
test(Date(-2010, 3, 31), SysTime(DateTime(-2010, 3, 31, 12, 13, 14)));
|
|
test(Date(-2010, 4, 1), SysTime(DateTime(-2010, 4, 1, 12, 13, 14), hnsecs(500)));
|
|
test(Date(-2010, 4, 30), SysTime(DateTime(-2010, 4, 30, 12, 13, 14), hnsecs(50_000)));
|
|
test(Date(-2010, 5, 1), SysTime(DateTime(-2010, 5, 1, 12, 13, 14), hnsecs(9_999_999)));
|
|
test(Date(-2010, 5, 31), SysTime(DateTime(-2010, 5, 31, 23, 59, 59)));
|
|
test(Date(-2010, 6, 1), SysTime(DateTime(-2010, 6, 1, 23, 59, 59), hnsecs(500)));
|
|
test(Date(-2010, 6, 30), SysTime(DateTime(-2010, 6, 30, 23, 59, 59), hnsecs(50_000)));
|
|
test(Date(-2010, 7, 1), SysTime(DateTime(-2010, 7, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
test(Date(-2010, 7, 31), SysTime(DateTime(-2010, 7, 31, 0, 0, 0)));
|
|
test(Date(-2010, 8, 1), SysTime(DateTime(-2010, 8, 1, 0, 0, 0), hnsecs(500)));
|
|
test(Date(-2010, 8, 31), SysTime(DateTime(-2010, 8, 31, 0, 0, 0), hnsecs(50_000)));
|
|
test(Date(-2010, 9, 1), SysTime(DateTime(-2010, 9, 1, 0, 0, 0), hnsecs(9_999_999)));
|
|
test(Date(-2010, 9, 30), SysTime(DateTime(-2010, 9, 30, 12, 0, 0)));
|
|
test(Date(-2010, 10, 1), SysTime(DateTime(-2010, 10, 1, 0, 12, 0), hnsecs(500)));
|
|
test(Date(-2010, 10, 31), SysTime(DateTime(-2010, 10, 31, 0, 0, 12), hnsecs(50_000)));
|
|
test(Date(-2010, 11, 1), SysTime(DateTime(-2010, 11, 1, 23, 0, 0), hnsecs(9_999_999)));
|
|
test(Date(-2010, 11, 30), SysTime(DateTime(-2010, 11, 30, 0, 59, 0)));
|
|
test(Date(-2010, 12, 1), SysTime(DateTime(-2010, 12, 1, 0, 0, 59), hnsecs(500)));
|
|
test(Date(-2010, 12, 31), SysTime(DateTime(-2010, 12, 31, 0, 59, 59), hnsecs(50_000)));
|
|
|
|
test(Date(-2012, 2, 1), SysTime(DateTime(-2012, 2, 1, 23, 0, 59), hnsecs(9_999_999)));
|
|
test(Date(-2012, 2, 28), SysTime(DateTime(-2012, 2, 28, 23, 59, 0)));
|
|
test(Date(-2012, 2, 29), SysTime(DateTime(-2012, 2, 29, 7, 7, 7), hnsecs(7)));
|
|
test(Date(-2012, 3, 1), SysTime(DateTime(-2012, 3, 1, 7, 7, 7), hnsecs(7)));
|
|
|
|
test(Date(-3760, 9, 7), SysTime(DateTime(-3760, 9, 7, 0, 0, 0)));
|
|
}
|
|
|
|
|
|
/++
|
|
The Xth day of the Gregorian Calendar that this $(LREF SysTime) is on.
|
|
Setting this property does not affect the time portion of $(LREF SysTime).
|
|
|
|
Params:
|
|
days = The day of the Gregorian Calendar to set this $(LREF SysTime)
|
|
to.
|
|
+/
|
|
@property void dayOfGregorianCal(int days) @safe 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
|
|
{
|
|
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)));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
void testST(SysTime orig, int day, in SysTime expected, size_t line = __LINE__)
|
|
{
|
|
import std.format : format;
|
|
|
|
orig.dayOfGregorianCal = day;
|
|
if(orig != expected)
|
|
throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
|
|
}
|
|
|
|
//Test A.D.
|
|
testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
|
|
testST(SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)), 1,
|
|
SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
|
|
//Test B.C.
|
|
testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0)));
|
|
testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)), 0,
|
|
SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(1)), 0,
|
|
SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1)));
|
|
testST(SysTime(DateTime(0, 1, 1, 23, 59, 59)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
|
|
|
|
//Test Both.
|
|
testST(SysTime(DateTime(-512, 7, 20, 0, 0, 0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
|
|
testST(SysTime(DateTime(-513, 6, 6, 0, 0, 0), hnsecs(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
|
|
testST(SysTime(DateTime(-511, 5, 7, 23, 59, 59), hnsecs(9_999_999)), 1,
|
|
SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
|
|
|
|
testST(SysTime(DateTime(1607, 4, 8, 0, 0, 0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0)));
|
|
testST(SysTime(DateTime(1500, 3, 9, 23, 59, 59), hnsecs(9_999_999)), 0,
|
|
SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
testST(SysTime(DateTime(999, 2, 10, 23, 59, 59), hnsecs(1)), 0,
|
|
SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1)));
|
|
testST(SysTime(DateTime(2007, 12, 11, 23, 59, 59)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
|
|
|
|
|
|
auto st = SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212));
|
|
|
|
void testST2(int day, in SysTime expected, size_t line = __LINE__)
|
|
{
|
|
import std.format : format;
|
|
|
|
st.dayOfGregorianCal = day;
|
|
if(st != expected)
|
|
throw new AssertError(format("Failed. actual [%s] != expected [%s]", st, expected), __FILE__, line);
|
|
}
|
|
|
|
//Test A.D.
|
|
testST2(1, SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(2, SysTime(DateTime(1, 1, 2, 12, 2, 9), msecs(212)));
|
|
testST2(32, SysTime(DateTime(1, 2, 1, 12, 2, 9), msecs(212)));
|
|
testST2(366, SysTime(DateTime(2, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(731, SysTime(DateTime(3, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(1096, SysTime(DateTime(4, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(1462, SysTime(DateTime(5, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(17_898, SysTime(DateTime(50, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(35_065, SysTime(DateTime(97, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(36_160, SysTime(DateTime(100, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(36_525, SysTime(DateTime(101, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(37_986, SysTime(DateTime(105, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(72_684, SysTime(DateTime(200, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(73_049, SysTime(DateTime(201, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(109_208, SysTime(DateTime(300, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(109_573, SysTime(DateTime(301, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(145_732, SysTime(DateTime(400, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(146_098, SysTime(DateTime(401, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(182_257, SysTime(DateTime(500, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(182_622, SysTime(DateTime(501, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(364_878, SysTime(DateTime(1000, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(365_243, SysTime(DateTime(1001, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(584_023, SysTime(DateTime(1600, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(584_389, SysTime(DateTime(1601, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(693_596, SysTime(DateTime(1900, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(693_961, SysTime(DateTime(1901, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(729_755, SysTime(DateTime(1999, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(730_120, SysTime(DateTime(2000, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(730_486, SysTime(DateTime(2001, 1, 1, 12, 2, 9), msecs(212)));
|
|
|
|
testST2(733_773, SysTime(DateTime(2010, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(733_803, SysTime(DateTime(2010, 1, 31, 12, 2, 9), msecs(212)));
|
|
testST2(733_804, SysTime(DateTime(2010, 2, 1, 12, 2, 9), msecs(212)));
|
|
testST2(733_831, SysTime(DateTime(2010, 2, 28, 12, 2, 9), msecs(212)));
|
|
testST2(733_832, SysTime(DateTime(2010, 3, 1, 12, 2, 9), msecs(212)));
|
|
testST2(733_862, SysTime(DateTime(2010, 3, 31, 12, 2, 9), msecs(212)));
|
|
testST2(733_863, SysTime(DateTime(2010, 4, 1, 12, 2, 9), msecs(212)));
|
|
testST2(733_892, SysTime(DateTime(2010, 4, 30, 12, 2, 9), msecs(212)));
|
|
testST2(733_893, SysTime(DateTime(2010, 5, 1, 12, 2, 9), msecs(212)));
|
|
testST2(733_923, SysTime(DateTime(2010, 5, 31, 12, 2, 9), msecs(212)));
|
|
testST2(733_924, SysTime(DateTime(2010, 6, 1, 12, 2, 9), msecs(212)));
|
|
testST2(733_953, SysTime(DateTime(2010, 6, 30, 12, 2, 9), msecs(212)));
|
|
testST2(733_954, SysTime(DateTime(2010, 7, 1, 12, 2, 9), msecs(212)));
|
|
testST2(733_984, SysTime(DateTime(2010, 7, 31, 12, 2, 9), msecs(212)));
|
|
testST2(733_985, SysTime(DateTime(2010, 8, 1, 12, 2, 9), msecs(212)));
|
|
testST2(734_015, SysTime(DateTime(2010, 8, 31, 12, 2, 9), msecs(212)));
|
|
testST2(734_016, SysTime(DateTime(2010, 9, 1, 12, 2, 9), msecs(212)));
|
|
testST2(734_045, SysTime(DateTime(2010, 9, 30, 12, 2, 9), msecs(212)));
|
|
testST2(734_046, SysTime(DateTime(2010, 10, 1, 12, 2, 9), msecs(212)));
|
|
testST2(734_076, SysTime(DateTime(2010, 10, 31, 12, 2, 9), msecs(212)));
|
|
testST2(734_077, SysTime(DateTime(2010, 11, 1, 12, 2, 9), msecs(212)));
|
|
testST2(734_106, SysTime(DateTime(2010, 11, 30, 12, 2, 9), msecs(212)));
|
|
testST2(734_107, SysTime(DateTime(2010, 12, 1, 12, 2, 9), msecs(212)));
|
|
testST2(734_137, SysTime(DateTime(2010, 12, 31, 12, 2, 9), msecs(212)));
|
|
|
|
testST2(734_534, SysTime(DateTime(2012, 2, 1, 12, 2, 9), msecs(212)));
|
|
testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), msecs(212)));
|
|
testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), msecs(212)));
|
|
testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), msecs(212)));
|
|
|
|
testST2(734_534, SysTime(DateTime(2012, 2, 1, 12, 2, 9), msecs(212)));
|
|
|
|
testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), msecs(212)));
|
|
testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), msecs(212)));
|
|
testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), msecs(212)));
|
|
|
|
//Test B.C.
|
|
testST2(0, SysTime(DateTime(0, 12, 31, 12, 2, 9), msecs(212)));
|
|
testST2(-1, SysTime(DateTime(0, 12, 30, 12, 2, 9), msecs(212)));
|
|
testST2(-30, SysTime(DateTime(0, 12, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-31, SysTime(DateTime(0, 11, 30, 12, 2, 9), msecs(212)));
|
|
|
|
testST2(-366, SysTime(DateTime(-1, 12, 31, 12, 2, 9), msecs(212)));
|
|
testST2(-367, SysTime(DateTime(-1, 12, 30, 12, 2, 9), msecs(212)));
|
|
testST2(-730, SysTime(DateTime(-1, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-731, SysTime(DateTime(-2, 12, 31, 12, 2, 9), msecs(212)));
|
|
testST2(-1095, SysTime(DateTime(-2, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-1096, SysTime(DateTime(-3, 12, 31, 12, 2, 9), msecs(212)));
|
|
testST2(-1460, SysTime(DateTime(-3, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-1461, SysTime(DateTime(-4, 12, 31, 12, 2, 9), msecs(212)));
|
|
testST2(-1826, SysTime(DateTime(-4, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-1827, SysTime(DateTime(-5, 12, 31, 12, 2, 9), msecs(212)));
|
|
testST2(-2191, SysTime(DateTime(-5, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-3652, SysTime(DateTime(-9, 1, 1, 12, 2, 9), msecs(212)));
|
|
|
|
testST2(-18_262, SysTime(DateTime(-49, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-18_627, SysTime(DateTime(-50, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-35_794, SysTime(DateTime(-97, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-36_160, SysTime(DateTime(-99, 12, 31, 12, 2, 9), msecs(212)));
|
|
testST2(-36_524, SysTime(DateTime(-99, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-36_889, SysTime(DateTime(-100, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-37_254, SysTime(DateTime(-101, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-38_715, SysTime(DateTime(-105, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-73_413, SysTime(DateTime(-200, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-73_778, SysTime(DateTime(-201, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-109_937, SysTime(DateTime(-300, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-110_302, SysTime(DateTime(-301, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-146_097, SysTime(DateTime(-400, 12, 31, 12, 2, 9), msecs(212)));
|
|
testST2(-146_462, SysTime(DateTime(-400, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-146_827, SysTime(DateTime(-401, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-182_621, SysTime(DateTime(-499, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-182_986, SysTime(DateTime(-500, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-183_351, SysTime(DateTime(-501, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-365_607, SysTime(DateTime(-1000, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-365_972, SysTime(DateTime(-1001, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-584_387, SysTime(DateTime(-1599, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-584_388, SysTime(DateTime(-1600, 12, 31, 12, 2, 9), msecs(212)));
|
|
testST2(-584_753, SysTime(DateTime(-1600, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-585_118, SysTime(DateTime(-1601, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-694_325, SysTime(DateTime(-1900, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-694_690, SysTime(DateTime(-1901, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-730_484, SysTime(DateTime(-1999, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-730_485, SysTime(DateTime(-2000, 12, 31, 12, 2, 9), msecs(212)));
|
|
testST2(-730_850, SysTime(DateTime(-2000, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-731_215, SysTime(DateTime(-2001, 1, 1, 12, 2, 9), msecs(212)));
|
|
|
|
testST2(-734_502, SysTime(DateTime(-2010, 1, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-734_472, SysTime(DateTime(-2010, 1, 31, 12, 2, 9), msecs(212)));
|
|
testST2(-734_471, SysTime(DateTime(-2010, 2, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-734_444, SysTime(DateTime(-2010, 2, 28, 12, 2, 9), msecs(212)));
|
|
testST2(-734_443, SysTime(DateTime(-2010, 3, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-734_413, SysTime(DateTime(-2010, 3, 31, 12, 2, 9), msecs(212)));
|
|
testST2(-734_412, SysTime(DateTime(-2010, 4, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-734_383, SysTime(DateTime(-2010, 4, 30, 12, 2, 9), msecs(212)));
|
|
testST2(-734_382, SysTime(DateTime(-2010, 5, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-734_352, SysTime(DateTime(-2010, 5, 31, 12, 2, 9), msecs(212)));
|
|
testST2(-734_351, SysTime(DateTime(-2010, 6, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-734_322, SysTime(DateTime(-2010, 6, 30, 12, 2, 9), msecs(212)));
|
|
testST2(-734_321, SysTime(DateTime(-2010, 7, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-734_291, SysTime(DateTime(-2010, 7, 31, 12, 2, 9), msecs(212)));
|
|
testST2(-734_290, SysTime(DateTime(-2010, 8, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-734_260, SysTime(DateTime(-2010, 8, 31, 12, 2, 9), msecs(212)));
|
|
testST2(-734_259, SysTime(DateTime(-2010, 9, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-734_230, SysTime(DateTime(-2010, 9, 30, 12, 2, 9), msecs(212)));
|
|
testST2(-734_229, SysTime(DateTime(-2010, 10, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-734_199, SysTime(DateTime(-2010, 10, 31, 12, 2, 9), msecs(212)));
|
|
testST2(-734_198, SysTime(DateTime(-2010, 11, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-734_169, SysTime(DateTime(-2010, 11, 30, 12, 2, 9), msecs(212)));
|
|
testST2(-734_168, SysTime(DateTime(-2010, 12, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-734_138, SysTime(DateTime(-2010, 12, 31, 12, 2, 9), msecs(212)));
|
|
|
|
testST2(-735_202, SysTime(DateTime(-2012, 2, 1, 12, 2, 9), msecs(212)));
|
|
testST2(-735_175, SysTime(DateTime(-2012, 2, 28, 12, 2, 9), msecs(212)));
|
|
testST2(-735_174, SysTime(DateTime(-2012, 2, 29, 12, 2, 9), msecs(212)));
|
|
testST2(-735_173, SysTime(DateTime(-2012, 3, 1, 12, 2, 9), 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));
|
|
}
|
|
|
|
|
|
/++
|
|
The ISO 8601 week of the year that this $(LREF SysTime) is in.
|
|
|
|
See_Also:
|
|
$(WEB en.wikipedia.org/wiki/ISO_week_date, ISO Week Date).
|
|
+/
|
|
@property ubyte isoWeek() @safe 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));
|
|
}
|
|
|
|
|
|
/++
|
|
$(LREF SysTime) for the last day in the month that this Date is in.
|
|
The time portion of endOfMonth is always 23:59:59.9999999.
|
|
+/
|
|
@property SysTime endOfMonth() @safe 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);
|
|
retval.adjTime = newDaysHNSecs + theTimeHNSecs;
|
|
|
|
return retval;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).endOfMonth ==
|
|
SysTime(DateTime(1999, 1, 31, 23, 59, 59),
|
|
hnsecs(9_999_999)));
|
|
|
|
assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0),
|
|
msecs(24)).endOfMonth ==
|
|
SysTime(DateTime(1999, 2, 28, 23, 59, 59),
|
|
hnsecs(9_999_999)));
|
|
|
|
assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27),
|
|
usecs(5203)).endOfMonth ==
|
|
SysTime(DateTime(2000, 2, 29, 23, 59, 59),
|
|
hnsecs(9_999_999)));
|
|
|
|
assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9),
|
|
hnsecs(12345)).endOfMonth ==
|
|
SysTime(DateTime(2000, 6, 30, 23, 59, 59),
|
|
hnsecs(9_999_999)));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
assert(SysTime(Date(1999, 1, 1)).endOfMonth == SysTime(DateTime(1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(1999, 2, 1)).endOfMonth == SysTime(DateTime(1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(2000, 2, 1)).endOfMonth == SysTime(DateTime(2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(1999, 3, 1)).endOfMonth == SysTime(DateTime(1999, 3, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(1999, 4, 1)).endOfMonth == SysTime(DateTime(1999, 4, 30, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(1999, 5, 1)).endOfMonth == SysTime(DateTime(1999, 5, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(1999, 6, 1)).endOfMonth == SysTime(DateTime(1999, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(1999, 7, 1)).endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(1999, 8, 1)).endOfMonth == SysTime(DateTime(1999, 8, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(1999, 9, 1)).endOfMonth == SysTime(DateTime(1999, 9, 30, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(1999, 10, 1)).endOfMonth == SysTime(DateTime(1999, 10, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(1999, 11, 1)).endOfMonth == SysTime(DateTime(1999, 11, 30, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(1999, 12, 1)).endOfMonth == SysTime(DateTime(1999, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
|
|
//Test B.C.
|
|
assert(SysTime(Date(-1999, 1, 1)).endOfMonth == SysTime(DateTime(-1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(-1999, 2, 1)).endOfMonth == SysTime(DateTime(-1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(-2000, 2, 1)).endOfMonth == SysTime(DateTime(-2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(-1999, 3, 1)).endOfMonth == SysTime(DateTime(-1999, 3, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(-1999, 4, 1)).endOfMonth == SysTime(DateTime(-1999, 4, 30, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(-1999, 5, 1)).endOfMonth == SysTime(DateTime(-1999, 5, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(-1999, 6, 1)).endOfMonth == SysTime(DateTime(-1999, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(-1999, 7, 1)).endOfMonth == SysTime(DateTime(-1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(-1999, 8, 1)).endOfMonth == SysTime(DateTime(-1999, 8, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(-1999, 9, 1)).endOfMonth == SysTime(DateTime(-1999, 9, 30, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(-1999, 10, 1)).endOfMonth ==
|
|
SysTime(DateTime(-1999, 10, 31, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(-1999, 11, 1)).endOfMonth ==
|
|
SysTime(DateTime(-1999, 11, 30, 23, 59, 59), hnsecs(9_999_999)));
|
|
assert(SysTime(Date(-1999, 12, 1)).endOfMonth ==
|
|
SysTime(DateTime(-1999, 12, 31, 23, 59, 59), 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));
|
|
}
|
|
|
|
|
|
/++
|
|
The last day in the month that this $(LREF SysTime) is in.
|
|
+/
|
|
@property ubyte daysInMonth() @safe const nothrow
|
|
{
|
|
return Date(dayOfGregorianCal).daysInMonth;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).daysInMonth == 31);
|
|
assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0)).daysInMonth == 28);
|
|
assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27)).daysInMonth == 29);
|
|
assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9)).daysInMonth == 30);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
assert(SysTime(DateTime(1999, 1, 1, 12, 1, 13)).daysInMonth == 31);
|
|
assert(SysTime(DateTime(1999, 2, 1, 17, 13, 12)).daysInMonth == 28);
|
|
assert(SysTime(DateTime(2000, 2, 1, 13, 2, 12)).daysInMonth == 29);
|
|
assert(SysTime(DateTime(1999, 3, 1, 12, 13, 12)).daysInMonth == 31);
|
|
assert(SysTime(DateTime(1999, 4, 1, 12, 6, 13)).daysInMonth == 30);
|
|
assert(SysTime(DateTime(1999, 5, 1, 15, 13, 12)).daysInMonth == 31);
|
|
assert(SysTime(DateTime(1999, 6, 1, 13, 7, 12)).daysInMonth == 30);
|
|
assert(SysTime(DateTime(1999, 7, 1, 12, 13, 17)).daysInMonth == 31);
|
|
assert(SysTime(DateTime(1999, 8, 1, 12, 3, 13)).daysInMonth == 31);
|
|
assert(SysTime(DateTime(1999, 9, 1, 12, 13, 12)).daysInMonth == 30);
|
|
assert(SysTime(DateTime(1999, 10, 1, 13, 19, 12)).daysInMonth == 31);
|
|
assert(SysTime(DateTime(1999, 11, 1, 12, 13, 17)).daysInMonth == 30);
|
|
assert(SysTime(DateTime(1999, 12, 1, 12, 52, 13)).daysInMonth == 31);
|
|
|
|
//Test B.C.
|
|
assert(SysTime(DateTime(-1999, 1, 1, 12, 1, 13)).daysInMonth == 31);
|
|
assert(SysTime(DateTime(-1999, 2, 1, 7, 13, 12)).daysInMonth == 28);
|
|
assert(SysTime(DateTime(-2000, 2, 1, 13, 2, 12)).daysInMonth == 29);
|
|
assert(SysTime(DateTime(-1999, 3, 1, 12, 13, 12)).daysInMonth == 31);
|
|
assert(SysTime(DateTime(-1999, 4, 1, 12, 6, 13)).daysInMonth == 30);
|
|
assert(SysTime(DateTime(-1999, 5, 1, 5, 13, 12)).daysInMonth == 31);
|
|
assert(SysTime(DateTime(-1999, 6, 1, 13, 7, 12)).daysInMonth == 30);
|
|
assert(SysTime(DateTime(-1999, 7, 1, 12, 13, 17)).daysInMonth == 31);
|
|
assert(SysTime(DateTime(-1999, 8, 1, 12, 3, 13)).daysInMonth == 31);
|
|
assert(SysTime(DateTime(-1999, 9, 1, 12, 13, 12)).daysInMonth == 30);
|
|
assert(SysTime(DateTime(-1999, 10, 1, 13, 19, 12)).daysInMonth == 31);
|
|
assert(SysTime(DateTime(-1999, 11, 1, 12, 13, 17)).daysInMonth == 30);
|
|
assert(SysTime(DateTime(-1999, 12, 1, 12, 52, 13)).daysInMonth == 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.daysInMonth));
|
|
//static assert(__traits(compiles, ist.daysInMonth));
|
|
}
|
|
|
|
|
|
/++
|
|
Whether the current year is a date in A.D.
|
|
+/
|
|
@property bool isAD() @safe const nothrow
|
|
{
|
|
return adjTime >= 0;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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);
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
/++
|
|
The $(WEB en.wikipedia.org/wiki/Julian_day, Julian day)
|
|
for this $(LREF 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, the Julian
|
|
day number would be 2_450_174, so this function returns 2_450_174.
|
|
+/
|
|
@property long julianDay() @safe const nothrow
|
|
{
|
|
immutable jd = dayOfGregorianCal + 1_721_425;
|
|
|
|
return hour < 12 ? jd - 1 : jd;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(SysTime(DateTime(-4713, 11, 24, 0, 0, 0)).julianDay == -1);
|
|
assert(SysTime(DateTime(-4713, 11, 24, 12, 0, 0)).julianDay == 0);
|
|
|
|
assert(SysTime(DateTime(0, 12, 31, 0, 0, 0)).julianDay == 1_721_424);
|
|
assert(SysTime(DateTime(0, 12, 31, 12, 0, 0)).julianDay == 1_721_425);
|
|
|
|
assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).julianDay == 1_721_425);
|
|
assert(SysTime(DateTime(1, 1, 1, 12, 0, 0)).julianDay == 1_721_426);
|
|
|
|
assert(SysTime(DateTime(1582, 10, 15, 0, 0, 0)).julianDay == 2_299_160);
|
|
assert(SysTime(DateTime(1582, 10, 15, 12, 0, 0)).julianDay == 2_299_161);
|
|
|
|
assert(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).julianDay == 2_400_000);
|
|
assert(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).julianDay == 2_400_001);
|
|
|
|
assert(SysTime(DateTime(1982, 1, 4, 0, 0, 0)).julianDay == 2_444_973);
|
|
assert(SysTime(DateTime(1982, 1, 4, 12, 0, 0)).julianDay == 2_444_974);
|
|
|
|
assert(SysTime(DateTime(1996, 3, 31, 0, 0, 0)).julianDay == 2_450_173);
|
|
assert(SysTime(DateTime(1996, 3, 31, 12, 0, 0)).julianDay == 2_450_174);
|
|
|
|
assert(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).julianDay == 2_455_432);
|
|
assert(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 $(WEB en.wikipedia.org/wiki/Julian_day, Julian day) for any time on this date (since, the modified
|
|
Julian day changes at midnight).
|
|
+/
|
|
@property long modJulianDay() @safe const nothrow
|
|
{
|
|
return (dayOfGregorianCal + 1_721_425) - 2_400_001;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).modJulianDay == 0);
|
|
assert(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).modJulianDay == 0);
|
|
|
|
assert(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).modJulianDay == 55_432);
|
|
assert(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 $(LREF Date) equivalent to this $(LREF SysTime).
|
|
+/
|
|
Date opCast(T)() @safe const nothrow
|
|
if(is(Unqual!T == Date))
|
|
{
|
|
return Date(dayOfGregorianCal);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(cast(Date)SysTime(Date(1999, 7, 6)) == Date(1999, 7, 6));
|
|
assert(cast(Date)SysTime(Date(2000, 12, 31)) == Date(2000, 12, 31));
|
|
assert(cast(Date)SysTime(Date(2001, 1, 1)) == Date(2001, 1, 1));
|
|
|
|
assert(cast(Date)SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == Date(1999, 7, 6));
|
|
assert(cast(Date)SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == Date(2000, 12, 31));
|
|
assert(cast(Date)SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == Date(2001, 1, 1));
|
|
|
|
assert(cast(Date)SysTime(Date(-1999, 7, 6)) == Date(-1999, 7, 6));
|
|
assert(cast(Date)SysTime(Date(-2000, 12, 31)) == Date(-2000, 12, 31));
|
|
assert(cast(Date)SysTime(Date(-2001, 1, 1)) == Date(-2001, 1, 1));
|
|
|
|
assert(cast(Date)SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == Date(-1999, 7, 6));
|
|
assert(cast(Date)SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == Date(-2000, 12, 31));
|
|
assert(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 $(LREF DateTime) equivalent to this $(LREF SysTime).
|
|
+/
|
|
DateTime opCast(T)() @safe 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
|
|
{
|
|
assert(cast(DateTime)SysTime(DateTime(1, 1, 6, 7, 12, 22)) == DateTime(1, 1, 6, 7, 12, 22));
|
|
assert(cast(DateTime)SysTime(DateTime(1, 1, 6, 7, 12, 22), msecs(22)) == DateTime(1, 1, 6, 7, 12, 22));
|
|
assert(cast(DateTime)SysTime(Date(1999, 7, 6)) == DateTime(1999, 7, 6, 0, 0, 0));
|
|
assert(cast(DateTime)SysTime(Date(2000, 12, 31)) == DateTime(2000, 12, 31, 0, 0, 0));
|
|
assert(cast(DateTime)SysTime(Date(2001, 1, 1)) == DateTime(2001, 1, 1, 0, 0, 0));
|
|
|
|
assert(cast(DateTime)SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == DateTime(1999, 7, 6, 12, 10, 9));
|
|
assert(cast(DateTime)SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == DateTime(2000, 12, 31, 13, 11, 10));
|
|
assert(cast(DateTime)SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == DateTime(2001, 1, 1, 14, 12, 11));
|
|
|
|
assert(cast(DateTime)SysTime(DateTime(-1, 1, 6, 7, 12, 22)) == DateTime(-1, 1, 6, 7, 12, 22));
|
|
assert(cast(DateTime)SysTime(DateTime(-1, 1, 6, 7, 12, 22), msecs(22)) == DateTime(-1, 1, 6, 7, 12, 22));
|
|
assert(cast(DateTime)SysTime(Date(-1999, 7, 6)) == DateTime(-1999, 7, 6, 0, 0, 0));
|
|
assert(cast(DateTime)SysTime(Date(-2000, 12, 31)) == DateTime(-2000, 12, 31, 0, 0, 0));
|
|
assert(cast(DateTime)SysTime(Date(-2001, 1, 1)) == DateTime(-2001, 1, 1, 0, 0, 0));
|
|
|
|
assert(cast(DateTime)SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == DateTime(-1999, 7, 6, 12, 10, 9));
|
|
assert(cast(DateTime)SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == DateTime(-2000, 12, 31, 13, 11, 10));
|
|
assert(cast(DateTime)SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == DateTime(-2001, 1, 1, 14, 12, 11));
|
|
|
|
assert(cast(DateTime)SysTime(DateTime(2011, 1, 13, 8, 17, 2), msecs(296), LocalTime()) ==
|
|
DateTime(2011, 1, 13, 8, 17, 2));
|
|
|
|
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 $(LREF TimeOfDay) equivalent to this $(LREF SysTime).
|
|
+/
|
|
TimeOfDay opCast(T)() @safe 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
|
|
{
|
|
assert(cast(TimeOfDay)SysTime(Date(1999, 7, 6)) == TimeOfDay(0, 0, 0));
|
|
assert(cast(TimeOfDay)SysTime(Date(2000, 12, 31)) == TimeOfDay(0, 0, 0));
|
|
assert(cast(TimeOfDay)SysTime(Date(2001, 1, 1)) == TimeOfDay(0, 0, 0));
|
|
|
|
assert(cast(TimeOfDay)SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == TimeOfDay(12, 10, 9));
|
|
assert(cast(TimeOfDay)SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == TimeOfDay(13, 11, 10));
|
|
assert(cast(TimeOfDay)SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == TimeOfDay(14, 12, 11));
|
|
|
|
assert(cast(TimeOfDay)SysTime(Date(-1999, 7, 6)) == TimeOfDay(0, 0, 0));
|
|
assert(cast(TimeOfDay)SysTime(Date(-2000, 12, 31)) == TimeOfDay(0, 0, 0));
|
|
assert(cast(TimeOfDay)SysTime(Date(-2001, 1, 1)) == TimeOfDay(0, 0, 0));
|
|
|
|
assert(cast(TimeOfDay)SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == TimeOfDay(12, 10, 9));
|
|
assert(cast(TimeOfDay)SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == TimeOfDay(13, 11, 10));
|
|
assert(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)() @safe const pure nothrow
|
|
if(is(Unqual!T == SysTime))
|
|
{
|
|
return SysTime(_stdTime, _timezone);
|
|
}
|
|
|
|
|
|
/++
|
|
Converts this $(LREF 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 $(LREF SysTime)'s time zone is $(LREF LocalTime), then TZ is empty.
|
|
If its time zone is $(D 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.
|
|
+/
|
|
string toISOString() @safe const nothrow
|
|
{
|
|
import std.format : format;
|
|
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 = fracSecsToISOString(cast(int)hnsecs);
|
|
|
|
if(_timezone is LocalTime())
|
|
return dateTime.toISOString() ~ fracSecsToISOString(cast(int)hnsecs);
|
|
|
|
if(_timezone is UTC())
|
|
return dateTime.toISOString() ~ fracSecsToISOString(cast(int)hnsecs) ~ "Z";
|
|
|
|
immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
|
|
|
|
return format("%s%s%s",
|
|
dateTime.toISOString(),
|
|
fracSecsToISOString(cast(int)hnsecs),
|
|
SimpleTimeZone.toISOString(utcOffset));
|
|
}
|
|
catch(Exception e)
|
|
assert(0, "format() threw.");
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOString() ==
|
|
"20100704T070612");
|
|
|
|
assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0),
|
|
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),
|
|
hnsecs(520_920)).toISOString() ==
|
|
"-00040105T000002.052092");
|
|
}
|
|
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
assert(SysTime(DateTime.init, UTC()).toISOString() == "00010101T000000Z");
|
|
assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toISOString() == "00010101T000000.0000001Z");
|
|
|
|
assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOString() == "00091204T000000");
|
|
assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOString() == "00991204T050612");
|
|
assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOString() == "09991204T134459");
|
|
assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOString() == "99990704T235959");
|
|
assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOString() == "+100001020T010101");
|
|
|
|
assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toISOString() == "00091204T000000.042");
|
|
assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toISOString() == "00991204T050612.1");
|
|
assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toISOString() == "09991204T134459.04502");
|
|
assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOString() == "99990704T235959.0000012");
|
|
assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOString() == "+100001020T010101.050789");
|
|
|
|
assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
|
|
new immutable SimpleTimeZone(dur!"minutes"(-360))).toISOString() ==
|
|
"20121221T121212-06:00");
|
|
|
|
assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
|
|
new immutable SimpleTimeZone(dur!"minutes"(420))).toISOString() ==
|
|
"20121221T121212+07:00");
|
|
|
|
//Test B.C.
|
|
assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toISOString() ==
|
|
"00001231T235959.9999999Z");
|
|
assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toISOString() == "00001231T235959.0000001Z");
|
|
assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOString() == "00001231T235959Z");
|
|
|
|
assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOString() == "00001204T001204");
|
|
assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOString() == "-00091204T000000");
|
|
assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOString() == "-00991204T050612");
|
|
assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOString() == "-09991204T134459");
|
|
assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOString() == "-99990704T235959");
|
|
assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOString() == "-100001020T010101");
|
|
|
|
assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toISOString() == "00001204T000000.007");
|
|
assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toISOString() == "-00091204T000000.042");
|
|
assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toISOString() == "-00991204T050612.1");
|
|
assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toISOString() == "-09991204T134459.04502");
|
|
assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOString() == "-99990704T235959.0000012");
|
|
assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), 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));
|
|
}
|
|
|
|
|
|
|
|
/++
|
|
Converts this $(LREF SysTime) to a string with the format
|
|
YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
|
|
is the 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 $(LREF SysTime)'s time zone is $(LREF LocalTime), then TZ is empty. If
|
|
its time zone is $(D 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.
|
|
+/
|
|
string toISOExtString() @safe const nothrow
|
|
{
|
|
import std.format : format;
|
|
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 = fracSecsToISOString(cast(int)hnsecs);
|
|
|
|
if(_timezone is LocalTime())
|
|
return dateTime.toISOExtString() ~ fracSecsToISOString(cast(int)hnsecs);
|
|
|
|
if(_timezone is UTC())
|
|
return dateTime.toISOExtString() ~ fracSecsToISOString(cast(int)hnsecs) ~ "Z";
|
|
|
|
immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
|
|
|
|
return format("%s%s%s",
|
|
dateTime.toISOExtString(),
|
|
fracSecsToISOString(cast(int)hnsecs),
|
|
SimpleTimeZone.toISOString(utcOffset));
|
|
}
|
|
catch(Exception e)
|
|
assert(0, "format() threw.");
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOExtString() ==
|
|
"2010-07-04T07:06:12");
|
|
|
|
assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0),
|
|
msecs(24)).toISOExtString() ==
|
|
"1998-12-25T02:15:00.024");
|
|
|
|
assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOExtString() ==
|
|
"0000-01-05T23:09:59");
|
|
|
|
assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2),
|
|
hnsecs(520_920)).toISOExtString() ==
|
|
"-0004-01-05T00:00:02.052092");
|
|
}
|
|
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
assert(SysTime(DateTime.init, UTC()).toISOExtString() == "0001-01-01T00:00:00Z");
|
|
assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toISOExtString() ==
|
|
"0001-01-01T00:00:00.0000001Z");
|
|
|
|
assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOExtString() == "0009-12-04T00:00:00");
|
|
assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOExtString() == "0099-12-04T05:06:12");
|
|
assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOExtString() == "0999-12-04T13:44:59");
|
|
assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOExtString() == "9999-07-04T23:59:59");
|
|
assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOExtString() == "+10000-10-20T01:01:01");
|
|
|
|
assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toISOExtString() == "0009-12-04T00:00:00.042");
|
|
assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toISOExtString() == "0099-12-04T05:06:12.1");
|
|
assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toISOExtString() == "0999-12-04T13:44:59.04502");
|
|
assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOExtString() == "9999-07-04T23:59:59.0000012");
|
|
assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOExtString() ==
|
|
"+10000-10-20T01:01:01.050789");
|
|
|
|
assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
|
|
new immutable SimpleTimeZone(dur!"minutes"(-360))).toISOExtString() ==
|
|
"2012-12-21T12:12:12-06:00");
|
|
|
|
assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
|
|
new immutable SimpleTimeZone(dur!"minutes"(420))).toISOExtString() ==
|
|
"2012-12-21T12:12:12+07:00");
|
|
|
|
//Test B.C.
|
|
assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toISOExtString() ==
|
|
"0000-12-31T23:59:59.9999999Z");
|
|
assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toISOExtString() ==
|
|
"0000-12-31T23:59:59.0000001Z");
|
|
assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOExtString() == "0000-12-31T23:59:59Z");
|
|
|
|
assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOExtString() == "0000-12-04T00:12:04");
|
|
assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOExtString() == "-0009-12-04T00:00:00");
|
|
assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOExtString() == "-0099-12-04T05:06:12");
|
|
assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOExtString() == "-0999-12-04T13:44:59");
|
|
assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOExtString() == "-9999-07-04T23:59:59");
|
|
assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOExtString() == "-10000-10-20T01:01:01");
|
|
|
|
assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toISOExtString() == "0000-12-04T00:00:00.007");
|
|
assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toISOExtString() == "-0009-12-04T00:00:00.042");
|
|
assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toISOExtString() == "-0099-12-04T05:06:12.1");
|
|
assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toISOExtString() ==
|
|
"-0999-12-04T13:44:59.04502");
|
|
assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOExtString() ==
|
|
"-9999-07-04T23:59:59.0000012");
|
|
assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOExtString() ==
|
|
"-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));
|
|
}
|
|
|
|
/++
|
|
Converts this $(LREF SysTime) to a string with the format
|
|
YYYY-Mon-DD HH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
|
|
is the 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 $(LREF SysTime)'s time zone is $(LREF LocalTime), then TZ is empty. If
|
|
its time zone is $(D 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.
|
|
+/
|
|
string toSimpleString() @safe const nothrow
|
|
{
|
|
import std.format : format;
|
|
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 = fracSecsToISOString(cast(int)hnsecs);
|
|
|
|
if(_timezone is LocalTime())
|
|
return dateTime.toSimpleString() ~ fracSecsToISOString(cast(int)hnsecs);
|
|
|
|
if(_timezone is UTC())
|
|
return dateTime.toSimpleString() ~ fracSecsToISOString(cast(int)hnsecs) ~ "Z";
|
|
|
|
immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
|
|
|
|
return format("%s%s%s",
|
|
dateTime.toSimpleString(),
|
|
fracSecsToISOString(cast(int)hnsecs),
|
|
SimpleTimeZone.toISOString(utcOffset));
|
|
}
|
|
catch(Exception e)
|
|
assert(0, "format() threw.");
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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),
|
|
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),
|
|
hnsecs(520_920)).toSimpleString() ==
|
|
"-0004-Jan-05 00:00:02.052092");
|
|
}
|
|
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
assert(SysTime(DateTime.init, UTC()).toString() == "0001-Jan-01 00:00:00Z");
|
|
assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toString() == "0001-Jan-01 00:00:00.0000001Z");
|
|
|
|
assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toSimpleString() == "0009-Dec-04 00:00:00");
|
|
assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toSimpleString() == "0099-Dec-04 05:06:12");
|
|
assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toSimpleString() == "0999-Dec-04 13:44:59");
|
|
assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toSimpleString() == "9999-Jul-04 23:59:59");
|
|
assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toSimpleString() == "+10000-Oct-20 01:01:01");
|
|
|
|
assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toSimpleString() == "0009-Dec-04 00:00:00.042");
|
|
assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toSimpleString() == "0099-Dec-04 05:06:12.1");
|
|
assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toSimpleString() ==
|
|
"0999-Dec-04 13:44:59.04502");
|
|
assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toSimpleString() ==
|
|
"9999-Jul-04 23:59:59.0000012");
|
|
assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toSimpleString() ==
|
|
"+10000-Oct-20 01:01:01.050789");
|
|
|
|
assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
|
|
new immutable SimpleTimeZone(dur!"minutes"(-360))).toSimpleString() ==
|
|
"2012-Dec-21 12:12:12-06:00");
|
|
|
|
assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
|
|
new immutable SimpleTimeZone(dur!"minutes"(420))).toSimpleString() ==
|
|
"2012-Dec-21 12:12:12+07:00");
|
|
|
|
//Test B.C.
|
|
assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toSimpleString() ==
|
|
"0000-Dec-31 23:59:59.9999999Z");
|
|
assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toSimpleString() ==
|
|
"0000-Dec-31 23:59:59.0000001Z");
|
|
assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toSimpleString() == "0000-Dec-31 23:59:59Z");
|
|
|
|
assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toSimpleString() == "0000-Dec-04 00:12:04");
|
|
assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toSimpleString() == "-0009-Dec-04 00:00:00");
|
|
assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toSimpleString() == "-0099-Dec-04 05:06:12");
|
|
assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toSimpleString() == "-0999-Dec-04 13:44:59");
|
|
assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toSimpleString() == "-9999-Jul-04 23:59:59");
|
|
assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toSimpleString() == "-10000-Oct-20 01:01:01");
|
|
|
|
assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toSimpleString() == "0000-Dec-04 00:00:00.007");
|
|
assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toSimpleString() == "-0009-Dec-04 00:00:00.042");
|
|
assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toSimpleString() == "-0099-Dec-04 05:06:12.1");
|
|
assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toSimpleString() ==
|
|
"-0999-Dec-04 13:44:59.04502");
|
|
assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toSimpleString() ==
|
|
"-9999-Jul-04 23:59:59.0000012");
|
|
assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), 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));
|
|
}
|
|
|
|
|
|
/++
|
|
Converts this $(LREF SysTime) to a string.
|
|
+/
|
|
string toString() @safe 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 $(LREF SysTime) from a string with the format
|
|
YYYYMMDDTHHMMSS.FFFFFFFTZ (where F is fractional seconds is the time
|
|
zone). Whitespace is stripped from the given string.
|
|
|
|
The exact format is exactly as described in $(D 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 $(LREF LocalTime) is used. If
|
|
the time zone is "Z", then $(D UTC) is used. Otherwise, a
|
|
$(LREF SimpleTimeZone) which corresponds to the given offset from UTC is
|
|
used. To get the returned $(LREF SysTime) to be a particular time
|
|
zone, pass in that time zone and the $(LREF 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:
|
|
$(LREF DateTimeException) if the given string is not in the ISO format
|
|
or if the resulting $(LREF SysTime) would not be valid.
|
|
+/
|
|
static SysTime fromISOString(S)(in S isoString, immutable TimeZone tz = null) @safe
|
|
if(isSomeString!S)
|
|
{
|
|
import std.string : strip;
|
|
import std.conv : to;
|
|
import std.algorithm : startsWith, find;
|
|
import std.format : format;
|
|
|
|
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 = fracSecsFromISOString(fracSecStr);
|
|
Rebindable!(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);
|
|
|
|
if(tz !is null)
|
|
retval.timezone = tz;
|
|
|
|
return retval;
|
|
}
|
|
catch(DateTimeException dte)
|
|
throw new DateTimeException(format("Invalid ISO String: %s", isoString));
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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), msecs(7)));
|
|
assert(SysTime.fromISOString("00000105T230959.00002") ==
|
|
SysTime(DateTime(0, 1, 5, 23, 9, 59), 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 immutable SimpleTimeZone(dur!"hours"(-8))));
|
|
assert(SysTime.fromISOString("20100704T070612+8:00") ==
|
|
SysTime(DateTime(2010, 7, 4, 7, 6, 12),
|
|
new immutable SimpleTimeZone(dur!"hours"(8))));
|
|
}
|
|
|
|
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"));
|
|
|
|
assert(SysTime.fromISOString("20101222T172201") == SysTime(DateTime(2010, 12, 22, 17, 22, 01)));
|
|
assert(SysTime.fromISOString("19990706T123033") == SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
assert(SysTime.fromISOString("-19990706T123033") == SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
|
|
assert(SysTime.fromISOString("+019990706T123033") == SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
assert(SysTime.fromISOString("19990706T123033 ") == SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
assert(SysTime.fromISOString(" 19990706T123033") == SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
assert(SysTime.fromISOString(" 19990706T123033 ") == SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
|
|
assert(SysTime.fromISOString("19070707T121212.0") == SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
|
|
assert(SysTime.fromISOString("19070707T121212.0000000") == SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
|
|
assert(SysTime.fromISOString("19070707T121212.0000001") ==
|
|
SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1)));
|
|
assert(SysTime.fromISOString("19070707T121212.000001") ==
|
|
SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
|
|
assert(SysTime.fromISOString("19070707T121212.0000010") ==
|
|
SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
|
|
assert(SysTime.fromISOString("19070707T121212.001") == SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
|
|
assert(SysTime.fromISOString("19070707T121212.0010000") ==
|
|
SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
|
|
|
|
assert(SysTime.fromISOString("20101222T172201Z") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC()));
|
|
assert(SysTime.fromISOString("20101222T172201-1:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(-60))));
|
|
assert(SysTime.fromISOString("20101222T172201-1") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(-60))));
|
|
assert(SysTime.fromISOString("20101222T172201-1:30") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(-90))));
|
|
assert(SysTime.fromISOString("20101222T172201-8:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(-480))));
|
|
assert(SysTime.fromISOString("20101222T172201+1:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(60))));
|
|
assert(SysTime.fromISOString("20101222T172201+1") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(60))));
|
|
assert(SysTime.fromISOString("20101222T172201+1:30") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(90))));
|
|
assert(SysTime.fromISOString("20101222T172201+8:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(480))));
|
|
|
|
assert(SysTime.fromISOString("20101103T065106.57159Z") ==
|
|
SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
|
|
|
|
assert(SysTime.fromISOString("20101222T172201.23412Z") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_341_200), UTC()));
|
|
assert(SysTime.fromISOString("20101222T172201.23112-1:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200),
|
|
new immutable SimpleTimeZone(dur!"minutes"(-60))));
|
|
assert(SysTime.fromISOString("20101222T172201.45-1") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000),
|
|
new immutable SimpleTimeZone(dur!"minutes"(-60))));
|
|
assert(SysTime.fromISOString("20101222T172201.1-1:30") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000),
|
|
new immutable SimpleTimeZone(dur!"minutes"(-90))));
|
|
assert(SysTime.fromISOString("20101222T172201.55-8:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000),
|
|
new immutable SimpleTimeZone(dur!"minutes"(-480))));
|
|
assert(SysTime.fromISOString("20101222T172201.1234567+1:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567),
|
|
new immutable SimpleTimeZone(dur!"minutes"(60))));
|
|
assert(SysTime.fromISOString("20101222T172201.0+1") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01),
|
|
new immutable SimpleTimeZone(dur!"minutes"(60))));
|
|
assert(SysTime.fromISOString("20101222T172201.0000000+1:30") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01),
|
|
new immutable SimpleTimeZone(dur!"minutes"(90))));
|
|
assert(SysTime.fromISOString("20101222T172201.45+8:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000),
|
|
new immutable SimpleTimeZone(dur!"minutes"(480))));
|
|
}
|
|
|
|
|
|
/++
|
|
Creates a $(LREF SysTime) from a string with the format
|
|
YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ (where F is fractional seconds is the
|
|
time zone). Whitespace is stripped from the given string.
|
|
|
|
The exact format is exactly as described in $(D toISOExtString)
|
|
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 $(LREF LocalTime) is used. If
|
|
the time zone is "Z", then $(D UTC) is used. Otherwise, a
|
|
$(LREF SimpleTimeZone) which corresponds to the given offset from UTC is
|
|
used. To get the returned $(LREF SysTime) to be a particular time
|
|
zone, pass in that time zone and the $(LREF 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:
|
|
isoExtString = 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:
|
|
$(LREF DateTimeException) if the given string is not in the ISO format
|
|
or if the resulting $(LREF SysTime) would not be valid.
|
|
+/
|
|
static SysTime fromISOExtString(S)(in S isoExtString, immutable TimeZone tz = null) @safe
|
|
if(isSomeString!(S))
|
|
{
|
|
import std.string : strip;
|
|
import std.conv : to;
|
|
import std.algorithm : countUntil, find;
|
|
import std.format : format;
|
|
|
|
auto dstr = to!dstring(strip(isoExtString));
|
|
|
|
auto tIndex = dstr.countUntil('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.fromISOExtString(dateTimeStr);
|
|
auto fracSec = fracSecsFromISOString(fracSecStr);
|
|
Rebindable!(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);
|
|
|
|
if(tz !is null)
|
|
retval.timezone = tz;
|
|
|
|
return retval;
|
|
}
|
|
catch(DateTimeException dte)
|
|
throw new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString));
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(SysTime.fromISOExtString("2010-07-04T07:06:12") ==
|
|
SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
|
|
assert(SysTime.fromISOExtString("1998-12-25T02:15:00.007") ==
|
|
SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
|
|
assert(SysTime.fromISOExtString("0000-01-05T23:09:59.00002") ==
|
|
SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
|
|
assert(SysTime.fromISOExtString("-0004-01-05T00:00:02") ==
|
|
SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
|
|
assert(SysTime.fromISOExtString(" 2010-07-04T07:06:12 ") ==
|
|
SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
|
|
|
|
assert(SysTime.fromISOExtString("2010-07-04T07:06:12Z") ==
|
|
SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
|
|
assert(SysTime.fromISOExtString("2010-07-04T07:06:12-8:00") ==
|
|
SysTime(DateTime(2010, 7, 4, 7, 6, 12),
|
|
new immutable SimpleTimeZone(dur!"hours"(-8))));
|
|
assert(SysTime.fromISOExtString("2010-07-04T07:06:12+8:00") ==
|
|
SysTime(DateTime(2010, 7, 4, 7, 6, 12),
|
|
new immutable SimpleTimeZone(dur!"hours"(8))));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString(""));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("20100704000000"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("20100704 000000"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("20100704t000000"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("20100704T000000."));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("20100704T000000.0"));
|
|
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-07:0400:00:00"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-07-04 00:00:00"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-07-04 00:00:00"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-07-04t00:00:00"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-07-04T00:00:00."));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-07-04T00:00:00.A"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-07-04T00:00:00.Z"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-07-04T00:00:00.00000000"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-07-04T00:00:00.00000000"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-07-04T00:00:00+"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-07-04T00:00:00-"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-07-04T00:00:00:"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-07-04T00:00:00-:"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-07-04T00:00:00+:"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-07-04T00:00:00-1:"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-07-04T00:00:00+1:"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-07-04T00:00:00+1:0"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-07-04T00:00:00-24.00"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-07-04T00:00:00+24.00"));
|
|
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-Jul-0400:00:00"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-Jul-04t00:00:00"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-Jul-04 00:00:00."));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-Jul-04 00:00:00.0"));
|
|
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("20101222T172201"));
|
|
assertThrown!DateTimeException(SysTime.fromISOExtString("2010-Dec-22 17:22:01"));
|
|
|
|
assert(SysTime.fromISOExtString("2010-12-22T17:22:01") == SysTime(DateTime(2010, 12, 22, 17, 22, 01)));
|
|
assert(SysTime.fromISOExtString("1999-07-06T12:30:33") == SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
assert(SysTime.fromISOExtString("-1999-07-06T12:30:33") == SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
|
|
assert(SysTime.fromISOExtString("+01999-07-06T12:30:33") == SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
assert(SysTime.fromISOExtString("1999-07-06T12:30:33 ") == SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
assert(SysTime.fromISOExtString(" 1999-07-06T12:30:33") == SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
assert(SysTime.fromISOExtString(" 1999-07-06T12:30:33 ") == SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
|
|
assert(SysTime.fromISOExtString("1907-07-07T12:12:12.0") == SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
|
|
assert(SysTime.fromISOExtString("1907-07-07T12:12:12.0000000") == SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
|
|
assert(SysTime.fromISOExtString("1907-07-07T12:12:12.0000001") ==
|
|
SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1)));
|
|
assert(SysTime.fromISOExtString("1907-07-07T12:12:12.000001") ==
|
|
SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
|
|
assert(SysTime.fromISOExtString("1907-07-07T12:12:12.0000010") ==
|
|
SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
|
|
assert(SysTime.fromISOExtString("1907-07-07T12:12:12.001") ==
|
|
SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
|
|
assert(SysTime.fromISOExtString("1907-07-07T12:12:12.0010000") ==
|
|
SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
|
|
|
|
assert(SysTime.fromISOExtString("2010-12-22T17:22:01Z") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC()));
|
|
assert(SysTime.fromISOExtString("2010-12-22T17:22:01-1:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(-60))));
|
|
assert(SysTime.fromISOExtString("2010-12-22T17:22:01-1") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(-60))));
|
|
assert(SysTime.fromISOExtString("2010-12-22T17:22:01-1:30") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(-90))));
|
|
assert(SysTime.fromISOExtString("2010-12-22T17:22:01-8:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(-480))));
|
|
assert(SysTime.fromISOExtString("2010-12-22T17:22:01+1:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(60))));
|
|
assert(SysTime.fromISOExtString("2010-12-22T17:22:01+1") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(60))));
|
|
assert(SysTime.fromISOExtString("2010-12-22T17:22:01+1:30") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(90))));
|
|
assert(SysTime.fromISOExtString("2010-12-22T17:22:01+8:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(480))));
|
|
|
|
assert(SysTime.fromISOExtString("2010-11-03T06:51:06.57159Z") ==
|
|
SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
|
|
|
|
assert(SysTime.fromISOExtString("2010-12-22T17:22:01.23412Z") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_341_200), UTC()));
|
|
assert(SysTime.fromISOExtString("2010-12-22T17:22:01.23112-1:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200),
|
|
new immutable SimpleTimeZone(dur!"minutes"(-60))));
|
|
assert(SysTime.fromISOExtString("2010-12-22T17:22:01.45-1") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000),
|
|
new immutable SimpleTimeZone(dur!"minutes"(-60))));
|
|
assert(SysTime.fromISOExtString("2010-12-22T17:22:01.1-1:30") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000),
|
|
new immutable SimpleTimeZone(dur!"minutes"(-90))));
|
|
assert(SysTime.fromISOExtString("2010-12-22T17:22:01.55-8:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000),
|
|
new immutable SimpleTimeZone(dur!"minutes"(-480))));
|
|
assert(SysTime.fromISOExtString("2010-12-22T17:22:01.1234567+1:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567),
|
|
new immutable SimpleTimeZone(dur!"minutes"(60))));
|
|
assert(SysTime.fromISOExtString("2010-12-22T17:22:01.0+1") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01),
|
|
new immutable SimpleTimeZone(dur!"minutes"(60))));
|
|
assert(SysTime.fromISOExtString("2010-12-22T17:22:01.0000000+1:30") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01),
|
|
new immutable SimpleTimeZone(dur!"minutes"(90))));
|
|
assert(SysTime.fromISOExtString("2010-12-22T17:22:01.45+8:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000),
|
|
new immutable SimpleTimeZone(dur!"minutes"(480))));
|
|
}
|
|
|
|
|
|
/++
|
|
Creates a $(LREF SysTime) from a string with the format
|
|
YYYY-MM-DD HH:MM:SS.FFFFFFFTZ (where F is fractional seconds is the
|
|
time zone). Whitespace is stripped from the given string.
|
|
|
|
The exact format is exactly as described in $(D 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 $(LREF LocalTime) is used. If
|
|
the time zone is "Z", then $(D UTC) is used. Otherwise, a
|
|
$(LREF SimpleTimeZone) which corresponds to the given offset from UTC is
|
|
used. To get the returned $(LREF SysTime) to be a particular time
|
|
zone, pass in that time zone and the $(LREF 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
|
|
$(D toSimpleString) formats dates and times.
|
|
tz = The time zone to convert the given time to (no
|
|
conversion occurs if null).
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given string is not in the ISO format
|
|
or if the resulting $(LREF SysTime) would not be valid.
|
|
+/
|
|
static SysTime fromSimpleString(S)(in S simpleString, immutable TimeZone tz = null) @safe
|
|
if(isSomeString!(S))
|
|
{
|
|
import std.string : strip;
|
|
import std.conv : to;
|
|
import std.algorithm : countUntil, find;
|
|
import std.format : format;
|
|
|
|
auto dstr = to!dstring(strip(simpleString));
|
|
|
|
auto spaceIndex = dstr.countUntil(' ');
|
|
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 = fracSecsFromISOString(fracSecStr);
|
|
Rebindable!(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);
|
|
|
|
if(tz !is null)
|
|
retval.timezone = tz;
|
|
|
|
return retval;
|
|
}
|
|
catch(DateTimeException dte)
|
|
throw new DateTimeException(format("Invalid Simple String: %s", simpleString));
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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), msecs(7)));
|
|
assert(SysTime.fromSimpleString("0000-Jan-05 23:09:59.00002") ==
|
|
SysTime(DateTime(0, 1, 5, 23, 9, 59), 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 immutable SimpleTimeZone(dur!"hours"(-8))));
|
|
assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12+8:00") ==
|
|
SysTime(DateTime(2010, 7, 4, 7, 6, 12),
|
|
new immutable SimpleTimeZone(dur!"hours"(8))));
|
|
}
|
|
|
|
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"));
|
|
|
|
assert(SysTime.fromSimpleString("2010-Dec-22 17:22:01") == SysTime(DateTime(2010, 12, 22, 17, 22, 01)));
|
|
assert(SysTime.fromSimpleString("1999-Jul-06 12:30:33") == SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
assert(SysTime.fromSimpleString("-1999-Jul-06 12:30:33") == SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
|
|
assert(SysTime.fromSimpleString("+01999-Jul-06 12:30:33") == SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
assert(SysTime.fromSimpleString("1999-Jul-06 12:30:33 ") == SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
assert(SysTime.fromSimpleString(" 1999-Jul-06 12:30:33") == SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
assert(SysTime.fromSimpleString(" 1999-Jul-06 12:30:33 ") == SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
|
|
|
|
assert(SysTime.fromSimpleString("1907-Jul-07 12:12:12.0") == SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
|
|
assert(SysTime.fromSimpleString("1907-Jul-07 12:12:12.0000000") == SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
|
|
assert(SysTime.fromSimpleString("1907-Jul-07 12:12:12.0000001") ==
|
|
SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1)));
|
|
assert(SysTime.fromSimpleString("1907-Jul-07 12:12:12.000001") ==
|
|
SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
|
|
assert(SysTime.fromSimpleString("1907-Jul-07 12:12:12.0000010") ==
|
|
SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
|
|
assert(SysTime.fromSimpleString("1907-Jul-07 12:12:12.001") ==
|
|
SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
|
|
assert(SysTime.fromSimpleString("1907-Jul-07 12:12:12.0010000") ==
|
|
SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
|
|
|
|
assert(SysTime.fromSimpleString("2010-Dec-22 17:22:01Z") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC()));
|
|
assert(SysTime.fromSimpleString("2010-Dec-22 17:22:01-1:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(-60))));
|
|
assert(SysTime.fromSimpleString("2010-Dec-22 17:22:01-1") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(-60))));
|
|
assert(SysTime.fromSimpleString("2010-Dec-22 17:22:01-1:30") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(-90))));
|
|
assert(SysTime.fromSimpleString("2010-Dec-22 17:22:01-8:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(-480))));
|
|
assert(SysTime.fromSimpleString("2010-Dec-22 17:22:01+1:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(60))));
|
|
assert(SysTime.fromSimpleString("2010-Dec-22 17:22:01+1") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(60))));
|
|
assert(SysTime.fromSimpleString("2010-Dec-22 17:22:01+1:30") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(90))));
|
|
assert(SysTime.fromSimpleString("2010-Dec-22 17:22:01+8:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), new immutable SimpleTimeZone(dur!"minutes"(480))));
|
|
|
|
assert(SysTime.fromSimpleString("2010-Nov-03 06:51:06.57159Z") ==
|
|
SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
|
|
|
|
assert(SysTime.fromSimpleString("2010-Dec-22 17:22:01.23412Z") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_341_200), UTC()));
|
|
assert(SysTime.fromSimpleString("2010-Dec-22 17:22:01.23112-1:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200),
|
|
new immutable SimpleTimeZone(dur!"minutes"(-60))));
|
|
assert(SysTime.fromSimpleString("2010-Dec-22 17:22:01.45-1") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000),
|
|
new immutable SimpleTimeZone(dur!"minutes"(-60))));
|
|
assert(SysTime.fromSimpleString("2010-Dec-22 17:22:01.1-1:30") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000),
|
|
new immutable SimpleTimeZone(dur!"minutes"(-90))));
|
|
assert(SysTime.fromSimpleString("2010-Dec-22 17:22:01.55-8:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000),
|
|
new immutable SimpleTimeZone(dur!"minutes"(-480))));
|
|
assert(SysTime.fromSimpleString("2010-Dec-22 17:22:01.1234567+1:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567),
|
|
new immutable SimpleTimeZone(dur!"minutes"(60))));
|
|
assert(SysTime.fromSimpleString("2010-Dec-22 17:22:01.0+1") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01),
|
|
new immutable SimpleTimeZone(dur!"minutes"(60))));
|
|
assert(SysTime.fromSimpleString("2010-Dec-22 17:22:01.0000000+1:30") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01),
|
|
new immutable SimpleTimeZone(dur!"minutes"(90))));
|
|
assert(SysTime.fromSimpleString("2010-Dec-22 17:22:01.45+8:00") ==
|
|
SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000),
|
|
new immutable SimpleTimeZone(dur!"minutes"(480))));
|
|
}
|
|
|
|
|
|
/++
|
|
Returns the $(LREF SysTime) farthest in the past which is representable
|
|
by $(LREF SysTime).
|
|
|
|
The $(LREF SysTime) which is returned is in UTC.
|
|
+/
|
|
@property static SysTime min() @safe pure nothrow
|
|
{
|
|
return SysTime(long.min, UTC());
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(SysTime.min.year < 0);
|
|
assert(SysTime.min < SysTime.max);
|
|
}
|
|
|
|
|
|
/++
|
|
Returns the $(LREF SysTime) farthest in the future which is representable
|
|
by $(LREF SysTime).
|
|
|
|
The $(LREF SysTime) which is returned is in UTC.
|
|
+/
|
|
@property static SysTime max() @safe pure nothrow
|
|
{
|
|
return SysTime(long.max, UTC());
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(SysTime.max.year > 0);
|
|
assert(SysTime.max > SysTime.min);
|
|
}
|
|
|
|
|
|
private:
|
|
|
|
/+
|
|
Returns $(D stdTime) converted to $(LREF SysTime)'s time zone.
|
|
+/
|
|
@property long adjTime() @safe const nothrow
|
|
{
|
|
return _timezone.utcToTZ(_stdTime);
|
|
}
|
|
|
|
|
|
/+
|
|
Converts the given hnsecs from $(LREF SysTime)'s time zone to std time.
|
|
+/
|
|
@property void adjTime(long adjTime) @safe nothrow
|
|
{
|
|
_stdTime = _timezone.tzToUTC(adjTime);
|
|
}
|
|
|
|
|
|
//Commented out due to bug http://d.puremagic.com/issues/show_bug.cgi?id=5058
|
|
/+
|
|
invariant()
|
|
{
|
|
assert(_timezone !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;
|
|
Rebindable!(immutable TimeZone) _timezone;
|
|
}
|
|
|
|
|
|
/++
|
|
Represents a date in the
|
|
$(WEB en.wikipedia.org/wiki/Proleptic_Gregorian_calendar, 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 $(D Date) is
|
|
optimized for calendar-based operations.
|
|
|
|
$(D Date) uses the Proleptic Gregorian Calendar, so it assumes the Gregorian
|
|
leap year calculations for its entire length. As per
|
|
$(WEB en.wikipedia.org/wiki/ISO_8601, ISO 8601), it treats 1 B.C. as
|
|
year 0, i.e. 1 B.C. is 0, 2 B.C. is -1, etc. Use $(LREF yearBC) to use 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:
|
|
$(LREF DateTimeException) if the resulting $(LREF 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) @safe 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
|
|
{
|
|
assert(Date(1, 1, 1) == Date.init);
|
|
|
|
static void testDate(in Date date, int year, int month, int day)
|
|
{
|
|
assert(date._year == year);
|
|
assert(date._month == month);
|
|
assert(date._day == day);
|
|
}
|
|
|
|
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
|
|
$(LREF Date) will be for.
|
|
+/
|
|
this(int day) @safe pure nothrow
|
|
{
|
|
if(day > 0)
|
|
{
|
|
int years = (day / daysIn400Years) * 400 + 1;
|
|
day %= daysIn400Years;
|
|
|
|
{
|
|
immutable tempYears = day / daysIn100Years;
|
|
|
|
if(tempYears == 4)
|
|
{
|
|
years += 300;
|
|
day -= daysIn100Years * 3;
|
|
}
|
|
else
|
|
{
|
|
years += tempYears * 100;
|
|
day %= daysIn100Years;
|
|
}
|
|
}
|
|
|
|
years += (day / daysIn4Years) * 4;
|
|
day %= daysIn4Years;
|
|
|
|
{
|
|
immutable tempYears = day / daysInYear;
|
|
|
|
if(tempYears == 4)
|
|
{
|
|
years += 3;
|
|
day -= daysInYear * 3;
|
|
}
|
|
else
|
|
{
|
|
years += tempYears;
|
|
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;
|
|
|
|
{
|
|
immutable tempYears = day / daysIn100Years;
|
|
|
|
if(tempYears == -4)
|
|
{
|
|
years -= 300;
|
|
day += daysIn100Years * 3;
|
|
}
|
|
else
|
|
{
|
|
years += tempYears * 100;
|
|
day %= daysIn100Years;
|
|
}
|
|
}
|
|
|
|
years += (day / daysIn4Years) * 4;
|
|
day %= daysIn4Years;
|
|
|
|
{
|
|
immutable tempYears = day / daysInYear;
|
|
|
|
if(tempYears == -4)
|
|
{
|
|
years -= 3;
|
|
day += daysInYear * 3;
|
|
}
|
|
else
|
|
{
|
|
years += tempYears;
|
|
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
|
|
{
|
|
import std.range;
|
|
|
|
//Test A.D.
|
|
foreach(gd; chain(testGregDaysBC, testGregDaysAD))
|
|
assert(Date(gd.day) == gd.date);
|
|
}
|
|
|
|
|
|
/++
|
|
Compares this $(LREF Date) with the given $(LREF Date).
|
|
|
|
Returns:
|
|
$(BOOKTABLE,
|
|
$(TR $(TD this < rhs) $(TD < 0))
|
|
$(TR $(TD this == rhs) $(TD 0))
|
|
$(TR $(TD this > rhs) $(TD > 0))
|
|
)
|
|
+/
|
|
int opCmp(in Date rhs) @safe 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.
|
|
assert(Date(1, 1, 1).opCmp(Date.init) == 0);
|
|
|
|
assert(Date(1999, 1, 1).opCmp(Date(1999, 1, 1)) == 0);
|
|
assert(Date(1, 7, 1).opCmp(Date(1, 7, 1)) == 0);
|
|
assert(Date(1, 1, 6).opCmp(Date(1, 1, 6)) == 0);
|
|
|
|
assert(Date(1999, 7, 1).opCmp(Date(1999, 7, 1)) == 0);
|
|
assert(Date(1999, 7, 6).opCmp(Date(1999, 7, 6)) == 0);
|
|
|
|
assert(Date(1, 7, 6).opCmp(Date(1, 7, 6)) == 0);
|
|
|
|
assert(Date(1999, 7, 6).opCmp(Date(2000, 7, 6)) < 0);
|
|
assert(Date(2000, 7, 6).opCmp(Date(1999, 7, 6)) > 0);
|
|
assert(Date(1999, 7, 6).opCmp(Date(1999, 8, 6)) < 0);
|
|
assert(Date(1999, 8, 6).opCmp(Date(1999, 7, 6)) > 0);
|
|
assert(Date(1999, 7, 6).opCmp(Date(1999, 7, 7)) < 0);
|
|
assert(Date(1999, 7, 7).opCmp(Date(1999, 7, 6)) > 0);
|
|
|
|
assert(Date(1999, 8, 7).opCmp(Date(2000, 7, 6)) < 0);
|
|
assert(Date(2000, 8, 6).opCmp(Date(1999, 7, 7)) > 0);
|
|
assert(Date(1999, 7, 7).opCmp(Date(2000, 7, 6)) < 0);
|
|
assert(Date(2000, 7, 6).opCmp(Date(1999, 7, 7)) > 0);
|
|
assert(Date(1999, 7, 7).opCmp(Date(1999, 8, 6)) < 0);
|
|
assert(Date(1999, 8, 6).opCmp(Date(1999, 7, 7)) > 0);
|
|
|
|
//Test B.C.
|
|
assert(Date(0, 1, 1).opCmp(Date(0, 1, 1)) == 0);
|
|
assert(Date(-1, 1, 1).opCmp(Date(-1, 1, 1)) == 0);
|
|
assert(Date(-1, 7, 1).opCmp(Date(-1, 7, 1)) == 0);
|
|
assert(Date(-1, 1, 6).opCmp(Date(-1, 1, 6)) == 0);
|
|
|
|
assert(Date(-1999, 7, 1).opCmp(Date(-1999, 7, 1)) == 0);
|
|
assert(Date(-1999, 7, 6).opCmp(Date(-1999, 7, 6)) == 0);
|
|
|
|
assert(Date(-1, 7, 6).opCmp(Date(-1, 7, 6)) == 0);
|
|
|
|
assert(Date(-2000, 7, 6).opCmp(Date(-1999, 7, 6)) < 0);
|
|
assert(Date(-1999, 7, 6).opCmp(Date(-2000, 7, 6)) > 0);
|
|
assert(Date(-1999, 7, 6).opCmp(Date(-1999, 8, 6)) < 0);
|
|
assert(Date(-1999, 8, 6).opCmp(Date(-1999, 7, 6)) > 0);
|
|
assert(Date(-1999, 7, 6).opCmp(Date(-1999, 7, 7)) < 0);
|
|
assert(Date(-1999, 7, 7).opCmp(Date(-1999, 7, 6)) > 0);
|
|
|
|
assert(Date(-2000, 8, 6).opCmp(Date(-1999, 7, 7)) < 0);
|
|
assert(Date(-1999, 8, 7).opCmp(Date(-2000, 7, 6)) > 0);
|
|
assert(Date(-2000, 7, 6).opCmp(Date(-1999, 7, 7)) < 0);
|
|
assert(Date(-1999, 7, 7).opCmp(Date(-2000, 7, 6)) > 0);
|
|
assert(Date(-1999, 7, 7).opCmp(Date(-1999, 8, 6)) < 0);
|
|
assert(Date(-1999, 8, 6).opCmp(Date(-1999, 7, 7)) > 0);
|
|
|
|
//Test Both
|
|
assert(Date(-1999, 7, 6).opCmp(Date(1999, 7, 6)) < 0);
|
|
assert(Date(1999, 7, 6).opCmp(Date(-1999, 7, 6)) > 0);
|
|
|
|
assert(Date(-1999, 8, 6).opCmp(Date(1999, 7, 6)) < 0);
|
|
assert(Date(1999, 7, 6).opCmp(Date(-1999, 8, 6)) > 0);
|
|
|
|
assert(Date(-1999, 7, 7).opCmp(Date(1999, 7, 6)) < 0);
|
|
assert(Date(1999, 7, 6).opCmp(Date(-1999, 7, 7)) > 0);
|
|
|
|
assert(Date(-1999, 8, 7).opCmp(Date(1999, 7, 6)) < 0);
|
|
assert(Date(1999, 7, 6).opCmp(Date(-1999, 8, 7)) > 0);
|
|
|
|
assert(Date(-1999, 8, 6).opCmp(Date(1999, 6, 6)) < 0);
|
|
assert(Date(1999, 6, 8).opCmp(Date(-1999, 7, 6)) > 0);
|
|
|
|
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.
|
|
+/
|
|
@property short year() @safe const pure nothrow
|
|
{
|
|
return _year;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(Date(1999, 7, 6).year == 1999);
|
|
assert(Date(2010, 10, 4).year == 2010);
|
|
assert(Date(-7, 4, 5).year == -7);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(Date.init.year == 1);
|
|
assert(Date(1999, 7, 6).year == 1999);
|
|
assert(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));
|
|
}
|
|
|
|
/++
|
|
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:
|
|
$(LREF DateTimeException) if the new year is not a leap year and the
|
|
resulting date would be on February 29th.
|
|
+/
|
|
@property void year(int year) @safe pure
|
|
{
|
|
enforceValid!"days"(year, _month, _day);
|
|
_year = cast(short)year;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(Date(1999, 7, 6).year == 1999);
|
|
assert(Date(2010, 10, 4).year == 2010);
|
|
assert(Date(-7, 4, 5).year == -7);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
static void testDateInvalid(Date date, int year)
|
|
{
|
|
date.year = year;
|
|
}
|
|
|
|
static void testDate(Date date, int year, in Date expected)
|
|
{
|
|
date.year = year;
|
|
assert(date == expected);
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
/++
|
|
Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if $(D isAD) is true.
|
|
+/
|
|
@property ushort yearBC() @safe const pure
|
|
{
|
|
import std.format : format;
|
|
|
|
if(isAD)
|
|
throw new DateTimeException(format("Year %s is A.D.", _year));
|
|
return cast(ushort)((_year * -1) + 1);
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(Date(0, 1, 1).yearBC == 1);
|
|
assert(Date(-1, 1, 1).yearBC == 2);
|
|
assert(Date(-100, 1, 1).yearBC == 101);
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
/++
|
|
Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
|
|
|
|
Params:
|
|
year = The year B.C. to set this $(LREF Date)'s year to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if a non-positive value is given.
|
|
+/
|
|
@property void yearBC(int year) @safe pure
|
|
{
|
|
if(year <= 0)
|
|
throw new DateTimeException("The given year is not a year B.C.");
|
|
|
|
_year = cast(short)((year - 1) * -1);
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
auto date = Date(2010, 1, 1);
|
|
date.yearBC = 1;
|
|
assert(date == Date(0, 1, 1));
|
|
|
|
date.yearBC = 10;
|
|
assert(date == Date(-9, 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));
|
|
}
|
|
|
|
|
|
/++
|
|
Month of a Gregorian Year.
|
|
+/
|
|
@property Month month() @safe const pure nothrow
|
|
{
|
|
return _month;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(Date(1999, 7, 6).month == 7);
|
|
assert(Date(2010, 10, 4).month == 10);
|
|
assert(Date(-7, 4, 5).month == 4);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(Date.init.month == 1);
|
|
assert(Date(1999, 7, 6).month == 7);
|
|
assert(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));
|
|
}
|
|
|
|
/++
|
|
Month of a Gregorian Year.
|
|
|
|
Params:
|
|
month = The month to set this $(LREF Date)'s month to.
|
|
|
|
Throws:
|
|
$(LREF 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) @safe 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)
|
|
{
|
|
date.month = month;
|
|
assert(expected != Date.init);
|
|
assert(date == expected);
|
|
}
|
|
|
|
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.
|
|
+/
|
|
@property ubyte day() @safe const pure nothrow
|
|
{
|
|
return _day;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(Date(1999, 7, 6).day == 6);
|
|
assert(Date(2010, 10, 4).day == 4);
|
|
assert(Date(-7, 4, 5).day == 5);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.range;
|
|
import std.format : format;
|
|
|
|
static void test(Date date, int expected)
|
|
{
|
|
assert(date.day == expected,
|
|
format("Value given: %s", date));
|
|
}
|
|
|
|
foreach(year; chain(testYearsBC, testYearsAD))
|
|
{
|
|
foreach(md; testMonthDays)
|
|
test(Date(year, md.month, md.day), md.day);
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
/++
|
|
Day of a Gregorian Month.
|
|
|
|
Params:
|
|
day = The day of the month to set this $(LREF Date)'s day to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given day is not a valid day of the
|
|
current month.
|
|
+/
|
|
@property void day(int day) @safe 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;
|
|
assert(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;
|
|
assert(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 or months to this $(LREF Date). 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 day 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
|
|
$(LREF Date).
|
|
allowOverflow = Whether the day should be allowed to overflow,
|
|
causing the month to increment.
|
|
+/
|
|
ref Date add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow
|
|
if(units == "years")
|
|
{
|
|
immutable newYear = _year + value;
|
|
|
|
_year += value;
|
|
|
|
if(_month == Month.feb && _day == 29 && !yearIsLeapYear(_year))
|
|
{
|
|
if(allowOverflow == AllowDayOverflow.yes)
|
|
{
|
|
_month = Month.mar;
|
|
_day = 1;
|
|
}
|
|
else
|
|
_day = 28;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
auto d1 = Date(2010, 1, 1);
|
|
d1.add!"months"(11);
|
|
assert(d1 == Date(2010, 12, 1));
|
|
|
|
auto d2 = Date(2010, 1, 1);
|
|
d2.add!"months"(-11);
|
|
assert(d2 == Date(2009, 2, 1));
|
|
|
|
auto d3 = Date(2000, 2, 29);
|
|
d3.add!"years"(1);
|
|
assert(d3 == Date(2001, 3, 1));
|
|
|
|
auto d4 = Date(2000, 2, 29);
|
|
d4.add!"years"(1, AllowDayOverflow.no);
|
|
assert(d4 == Date(2001, 2, 28));
|
|
}
|
|
|
|
//Test add!"years"() with AllowDayOverlow.yes
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
date.add!"years"(7);
|
|
assert(date == Date(2006, 7, 6));
|
|
date.add!"years"(-9);
|
|
assert(date == Date(1997, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 2, 28);
|
|
date.add!"years"(1);
|
|
assert(date == Date(2000, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(2000, 2, 29);
|
|
date.add!"years"(-1);
|
|
assert(date == Date(1999, 3, 1));
|
|
}
|
|
|
|
//Test B.C.
|
|
{
|
|
auto date = Date(-1999, 7, 6);
|
|
date.add!"years"(-7);
|
|
assert(date == Date(-2006, 7, 6));
|
|
date.add!"years"(9);
|
|
assert(date == Date(-1997, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 2, 28);
|
|
date.add!"years"(-1);
|
|
assert(date == Date(-2000, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-2000, 2, 29);
|
|
date.add!"years"(1);
|
|
assert(date == Date(-1999, 3, 1));
|
|
}
|
|
|
|
//Test Both
|
|
{
|
|
auto date = Date(4, 7, 6);
|
|
date.add!"years"(-5);
|
|
assert(date == Date(-1, 7, 6));
|
|
date.add!"years"(5);
|
|
assert(date == Date(4, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-4, 7, 6);
|
|
date.add!"years"(5);
|
|
assert(date == Date(1, 7, 6));
|
|
date.add!"years"(-5);
|
|
assert(date == Date(-4, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(4, 7, 6);
|
|
date.add!"years"(-8);
|
|
assert(date == Date(-4, 7, 6));
|
|
date.add!"years"(8);
|
|
assert(date == Date(4, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-4, 7, 6);
|
|
date.add!"years"(8);
|
|
assert(date == Date(4, 7, 6));
|
|
date.add!"years"(-8);
|
|
assert(date == Date(-4, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-4, 2, 29);
|
|
date.add!"years"(5);
|
|
assert(date == Date(1, 3, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(4, 2, 29);
|
|
date.add!"years"(-5);
|
|
assert(date == Date(-1, 3, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(4, 2, 29);
|
|
date.add!"years"(-5).add!"years"(7);
|
|
assert(date == Date(6, 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)));
|
|
}
|
|
|
|
//Test add!"years"() with AllowDayOverlow.no
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
date.add!"years"(7, AllowDayOverflow.no);
|
|
assert(date == Date(2006, 7, 6));
|
|
date.add!"years"(-9, AllowDayOverflow.no);
|
|
assert(date == Date(1997, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 2, 28);
|
|
date.add!"years"(1, AllowDayOverflow.no);
|
|
assert(date == Date(2000, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(2000, 2, 29);
|
|
date.add!"years"(-1, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 2, 28));
|
|
}
|
|
|
|
//Test B.C.
|
|
{
|
|
auto date = Date(-1999, 7, 6);
|
|
date.add!"years"(-7, AllowDayOverflow.no);
|
|
assert(date == Date(-2006, 7, 6));
|
|
date.add!"years"(9, AllowDayOverflow.no);
|
|
assert(date == Date(-1997, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 2, 28);
|
|
date.add!"years"(-1, AllowDayOverflow.no);
|
|
assert(date == Date(-2000, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-2000, 2, 29);
|
|
date.add!"years"(1, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 2, 28));
|
|
}
|
|
|
|
//Test Both
|
|
{
|
|
auto date = Date(4, 7, 6);
|
|
date.add!"years"(-5, AllowDayOverflow.no);
|
|
assert(date == Date(-1, 7, 6));
|
|
date.add!"years"(5, AllowDayOverflow.no);
|
|
assert(date == Date(4, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-4, 7, 6);
|
|
date.add!"years"(5, AllowDayOverflow.no);
|
|
assert(date == Date(1, 7, 6));
|
|
date.add!"years"(-5, AllowDayOverflow.no);
|
|
assert(date == Date(-4, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(4, 7, 6);
|
|
date.add!"years"(-8, AllowDayOverflow.no);
|
|
assert(date == Date(-4, 7, 6));
|
|
date.add!"years"(8, AllowDayOverflow.no);
|
|
assert(date == Date(4, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-4, 7, 6);
|
|
date.add!"years"(8, AllowDayOverflow.no);
|
|
assert(date == Date(4, 7, 6));
|
|
date.add!"years"(-8, AllowDayOverflow.no);
|
|
assert(date == Date(-4, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-4, 2, 29);
|
|
date.add!"years"(5, AllowDayOverflow.no);
|
|
assert(date == Date(1, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(4, 2, 29);
|
|
date.add!"years"(-5, AllowDayOverflow.no);
|
|
assert(date == Date(-1, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(4, 2, 29);
|
|
date.add!"years"(-5, AllowDayOverflow.no).add!"years"(7, AllowDayOverflow.no);
|
|
assert(date == Date(6, 2, 28));
|
|
}
|
|
}
|
|
|
|
|
|
//Shares documentation with "years" version.
|
|
ref Date add(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe 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;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
//Test add!"months"() with AllowDayOverlow.yes
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
date.add!"months"(3);
|
|
assert(date == Date(1999, 10, 6));
|
|
date.add!"months"(-4);
|
|
assert(date == Date(1999, 6, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
date.add!"months"(6);
|
|
assert(date == Date(2000, 1, 6));
|
|
date.add!"months"(-6);
|
|
assert(date == Date(1999, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
date.add!"months"(27);
|
|
assert(date == Date(2001, 10, 6));
|
|
date.add!"months"(-28);
|
|
assert(date == Date(1999, 6, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 5, 31);
|
|
date.add!"months"(1);
|
|
assert(date == Date(1999, 7, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 5, 31);
|
|
date.add!"months"(-1);
|
|
assert(date == Date(1999, 5, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 2, 28);
|
|
date.add!"months"(12);
|
|
assert(date == Date(2000, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(2000, 2, 29);
|
|
date.add!"months"(12);
|
|
assert(date == Date(2001, 3, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 7, 31);
|
|
date.add!"months"(1);
|
|
assert(date == Date(1999, 8, 31));
|
|
date.add!"months"(1);
|
|
assert(date == Date(1999, 10, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1998, 8, 31);
|
|
date.add!"months"(13);
|
|
assert(date == Date(1999, 10, 1));
|
|
date.add!"months"(-13);
|
|
assert(date == Date(1998, 9, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1997, 12, 31);
|
|
date.add!"months"(13);
|
|
assert(date == Date(1999, 1, 31));
|
|
date.add!"months"(-13);
|
|
assert(date == Date(1997, 12, 31));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1997, 12, 31);
|
|
date.add!"months"(14);
|
|
assert(date == Date(1999, 3, 3));
|
|
date.add!"months"(-14);
|
|
assert(date == Date(1998, 1, 3));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1998, 12, 31);
|
|
date.add!"months"(14);
|
|
assert(date == Date(2000, 3, 2));
|
|
date.add!"months"(-14);
|
|
assert(date == Date(1999, 1, 2));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 12, 31);
|
|
date.add!"months"(14);
|
|
assert(date == Date(2001, 3, 3));
|
|
date.add!"months"(-14);
|
|
assert(date == Date(2000, 1, 3));
|
|
}
|
|
|
|
//Test B.C.
|
|
{
|
|
auto date = Date(-1999, 7, 6);
|
|
date.add!"months"(3);
|
|
assert(date == Date(-1999, 10, 6));
|
|
date.add!"months"(-4);
|
|
assert(date == Date(-1999, 6, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 7, 6);
|
|
date.add!"months"(6);
|
|
assert(date == Date(-1998, 1, 6));
|
|
date.add!"months"(-6);
|
|
assert(date == Date(-1999, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 7, 6);
|
|
date.add!"months"(-27);
|
|
assert(date == Date(-2001, 4, 6));
|
|
date.add!"months"(28);
|
|
assert(date == Date(-1999, 8, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 5, 31);
|
|
date.add!"months"(1);
|
|
assert(date == Date(-1999, 7, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 5, 31);
|
|
date.add!"months"(-1);
|
|
assert(date == Date(-1999, 5, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 2, 28);
|
|
date.add!"months"(-12);
|
|
assert(date == Date(-2000, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-2000, 2, 29);
|
|
date.add!"months"(-12);
|
|
assert(date == Date(-2001, 3, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 7, 31);
|
|
date.add!"months"(1);
|
|
assert(date == Date(-1999, 8, 31));
|
|
date.add!"months"(1);
|
|
assert(date == Date(-1999, 10, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1998, 8, 31);
|
|
date.add!"months"(13);
|
|
assert(date == Date(-1997, 10, 1));
|
|
date.add!"months"(-13);
|
|
assert(date == Date(-1998, 9, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1997, 12, 31);
|
|
date.add!"months"(13);
|
|
assert(date == Date(-1995, 1, 31));
|
|
date.add!"months"(-13);
|
|
assert(date == Date(-1997, 12, 31));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1997, 12, 31);
|
|
date.add!"months"(14);
|
|
assert(date == Date(-1995, 3, 3));
|
|
date.add!"months"(-14);
|
|
assert(date == Date(-1996, 1, 3));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-2002, 12, 31);
|
|
date.add!"months"(14);
|
|
assert(date == Date(-2000, 3, 2));
|
|
date.add!"months"(-14);
|
|
assert(date == Date(-2001, 1, 2));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-2001, 12, 31);
|
|
date.add!"months"(14);
|
|
assert(date == Date(-1999, 3, 3));
|
|
date.add!"months"(-14);
|
|
assert(date == Date(-2000, 1, 3));
|
|
}
|
|
|
|
//Test Both
|
|
{
|
|
auto date = Date(1, 1, 1);
|
|
date.add!"months"(-1);
|
|
assert(date == Date(0, 12, 1));
|
|
date.add!"months"(1);
|
|
assert(date == Date(1, 1, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(4, 1, 1);
|
|
date.add!"months"(-48);
|
|
assert(date == Date(0, 1, 1));
|
|
date.add!"months"(48);
|
|
assert(date == Date(4, 1, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(4, 3, 31);
|
|
date.add!"months"(-49);
|
|
assert(date == Date(0, 3, 2));
|
|
date.add!"months"(49);
|
|
assert(date == Date(4, 4, 2));
|
|
}
|
|
|
|
{
|
|
auto date = Date(4, 3, 31);
|
|
date.add!"months"(-85);
|
|
assert(date == Date(-3, 3, 3));
|
|
date.add!"months"(85);
|
|
assert(date == Date(4, 4, 3));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-3, 3, 31);
|
|
date.add!"months"(85).add!"months"(-83);
|
|
assert(date == Date(-3, 6, 1));
|
|
}
|
|
|
|
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)));
|
|
}
|
|
|
|
//Test add!"months"() with AllowDayOverlow.no
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
date.add!"months"(3, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 10, 6));
|
|
date.add!"months"(-4, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 6, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
date.add!"months"(6, AllowDayOverflow.no);
|
|
assert(date == Date(2000, 1, 6));
|
|
date.add!"months"(-6, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
date.add!"months"(27, AllowDayOverflow.no);
|
|
assert(date == Date(2001, 10, 6));
|
|
date.add!"months"(-28, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 6, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 5, 31);
|
|
date.add!"months"(1, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 6, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 5, 31);
|
|
date.add!"months"(-1, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 4, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 2, 28);
|
|
date.add!"months"(12, AllowDayOverflow.no);
|
|
assert(date == Date(2000, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(2000, 2, 29);
|
|
date.add!"months"(12, AllowDayOverflow.no);
|
|
assert(date == Date(2001, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 7, 31);
|
|
date.add!"months"(1, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 8, 31));
|
|
date.add!"months"(1, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 9, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1998, 8, 31);
|
|
date.add!"months"(13, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 9, 30));
|
|
date.add!"months"(-13, AllowDayOverflow.no);
|
|
assert(date == Date(1998, 8, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1997, 12, 31);
|
|
date.add!"months"(13, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 1, 31));
|
|
date.add!"months"(-13, AllowDayOverflow.no);
|
|
assert(date == Date(1997, 12, 31));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1997, 12, 31);
|
|
date.add!"months"(14, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 2, 28));
|
|
date.add!"months"(-14, AllowDayOverflow.no);
|
|
assert(date == Date(1997, 12, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1998, 12, 31);
|
|
date.add!"months"(14, AllowDayOverflow.no);
|
|
assert(date == Date(2000, 2, 29));
|
|
date.add!"months"(-14, AllowDayOverflow.no);
|
|
assert(date == Date(1998, 12, 29));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 12, 31);
|
|
date.add!"months"(14, AllowDayOverflow.no);
|
|
assert(date == Date(2001, 2, 28));
|
|
date.add!"months"(-14, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 12, 28));
|
|
}
|
|
|
|
//Test B.C.
|
|
{
|
|
auto date = Date(-1999, 7, 6);
|
|
date.add!"months"(3, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 10, 6));
|
|
date.add!"months"(-4, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 6, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 7, 6);
|
|
date.add!"months"(6, AllowDayOverflow.no);
|
|
assert(date == Date(-1998, 1, 6));
|
|
date.add!"months"(-6, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 7, 6);
|
|
date.add!"months"(-27, AllowDayOverflow.no);
|
|
assert(date == Date(-2001, 4, 6));
|
|
date.add!"months"(28, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 8, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 5, 31);
|
|
date.add!"months"(1, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 6, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 5, 31);
|
|
date.add!"months"(-1, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 4, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 2, 28);
|
|
date.add!"months"(-12, AllowDayOverflow.no);
|
|
assert(date == Date(-2000, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-2000, 2, 29);
|
|
date.add!"months"(-12, AllowDayOverflow.no);
|
|
assert(date == Date(-2001, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 7, 31);
|
|
date.add!"months"(1, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 8, 31));
|
|
date.add!"months"(1, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 9, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1998, 8, 31);
|
|
date.add!"months"(13, AllowDayOverflow.no);
|
|
assert(date == Date(-1997, 9, 30));
|
|
date.add!"months"(-13, AllowDayOverflow.no);
|
|
assert(date == Date(-1998, 8, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1997, 12, 31);
|
|
date.add!"months"(13, AllowDayOverflow.no);
|
|
assert(date == Date(-1995, 1, 31));
|
|
date.add!"months"(-13, AllowDayOverflow.no);
|
|
assert(date == Date(-1997, 12, 31));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1997, 12, 31);
|
|
date.add!"months"(14, AllowDayOverflow.no);
|
|
assert(date == Date(-1995, 2, 28));
|
|
date.add!"months"(-14, AllowDayOverflow.no);
|
|
assert(date == Date(-1997, 12, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-2002, 12, 31);
|
|
date.add!"months"(14, AllowDayOverflow.no);
|
|
assert(date == Date(-2000, 2, 29));
|
|
date.add!"months"(-14, AllowDayOverflow.no);
|
|
assert(date == Date(-2002, 12, 29));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-2001, 12, 31);
|
|
date.add!"months"(14, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 2, 28));
|
|
date.add!"months"(-14, AllowDayOverflow.no);
|
|
assert(date == Date(-2001, 12, 28));
|
|
}
|
|
|
|
//Test Both
|
|
{
|
|
auto date = Date(1, 1, 1);
|
|
date.add!"months"(-1, AllowDayOverflow.no);
|
|
assert(date == Date(0, 12, 1));
|
|
date.add!"months"(1, AllowDayOverflow.no);
|
|
assert(date == Date(1, 1, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(4, 1, 1);
|
|
date.add!"months"(-48, AllowDayOverflow.no);
|
|
assert(date == Date(0, 1, 1));
|
|
date.add!"months"(48, AllowDayOverflow.no);
|
|
assert(date == Date(4, 1, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(4, 3, 31);
|
|
date.add!"months"(-49, AllowDayOverflow.no);
|
|
assert(date == Date(0, 2, 29));
|
|
date.add!"months"(49, AllowDayOverflow.no);
|
|
assert(date == Date(4, 3, 29));
|
|
}
|
|
|
|
{
|
|
auto date = Date(4, 3, 31);
|
|
date.add!"months"(-85, AllowDayOverflow.no);
|
|
assert(date == Date(-3, 2, 28));
|
|
date.add!"months"(85, AllowDayOverflow.no);
|
|
assert(date == Date(4, 3, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-3, 3, 31);
|
|
date.add!"months"(85, AllowDayOverflow.no).add!"months"(-83, AllowDayOverflow.no);
|
|
assert(date == Date(-3, 5, 30));
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
Adds the given number of years or months to this $(LREF Date). A negative
|
|
number will subtract.
|
|
|
|
The difference between rolling and adding is that rolling does not
|
|
affect larger units. Rolling a $(LREF Date) 12 months gets
|
|
the exact same $(LREF Date). However, the days can still be affected due to
|
|
the differing number of days in each month.
|
|
|
|
Because there are no units larger than years, there is no difference
|
|
between adding and rolling years.
|
|
|
|
Params:
|
|
units = The type of units to add ("years" or "months").
|
|
value = The number of months or years to add to this
|
|
$(LREF Date).
|
|
allowOverflow = Whether the day should be allowed to overflow,
|
|
causing the month to increment.
|
|
+/
|
|
ref Date roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow
|
|
if(units == "years")
|
|
{
|
|
return add!"years"(value, allowOverflow);
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
auto d1 = Date(2010, 1, 1);
|
|
d1.roll!"months"(1);
|
|
assert(d1 == Date(2010, 2, 1));
|
|
|
|
auto d2 = Date(2010, 1, 1);
|
|
d2.roll!"months"(-1);
|
|
assert(d2 == Date(2010, 12, 1));
|
|
|
|
auto d3 = Date(1999, 1, 29);
|
|
d3.roll!"months"(1);
|
|
assert(d3 == Date(1999, 3, 1));
|
|
|
|
auto d4 = Date(1999, 1, 29);
|
|
d4.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(d4 == Date(1999, 2, 28));
|
|
|
|
auto d5 = Date(2000, 2, 29);
|
|
d5.roll!"years"(1);
|
|
assert(d5 == Date(2001, 3, 1));
|
|
|
|
auto d6 = Date(2000, 2, 29);
|
|
d6.roll!"years"(1, AllowDayOverflow.no);
|
|
assert(d6 == Date(2001, 2, 28));
|
|
}
|
|
|
|
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)));
|
|
}
|
|
|
|
|
|
//Shares documentation with "years" version.
|
|
ref Date roll(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe 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;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
//Test roll!"months"() with AllowDayOverlow.yes
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
date.roll!"months"(3);
|
|
assert(date == Date(1999, 10, 6));
|
|
date.roll!"months"(-4);
|
|
assert(date == Date(1999, 6, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
date.roll!"months"(6);
|
|
assert(date == Date(1999, 1, 6));
|
|
date.roll!"months"(-6);
|
|
assert(date == Date(1999, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
date.roll!"months"(27);
|
|
assert(date == Date(1999, 10, 6));
|
|
date.roll!"months"(-28);
|
|
assert(date == Date(1999, 6, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 5, 31);
|
|
date.roll!"months"(1);
|
|
assert(date == Date(1999, 7, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 5, 31);
|
|
date.roll!"months"(-1);
|
|
assert(date == Date(1999, 5, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 2, 28);
|
|
date.roll!"months"(12);
|
|
assert(date == Date(1999, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(2000, 2, 29);
|
|
date.roll!"months"(12);
|
|
assert(date == Date(2000, 2, 29));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 7, 31);
|
|
date.roll!"months"(1);
|
|
assert(date == Date(1999, 8, 31));
|
|
date.roll!"months"(1);
|
|
assert(date == Date(1999, 10, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1998, 8, 31);
|
|
date.roll!"months"(13);
|
|
assert(date == Date(1998, 10, 1));
|
|
date.roll!"months"(-13);
|
|
assert(date == Date(1998, 9, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1997, 12, 31);
|
|
date.roll!"months"(13);
|
|
assert(date == Date(1997, 1, 31));
|
|
date.roll!"months"(-13);
|
|
assert(date == Date(1997, 12, 31));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1997, 12, 31);
|
|
date.roll!"months"(14);
|
|
assert(date == Date(1997, 3, 3));
|
|
date.roll!"months"(-14);
|
|
assert(date == Date(1997, 1, 3));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1998, 12, 31);
|
|
date.roll!"months"(14);
|
|
assert(date == Date(1998, 3, 3));
|
|
date.roll!"months"(-14);
|
|
assert(date == Date(1998, 1, 3));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 12, 31);
|
|
date.roll!"months"(14);
|
|
assert(date == Date(1999, 3, 3));
|
|
date.roll!"months"(-14);
|
|
assert(date == Date(1999, 1, 3));
|
|
}
|
|
|
|
//Test B.C.
|
|
{
|
|
auto date = Date(-1999, 7, 6);
|
|
date.roll!"months"(3);
|
|
assert(date == Date(-1999, 10, 6));
|
|
date.roll!"months"(-4);
|
|
assert(date == Date(-1999, 6, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 7, 6);
|
|
date.roll!"months"(6);
|
|
assert(date == Date(-1999, 1, 6));
|
|
date.roll!"months"(-6);
|
|
assert(date == Date(-1999, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 7, 6);
|
|
date.roll!"months"(-27);
|
|
assert(date == Date(-1999, 4, 6));
|
|
date.roll!"months"(28);
|
|
assert(date == Date(-1999, 8, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 5, 31);
|
|
date.roll!"months"(1);
|
|
assert(date == Date(-1999, 7, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 5, 31);
|
|
date.roll!"months"(-1);
|
|
assert(date == Date(-1999, 5, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 2, 28);
|
|
date.roll!"months"(-12);
|
|
assert(date == Date(-1999, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-2000, 2, 29);
|
|
date.roll!"months"(-12);
|
|
assert(date == Date(-2000, 2, 29));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 7, 31);
|
|
date.roll!"months"(1);
|
|
assert(date == Date(-1999, 8, 31));
|
|
date.roll!"months"(1);
|
|
assert(date == Date(-1999, 10, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1998, 8, 31);
|
|
date.roll!"months"(13);
|
|
assert(date == Date(-1998, 10, 1));
|
|
date.roll!"months"(-13);
|
|
assert(date == Date(-1998, 9, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1997, 12, 31);
|
|
date.roll!"months"(13);
|
|
assert(date == Date(-1997, 1, 31));
|
|
date.roll!"months"(-13);
|
|
assert(date == Date(-1997, 12, 31));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1997, 12, 31);
|
|
date.roll!"months"(14);
|
|
assert(date == Date(-1997, 3, 3));
|
|
date.roll!"months"(-14);
|
|
assert(date == Date(-1997, 1, 3));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-2002, 12, 31);
|
|
date.roll!"months"(14);
|
|
assert(date == Date(-2002, 3, 3));
|
|
date.roll!"months"(-14);
|
|
assert(date == Date(-2002, 1, 3));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-2001, 12, 31);
|
|
date.roll!"months"(14);
|
|
assert(date == Date(-2001, 3, 3));
|
|
date.roll!"months"(-14);
|
|
assert(date == Date(-2001, 1, 3));
|
|
}
|
|
|
|
//Test Both
|
|
{
|
|
auto date = Date(1, 1, 1);
|
|
date.roll!"months"(-1);
|
|
assert(date == Date(1, 12, 1));
|
|
date.roll!"months"(1);
|
|
assert(date == Date(1, 1, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(4, 1, 1);
|
|
date.roll!"months"(-48);
|
|
assert(date == Date(4, 1, 1));
|
|
date.roll!"months"(48);
|
|
assert(date == Date(4, 1, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(4, 3, 31);
|
|
date.roll!"months"(-49);
|
|
assert(date == Date(4, 3, 2));
|
|
date.roll!"months"(49);
|
|
assert(date == Date(4, 4, 2));
|
|
}
|
|
|
|
{
|
|
auto date = Date(4, 3, 31);
|
|
date.roll!"months"(-85);
|
|
assert(date == Date(4, 3, 2));
|
|
date.roll!"months"(85);
|
|
assert(date == Date(4, 4, 2));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1, 1, 1);
|
|
date.roll!"months"(-1);
|
|
assert(date == Date(-1, 12, 1));
|
|
date.roll!"months"(1);
|
|
assert(date == Date(-1, 1, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-4, 1, 1);
|
|
date.roll!"months"(-48);
|
|
assert(date == Date(-4, 1, 1));
|
|
date.roll!"months"(48);
|
|
assert(date == Date(-4, 1, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-4, 3, 31);
|
|
date.roll!"months"(-49);
|
|
assert(date == Date(-4, 3, 2));
|
|
date.roll!"months"(49);
|
|
assert(date == Date(-4, 4, 2));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-4, 3, 31);
|
|
date.roll!"months"(-85);
|
|
assert(date == Date(-4, 3, 2));
|
|
date.roll!"months"(85);
|
|
assert(date == Date(-4, 4, 2));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-3, 3, 31);
|
|
date.roll!"months"(85).roll!"months"(-83);
|
|
assert(date == Date(-3, 6, 1));
|
|
}
|
|
|
|
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)));
|
|
}
|
|
|
|
//Test roll!"months"() with AllowDayOverlow.no
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
date.roll!"months"(3, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 10, 6));
|
|
date.roll!"months"(-4, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 6, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
date.roll!"months"(6, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 1, 6));
|
|
date.roll!"months"(-6, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
date.roll!"months"(27, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 10, 6));
|
|
date.roll!"months"(-28, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 6, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 5, 31);
|
|
date.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 6, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 5, 31);
|
|
date.roll!"months"(-1, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 4, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 2, 28);
|
|
date.roll!"months"(12, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(2000, 2, 29);
|
|
date.roll!"months"(12, AllowDayOverflow.no);
|
|
assert(date == Date(2000, 2, 29));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 7, 31);
|
|
date.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 8, 31));
|
|
date.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 9, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1998, 8, 31);
|
|
date.roll!"months"(13, AllowDayOverflow.no);
|
|
assert(date == Date(1998, 9, 30));
|
|
date.roll!"months"(-13, AllowDayOverflow.no);
|
|
assert(date == Date(1998, 8, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1997, 12, 31);
|
|
date.roll!"months"(13, AllowDayOverflow.no);
|
|
assert(date == Date(1997, 1, 31));
|
|
date.roll!"months"(-13, AllowDayOverflow.no);
|
|
assert(date == Date(1997, 12, 31));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1997, 12, 31);
|
|
date.roll!"months"(14, AllowDayOverflow.no);
|
|
assert(date == Date(1997, 2, 28));
|
|
date.roll!"months"(-14, AllowDayOverflow.no);
|
|
assert(date == Date(1997, 12, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1998, 12, 31);
|
|
date.roll!"months"(14, AllowDayOverflow.no);
|
|
assert(date == Date(1998, 2, 28));
|
|
date.roll!"months"(-14, AllowDayOverflow.no);
|
|
assert(date == Date(1998, 12, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 12, 31);
|
|
date.roll!"months"(14, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 2, 28));
|
|
date.roll!"months"(-14, AllowDayOverflow.no);
|
|
assert(date == Date(1999, 12, 28));
|
|
}
|
|
|
|
//Test B.C.
|
|
{
|
|
auto date = Date(-1999, 7, 6);
|
|
date.roll!"months"(3, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 10, 6));
|
|
date.roll!"months"(-4, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 6, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 7, 6);
|
|
date.roll!"months"(6, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 1, 6));
|
|
date.roll!"months"(-6, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 7, 6);
|
|
date.roll!"months"(-27, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 4, 6));
|
|
date.roll!"months"(28, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 8, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 5, 31);
|
|
date.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 6, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 5, 31);
|
|
date.roll!"months"(-1, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 4, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 2, 28);
|
|
date.roll!"months"(-12, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-2000, 2, 29);
|
|
date.roll!"months"(-12, AllowDayOverflow.no);
|
|
assert(date == Date(-2000, 2, 29));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 7, 31);
|
|
date.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 8, 31));
|
|
date.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(date == Date(-1999, 9, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1998, 8, 31);
|
|
date.roll!"months"(13, AllowDayOverflow.no);
|
|
assert(date == Date(-1998, 9, 30));
|
|
date.roll!"months"(-13, AllowDayOverflow.no);
|
|
assert(date == Date(-1998, 8, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1997, 12, 31);
|
|
date.roll!"months"(13, AllowDayOverflow.no);
|
|
assert(date == Date(-1997, 1, 31));
|
|
date.roll!"months"(-13, AllowDayOverflow.no);
|
|
assert(date == Date(-1997, 12, 31));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1997, 12, 31);
|
|
date.roll!"months"(14, AllowDayOverflow.no);
|
|
assert(date == Date(-1997, 2, 28));
|
|
date.roll!"months"(-14, AllowDayOverflow.no);
|
|
assert(date == Date(-1997, 12, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-2002, 12, 31);
|
|
date.roll!"months"(14, AllowDayOverflow.no);
|
|
assert(date == Date(-2002, 2, 28));
|
|
date.roll!"months"(-14, AllowDayOverflow.no);
|
|
assert(date == Date(-2002, 12, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-2001, 12, 31);
|
|
date.roll!"months"(14, AllowDayOverflow.no);
|
|
assert(date == Date(-2001, 2, 28));
|
|
date.roll!"months"(-14, AllowDayOverflow.no);
|
|
assert(date == Date(-2001, 12, 28));
|
|
}
|
|
|
|
//Test Both
|
|
{
|
|
auto date = Date(1, 1, 1);
|
|
date.roll!"months"(-1, AllowDayOverflow.no);
|
|
assert(date == Date(1, 12, 1));
|
|
date.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(date == Date(1, 1, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(4, 1, 1);
|
|
date.roll!"months"(-48, AllowDayOverflow.no);
|
|
assert(date == Date(4, 1, 1));
|
|
date.roll!"months"(48, AllowDayOverflow.no);
|
|
assert(date == Date(4, 1, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(4, 3, 31);
|
|
date.roll!"months"(-49, AllowDayOverflow.no);
|
|
assert(date == Date(4, 2, 29));
|
|
date.roll!"months"(49, AllowDayOverflow.no);
|
|
assert(date == Date(4, 3, 29));
|
|
}
|
|
|
|
{
|
|
auto date = Date(4, 3, 31);
|
|
date.roll!"months"(-85, AllowDayOverflow.no);
|
|
assert(date == Date(4, 2, 29));
|
|
date.roll!"months"(85, AllowDayOverflow.no);
|
|
assert(date == Date(4, 3, 29));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1, 1, 1);
|
|
date.roll!"months"(-1, AllowDayOverflow.no);
|
|
assert(date == Date(-1, 12, 1));
|
|
date.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(date == Date(-1, 1, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-4, 1, 1);
|
|
date.roll!"months"(-48, AllowDayOverflow.no);
|
|
assert(date == Date(-4, 1, 1));
|
|
date.roll!"months"(48, AllowDayOverflow.no);
|
|
assert(date == Date(-4, 1, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-4, 3, 31);
|
|
date.roll!"months"(-49, AllowDayOverflow.no);
|
|
assert(date == Date(-4, 2, 29));
|
|
date.roll!"months"(49, AllowDayOverflow.no);
|
|
assert(date == Date(-4, 3, 29));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-4, 3, 31);
|
|
date.roll!"months"(-85, AllowDayOverflow.no);
|
|
assert(date == Date(-4, 2, 29));
|
|
date.roll!"months"(85, AllowDayOverflow.no);
|
|
assert(date == Date(-4, 3, 29));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-3, 3, 31);
|
|
date.roll!"months"(85, AllowDayOverflow.no).roll!"months"(-83, AllowDayOverflow.no);
|
|
assert(date == Date(-3, 5, 30));
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
Adds the given number of units to this $(LREF Date). A negative number will
|
|
subtract.
|
|
|
|
The difference between rolling and adding is that rolling does not
|
|
affect larger units. For instance, rolling a $(LREF Date) one
|
|
year's worth of days gets the exact same $(LREF Date).
|
|
|
|
The only accepted units are $(D "days").
|
|
|
|
Params:
|
|
units = The units to add. Must be $(D "days").
|
|
days = The number of days to add to this $(LREF Date).
|
|
+/
|
|
ref Date roll(string units)(long days) @safe 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;
|
|
return this;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
auto d = Date(2010, 1, 1);
|
|
d.roll!"days"(1);
|
|
assert(d == Date(2010, 1, 2));
|
|
d.roll!"days"(365);
|
|
assert(d == Date(2010, 1, 26));
|
|
d.roll!"days"(-32);
|
|
assert(d == Date(2010, 1, 25));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
{
|
|
auto date = Date(1999, 2, 28);
|
|
date.roll!"days"(1);
|
|
assert(date == Date(1999, 2, 1));
|
|
date.roll!"days"(-1);
|
|
assert(date == Date(1999, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(2000, 2, 28);
|
|
date.roll!"days"(1);
|
|
assert(date == Date(2000, 2, 29));
|
|
date.roll!"days"(1);
|
|
assert(date == Date(2000, 2, 1));
|
|
date.roll!"days"(-1);
|
|
assert(date == Date(2000, 2, 29));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 6, 30);
|
|
date.roll!"days"(1);
|
|
assert(date == Date(1999, 6, 1));
|
|
date.roll!"days"(-1);
|
|
assert(date == Date(1999, 6, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 7, 31);
|
|
date.roll!"days"(1);
|
|
assert(date == Date(1999, 7, 1));
|
|
date.roll!"days"(-1);
|
|
assert(date == Date(1999, 7, 31));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 1, 1);
|
|
date.roll!"days"(-1);
|
|
assert(date == Date(1999, 1, 31));
|
|
date.roll!"days"(1);
|
|
assert(date == Date(1999, 1, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
date.roll!"days"(9);
|
|
assert(date == Date(1999, 7, 15));
|
|
date.roll!"days"(-11);
|
|
assert(date == Date(1999, 7, 4));
|
|
date.roll!"days"(30);
|
|
assert(date == Date(1999, 7, 3));
|
|
date.roll!"days"(-3);
|
|
assert(date == Date(1999, 7, 31));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
date.roll!"days"(365);
|
|
assert(date == Date(1999, 7, 30));
|
|
date.roll!"days"(-365);
|
|
assert(date == Date(1999, 7, 6));
|
|
date.roll!"days"(366);
|
|
assert(date == Date(1999, 7, 31));
|
|
date.roll!"days"(730);
|
|
assert(date == Date(1999, 7, 17));
|
|
date.roll!"days"(-1096);
|
|
assert(date == Date(1999, 7, 6));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 2, 6);
|
|
date.roll!"days"(365);
|
|
assert(date == Date(1999, 2, 7));
|
|
date.roll!"days"(-365);
|
|
assert(date == Date(1999, 2, 6));
|
|
date.roll!"days"(366);
|
|
assert(date == Date(1999, 2, 8));
|
|
date.roll!"days"(730);
|
|
assert(date == Date(1999, 2, 10));
|
|
date.roll!"days"(-1096);
|
|
assert(date == Date(1999, 2, 6));
|
|
}
|
|
|
|
//Test B.C.
|
|
{
|
|
auto date = Date(-1999, 2, 28);
|
|
date.roll!"days"(1);
|
|
assert(date == Date(-1999, 2, 1));
|
|
date.roll!"days"(-1);
|
|
assert(date == Date(-1999, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-2000, 2, 28);
|
|
date.roll!"days"(1);
|
|
assert(date == Date(-2000, 2, 29));
|
|
date.roll!"days"(1);
|
|
assert(date == Date(-2000, 2, 1));
|
|
date.roll!"days"(-1);
|
|
assert(date == Date(-2000, 2, 29));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 6, 30);
|
|
date.roll!"days"(1);
|
|
assert(date == Date(-1999, 6, 1));
|
|
date.roll!"days"(-1);
|
|
assert(date == Date(-1999, 6, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 7, 31);
|
|
date.roll!"days"(1);
|
|
assert(date == Date(-1999, 7, 1));
|
|
date.roll!"days"(-1);
|
|
assert(date == Date(-1999, 7, 31));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 1, 1);
|
|
date.roll!"days"(-1);
|
|
assert(date == Date(-1999, 1, 31));
|
|
date.roll!"days"(1);
|
|
assert(date == Date(-1999, 1, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 7, 6);
|
|
date.roll!"days"(9);
|
|
assert(date == Date(-1999, 7, 15));
|
|
date.roll!"days"(-11);
|
|
assert(date == Date(-1999, 7, 4));
|
|
date.roll!"days"(30);
|
|
assert(date == Date(-1999, 7, 3));
|
|
date.roll!"days"(-3);
|
|
assert(date == Date(-1999, 7, 31));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 7, 6);
|
|
date.roll!"days"(365);
|
|
assert(date == Date(-1999, 7, 30));
|
|
date.roll!"days"(-365);
|
|
assert(date == Date(-1999, 7, 6));
|
|
date.roll!"days"(366);
|
|
assert(date == Date(-1999, 7, 31));
|
|
date.roll!"days"(730);
|
|
assert(date == Date(-1999, 7, 17));
|
|
date.roll!"days"(-1096);
|
|
assert(date == Date(-1999, 7, 6));
|
|
}
|
|
|
|
//Test Both
|
|
{
|
|
auto date = Date(1, 7, 6);
|
|
date.roll!"days"(-365);
|
|
assert(date == Date(1, 7, 13));
|
|
date.roll!"days"(365);
|
|
assert(date == Date(1, 7, 6));
|
|
date.roll!"days"(-731);
|
|
assert(date == Date(1, 7, 19));
|
|
date.roll!"days"(730);
|
|
assert(date == Date(1, 7, 5));
|
|
}
|
|
|
|
{
|
|
auto date = Date(0, 7, 6);
|
|
date.roll!"days"(-365);
|
|
assert(date == Date(0, 7, 13));
|
|
date.roll!"days"(365);
|
|
assert(date == Date(0, 7, 6));
|
|
date.roll!"days"(-731);
|
|
assert(date == Date(0, 7, 19));
|
|
date.roll!"days"(730);
|
|
assert(date == Date(0, 7, 5));
|
|
}
|
|
|
|
{
|
|
auto date = Date(0, 7, 6);
|
|
date.roll!"days"(-365).roll!"days"(362).roll!"days"(-12).roll!"days"(730);
|
|
assert(date == Date(0, 7, 8));
|
|
}
|
|
|
|
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)));
|
|
}
|
|
|
|
|
|
/++
|
|
Gives the result of adding or subtracting a duration from this
|
|
$(LREF Date).
|
|
|
|
The legal types of arithmetic for Date using this operator are
|
|
|
|
$(BOOKTABLE,
|
|
$(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 $(LREF Date).
|
|
+/
|
|
Date opBinary(string op, D)(in D duration) @safe const pure nothrow
|
|
if((op == "+" || op == "-") &&
|
|
(is(Unqual!D == Duration) ||
|
|
is(Unqual!D == TickDuration)))
|
|
{
|
|
import std.format : format;
|
|
|
|
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);
|
|
|
|
mixin(format("return retval._addDays(%sdays);", op));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
|
|
assert(date + dur!"weeks"(7) == Date(1999, 8, 24));
|
|
assert(date + dur!"weeks"(-7) == Date(1999, 5, 18));
|
|
assert(date + dur!"days"(7) == Date(1999, 7, 13));
|
|
assert(date + dur!"days"(-7) == Date(1999, 6, 29));
|
|
|
|
assert(date + dur!"hours"(24) == Date(1999, 7, 7));
|
|
assert(date + dur!"hours"(-24) == Date(1999, 7, 5));
|
|
assert(date + dur!"minutes"(1440) == Date(1999, 7, 7));
|
|
assert(date + dur!"minutes"(-1440) == Date(1999, 7, 5));
|
|
assert(date + dur!"seconds"(86_400) == Date(1999, 7, 7));
|
|
assert(date + dur!"seconds"(-86_400) == Date(1999, 7, 5));
|
|
assert(date + dur!"msecs"(86_400_000) == Date(1999, 7, 7));
|
|
assert(date + dur!"msecs"(-86_400_000) == Date(1999, 7, 5));
|
|
assert(date + dur!"usecs"(86_400_000_000) == Date(1999, 7, 7));
|
|
assert(date + dur!"usecs"(-86_400_000_000) == Date(1999, 7, 5));
|
|
assert(date + dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 7));
|
|
assert(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)
|
|
{
|
|
assert(date + TickDuration.from!"usecs"(86_400_000_000) == Date(1999, 7, 7));
|
|
assert(date + TickDuration.from!"usecs"(-86_400_000_000) == Date(1999, 7, 5));
|
|
}
|
|
|
|
assert(date - dur!"weeks"(-7) == Date(1999, 8, 24));
|
|
assert(date - dur!"weeks"(7) == Date(1999, 5, 18));
|
|
assert(date - dur!"days"(-7) == Date(1999, 7, 13));
|
|
assert(date - dur!"days"(7) == Date(1999, 6, 29));
|
|
|
|
assert(date - dur!"hours"(-24) == Date(1999, 7, 7));
|
|
assert(date - dur!"hours"(24) == Date(1999, 7, 5));
|
|
assert(date - dur!"minutes"(-1440) == Date(1999, 7, 7));
|
|
assert(date - dur!"minutes"(1440) == Date(1999, 7, 5));
|
|
assert(date - dur!"seconds"(-86_400) == Date(1999, 7, 7));
|
|
assert(date - dur!"seconds"(86_400) == Date(1999, 7, 5));
|
|
assert(date - dur!"msecs"(-86_400_000) == Date(1999, 7, 7));
|
|
assert(date - dur!"msecs"(86_400_000) == Date(1999, 7, 5));
|
|
assert(date - dur!"usecs"(-86_400_000_000) == Date(1999, 7, 7));
|
|
assert(date - dur!"usecs"(86_400_000_000) == Date(1999, 7, 5));
|
|
assert(date - dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 7));
|
|
assert(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)
|
|
{
|
|
assert(date - TickDuration.from!"usecs"(-86_400_000_000) == Date(1999, 7, 7));
|
|
assert(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
|
|
$(LREF Date), as well as assigning the result to this $(LREF Date).
|
|
|
|
The legal types of arithmetic for $(LREF Date) using this operator are
|
|
|
|
$(BOOKTABLE,
|
|
$(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 $(LREF Date).
|
|
+/
|
|
ref Date opOpAssign(string op, D)(in D duration) @safe pure nothrow
|
|
if((op == "+" || op == "-") &&
|
|
(is(Unqual!D == Duration) ||
|
|
is(Unqual!D == TickDuration)))
|
|
{
|
|
import std.format : format;
|
|
|
|
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);
|
|
|
|
mixin(format("return _addDays(%sdays);", op));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(Date(1999, 7, 6) + dur!"weeks"(7) == Date(1999, 8, 24));
|
|
assert(Date(1999, 7, 6) + dur!"weeks"(-7) == Date(1999, 5, 18));
|
|
assert(Date(1999, 7, 6) + dur!"days"(7) == Date(1999, 7, 13));
|
|
assert(Date(1999, 7, 6) + dur!"days"(-7) == Date(1999, 6, 29));
|
|
|
|
assert(Date(1999, 7, 6) + dur!"hours"(24) == Date(1999, 7, 7));
|
|
assert(Date(1999, 7, 6) + dur!"hours"(-24) == Date(1999, 7, 5));
|
|
assert(Date(1999, 7, 6) + dur!"minutes"(1440) == Date(1999, 7, 7));
|
|
assert(Date(1999, 7, 6) + dur!"minutes"(-1440) == Date(1999, 7, 5));
|
|
assert(Date(1999, 7, 6) + dur!"seconds"(86_400) == Date(1999, 7, 7));
|
|
assert(Date(1999, 7, 6) + dur!"seconds"(-86_400) == Date(1999, 7, 5));
|
|
assert(Date(1999, 7, 6) + dur!"msecs"(86_400_000) == Date(1999, 7, 7));
|
|
assert(Date(1999, 7, 6) + dur!"msecs"(-86_400_000) == Date(1999, 7, 5));
|
|
assert(Date(1999, 7, 6) + dur!"usecs"(86_400_000_000) == Date(1999, 7, 7));
|
|
assert(Date(1999, 7, 6) + dur!"usecs"(-86_400_000_000) == Date(1999, 7, 5));
|
|
assert(Date(1999, 7, 6) + dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 7));
|
|
assert(Date(1999, 7, 6) + dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 5));
|
|
|
|
assert(Date(1999, 7, 6) - dur!"weeks"(-7) == Date(1999, 8, 24));
|
|
assert(Date(1999, 7, 6) - dur!"weeks"(7) == Date(1999, 5, 18));
|
|
assert(Date(1999, 7, 6) - dur!"days"(-7) == Date(1999, 7, 13));
|
|
assert(Date(1999, 7, 6) - dur!"days"(7) == Date(1999, 6, 29));
|
|
|
|
assert(Date(1999, 7, 6) - dur!"hours"(-24) == Date(1999, 7, 7));
|
|
assert(Date(1999, 7, 6) - dur!"hours"(24) == Date(1999, 7, 5));
|
|
assert(Date(1999, 7, 6) - dur!"minutes"(-1440) == Date(1999, 7, 7));
|
|
assert(Date(1999, 7, 6) - dur!"minutes"(1440) == Date(1999, 7, 5));
|
|
assert(Date(1999, 7, 6) - dur!"seconds"(-86_400) == Date(1999, 7, 7));
|
|
assert(Date(1999, 7, 6) - dur!"seconds"(86_400) == Date(1999, 7, 5));
|
|
assert(Date(1999, 7, 6) - dur!"msecs"(-86_400_000) == Date(1999, 7, 7));
|
|
assert(Date(1999, 7, 6) - dur!"msecs"(86_400_000) == Date(1999, 7, 5));
|
|
assert(Date(1999, 7, 6) - dur!"usecs"(-86_400_000_000) == Date(1999, 7, 7));
|
|
assert(Date(1999, 7, 6) - dur!"usecs"(86_400_000_000) == Date(1999, 7, 5));
|
|
assert(Date(1999, 7, 6) - dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 7));
|
|
assert(Date(1999, 7, 6) - dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 5));
|
|
|
|
{
|
|
auto date = Date(0, 1, 31);
|
|
(date += dur!"days"(507)) += dur!"days"(-2);
|
|
assert(date == Date(1, 6, 19));
|
|
}
|
|
|
|
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 $(LREF Date)s.
|
|
|
|
The legal types of arithmetic for Date using this operator are
|
|
|
|
$(BOOKTABLE,
|
|
$(TR $(TD Date) $(TD -) $(TD Date) $(TD -->) $(TD duration))
|
|
)
|
|
+/
|
|
Duration opBinary(string op)(in Date rhs) @safe const pure nothrow
|
|
if(op == "-")
|
|
{
|
|
return dur!"days"(this.dayOfGregorianCal - rhs.dayOfGregorianCal);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
|
|
assert(Date(1999, 7, 6) - Date(1998, 7, 6) == dur!"days"(365));
|
|
assert(Date(1998, 7, 6) - Date(1999, 7, 6) == dur!"days"(-365));
|
|
assert(Date(1999, 6, 6) - Date(1999, 5, 6) == dur!"days"(31));
|
|
assert(Date(1999, 5, 6) - Date(1999, 6, 6) == dur!"days"(-31));
|
|
assert(Date(1999, 1, 1) - Date(1998, 12, 31) == dur!"days"(1));
|
|
assert(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 $(LREF Date)s in months.
|
|
|
|
To get the difference in years, subtract the year property
|
|
of two $(LREF SysTime)s. To get the difference in days or weeks,
|
|
subtract the $(LREF SysTime)s themselves and use the $(CXREF time, Duration)
|
|
that results. Because converting between months and smaller
|
|
units requires a specific date (which $(CXREF time, Duration)s don't have),
|
|
getting the difference in months requires 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 $(LREF 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 $(LREF Date) to subtract from this one.
|
|
+/
|
|
int diffMonths(in Date rhs) @safe const pure nothrow
|
|
{
|
|
immutable yearDiff = _year - rhs._year;
|
|
immutable monthDiff = _month - rhs._month;
|
|
|
|
return yearDiff * 12 + monthDiff;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
|
|
//Test A.D.
|
|
assert(date.diffMonths(Date(1998, 6, 5)) == 13);
|
|
assert(date.diffMonths(Date(1998, 7, 5)) == 12);
|
|
assert(date.diffMonths(Date(1998, 8, 5)) == 11);
|
|
assert(date.diffMonths(Date(1998, 9, 5)) == 10);
|
|
assert(date.diffMonths(Date(1998, 10, 5)) == 9);
|
|
assert(date.diffMonths(Date(1998, 11, 5)) == 8);
|
|
assert(date.diffMonths(Date(1998, 12, 5)) == 7);
|
|
assert(date.diffMonths(Date(1999, 1, 5)) == 6);
|
|
assert(date.diffMonths(Date(1999, 2, 6)) == 5);
|
|
assert(date.diffMonths(Date(1999, 3, 6)) == 4);
|
|
assert(date.diffMonths(Date(1999, 4, 6)) == 3);
|
|
assert(date.diffMonths(Date(1999, 5, 6)) == 2);
|
|
assert(date.diffMonths(Date(1999, 6, 6)) == 1);
|
|
assert(date.diffMonths(date) == 0);
|
|
assert(date.diffMonths(Date(1999, 8, 6)) == -1);
|
|
assert(date.diffMonths(Date(1999, 9, 6)) == -2);
|
|
assert(date.diffMonths(Date(1999, 10, 6)) == -3);
|
|
assert(date.diffMonths(Date(1999, 11, 6)) == -4);
|
|
assert(date.diffMonths(Date(1999, 12, 6)) == -5);
|
|
assert(date.diffMonths(Date(2000, 1, 6)) == -6);
|
|
assert(date.diffMonths(Date(2000, 2, 6)) == -7);
|
|
assert(date.diffMonths(Date(2000, 3, 6)) == -8);
|
|
assert(date.diffMonths(Date(2000, 4, 6)) == -9);
|
|
assert(date.diffMonths(Date(2000, 5, 6)) == -10);
|
|
assert(date.diffMonths(Date(2000, 6, 6)) == -11);
|
|
assert(date.diffMonths(Date(2000, 7, 6)) == -12);
|
|
assert(date.diffMonths(Date(2000, 8, 6)) == -13);
|
|
|
|
assert(Date(1998, 6, 5).diffMonths(date) == -13);
|
|
assert(Date(1998, 7, 5).diffMonths(date) == -12);
|
|
assert(Date(1998, 8, 5).diffMonths(date) == -11);
|
|
assert(Date(1998, 9, 5).diffMonths(date) == -10);
|
|
assert(Date(1998, 10, 5).diffMonths(date) == -9);
|
|
assert(Date(1998, 11, 5).diffMonths(date) == -8);
|
|
assert(Date(1998, 12, 5).diffMonths(date) == -7);
|
|
assert(Date(1999, 1, 5).diffMonths(date) == -6);
|
|
assert(Date(1999, 2, 6).diffMonths(date) == -5);
|
|
assert(Date(1999, 3, 6).diffMonths(date) == -4);
|
|
assert(Date(1999, 4, 6).diffMonths(date) == -3);
|
|
assert(Date(1999, 5, 6).diffMonths(date) == -2);
|
|
assert(Date(1999, 6, 6).diffMonths(date) == -1);
|
|
assert(Date(1999, 8, 6).diffMonths(date) == 1);
|
|
assert(Date(1999, 9, 6).diffMonths(date) == 2);
|
|
assert(Date(1999, 10, 6).diffMonths(date) == 3);
|
|
assert(Date(1999, 11, 6).diffMonths(date) == 4);
|
|
assert(Date(1999, 12, 6).diffMonths(date) == 5);
|
|
assert(Date(2000, 1, 6).diffMonths(date) == 6);
|
|
assert(Date(2000, 2, 6).diffMonths(date) == 7);
|
|
assert(Date(2000, 3, 6).diffMonths(date) == 8);
|
|
assert(Date(2000, 4, 6).diffMonths(date) == 9);
|
|
assert(Date(2000, 5, 6).diffMonths(date) == 10);
|
|
assert(Date(2000, 6, 6).diffMonths(date) == 11);
|
|
assert(Date(2000, 7, 6).diffMonths(date) == 12);
|
|
assert(Date(2000, 8, 6).diffMonths(date) == 13);
|
|
|
|
assert(date.diffMonths(Date(1999, 6, 30)) == 1);
|
|
assert(date.diffMonths(Date(1999, 7, 1)) == 0);
|
|
assert(date.diffMonths(Date(1999, 7, 6)) == 0);
|
|
assert(date.diffMonths(Date(1999, 7, 11)) == 0);
|
|
assert(date.diffMonths(Date(1999, 7, 16)) == 0);
|
|
assert(date.diffMonths(Date(1999, 7, 21)) == 0);
|
|
assert(date.diffMonths(Date(1999, 7, 26)) == 0);
|
|
assert(date.diffMonths(Date(1999, 7, 31)) == 0);
|
|
assert(date.diffMonths(Date(1999, 8, 1)) == -1);
|
|
|
|
assert(date.diffMonths(Date(1990, 6, 30)) == 109);
|
|
assert(date.diffMonths(Date(1990, 7, 1)) == 108);
|
|
assert(date.diffMonths(Date(1990, 7, 6)) == 108);
|
|
assert(date.diffMonths(Date(1990, 7, 11)) == 108);
|
|
assert(date.diffMonths(Date(1990, 7, 16)) == 108);
|
|
assert(date.diffMonths(Date(1990, 7, 21)) == 108);
|
|
assert(date.diffMonths(Date(1990, 7, 26)) == 108);
|
|
assert(date.diffMonths(Date(1990, 7, 31)) == 108);
|
|
assert(date.diffMonths(Date(1990, 8, 1)) == 107);
|
|
|
|
assert(Date(1999, 6, 30).diffMonths(date) == -1);
|
|
assert(Date(1999, 7, 1).diffMonths(date) == 0);
|
|
assert(Date(1999, 7, 6).diffMonths(date) == 0);
|
|
assert(Date(1999, 7, 11).diffMonths(date) == 0);
|
|
assert(Date(1999, 7, 16).diffMonths(date) == 0);
|
|
assert(Date(1999, 7, 21).diffMonths(date) == 0);
|
|
assert(Date(1999, 7, 26).diffMonths(date) == 0);
|
|
assert(Date(1999, 7, 31).diffMonths(date) == 0);
|
|
assert(Date(1999, 8, 1).diffMonths(date) == 1);
|
|
|
|
assert(Date(1990, 6, 30).diffMonths(date) == -109);
|
|
assert(Date(1990, 7, 1).diffMonths(date) == -108);
|
|
assert(Date(1990, 7, 6).diffMonths(date) == -108);
|
|
assert(Date(1990, 7, 11).diffMonths(date) == -108);
|
|
assert(Date(1990, 7, 16).diffMonths(date) == -108);
|
|
assert(Date(1990, 7, 21).diffMonths(date) == -108);
|
|
assert(Date(1990, 7, 26).diffMonths(date) == -108);
|
|
assert(Date(1990, 7, 31).diffMonths(date) == -108);
|
|
assert(Date(1990, 8, 1).diffMonths(date) == -107);
|
|
|
|
//Test B.C.
|
|
auto dateBC = Date(-1999, 7, 6);
|
|
|
|
assert(dateBC.diffMonths(Date(-2000, 6, 5)) == 13);
|
|
assert(dateBC.diffMonths(Date(-2000, 7, 5)) == 12);
|
|
assert(dateBC.diffMonths(Date(-2000, 8, 5)) == 11);
|
|
assert(dateBC.diffMonths(Date(-2000, 9, 5)) == 10);
|
|
assert(dateBC.diffMonths(Date(-2000, 10, 5)) == 9);
|
|
assert(dateBC.diffMonths(Date(-2000, 11, 5)) == 8);
|
|
assert(dateBC.diffMonths(Date(-2000, 12, 5)) == 7);
|
|
assert(dateBC.diffMonths(Date(-1999, 1, 5)) == 6);
|
|
assert(dateBC.diffMonths(Date(-1999, 2, 6)) == 5);
|
|
assert(dateBC.diffMonths(Date(-1999, 3, 6)) == 4);
|
|
assert(dateBC.diffMonths(Date(-1999, 4, 6)) == 3);
|
|
assert(dateBC.diffMonths(Date(-1999, 5, 6)) == 2);
|
|
assert(dateBC.diffMonths(Date(-1999, 6, 6)) == 1);
|
|
assert(dateBC.diffMonths(dateBC) == 0);
|
|
assert(dateBC.diffMonths(Date(-1999, 8, 6)) == -1);
|
|
assert(dateBC.diffMonths(Date(-1999, 9, 6)) == -2);
|
|
assert(dateBC.diffMonths(Date(-1999, 10, 6)) == -3);
|
|
assert(dateBC.diffMonths(Date(-1999, 11, 6)) == -4);
|
|
assert(dateBC.diffMonths(Date(-1999, 12, 6)) == -5);
|
|
assert(dateBC.diffMonths(Date(-1998, 1, 6)) == -6);
|
|
assert(dateBC.diffMonths(Date(-1998, 2, 6)) == -7);
|
|
assert(dateBC.diffMonths(Date(-1998, 3, 6)) == -8);
|
|
assert(dateBC.diffMonths(Date(-1998, 4, 6)) == -9);
|
|
assert(dateBC.diffMonths(Date(-1998, 5, 6)) == -10);
|
|
assert(dateBC.diffMonths(Date(-1998, 6, 6)) == -11);
|
|
assert(dateBC.diffMonths(Date(-1998, 7, 6)) == -12);
|
|
assert(dateBC.diffMonths(Date(-1998, 8, 6)) == -13);
|
|
|
|
assert(Date(-2000, 6, 5).diffMonths(dateBC) == -13);
|
|
assert(Date(-2000, 7, 5).diffMonths(dateBC) == -12);
|
|
assert(Date(-2000, 8, 5).diffMonths(dateBC) == -11);
|
|
assert(Date(-2000, 9, 5).diffMonths(dateBC) == -10);
|
|
assert(Date(-2000, 10, 5).diffMonths(dateBC) == -9);
|
|
assert(Date(-2000, 11, 5).diffMonths(dateBC) == -8);
|
|
assert(Date(-2000, 12, 5).diffMonths(dateBC) == -7);
|
|
assert(Date(-1999, 1, 5).diffMonths(dateBC) == -6);
|
|
assert(Date(-1999, 2, 6).diffMonths(dateBC) == -5);
|
|
assert(Date(-1999, 3, 6).diffMonths(dateBC) == -4);
|
|
assert(Date(-1999, 4, 6).diffMonths(dateBC) == -3);
|
|
assert(Date(-1999, 5, 6).diffMonths(dateBC) == -2);
|
|
assert(Date(-1999, 6, 6).diffMonths(dateBC) == -1);
|
|
assert(Date(-1999, 8, 6).diffMonths(dateBC) == 1);
|
|
assert(Date(-1999, 9, 6).diffMonths(dateBC) == 2);
|
|
assert(Date(-1999, 10, 6).diffMonths(dateBC) == 3);
|
|
assert(Date(-1999, 11, 6).diffMonths(dateBC) == 4);
|
|
assert(Date(-1999, 12, 6).diffMonths(dateBC) == 5);
|
|
assert(Date(-1998, 1, 6).diffMonths(dateBC) == 6);
|
|
assert(Date(-1998, 2, 6).diffMonths(dateBC) == 7);
|
|
assert(Date(-1998, 3, 6).diffMonths(dateBC) == 8);
|
|
assert(Date(-1998, 4, 6).diffMonths(dateBC) == 9);
|
|
assert(Date(-1998, 5, 6).diffMonths(dateBC) == 10);
|
|
assert(Date(-1998, 6, 6).diffMonths(dateBC) == 11);
|
|
assert(Date(-1998, 7, 6).diffMonths(dateBC) == 12);
|
|
assert(Date(-1998, 8, 6).diffMonths(dateBC) == 13);
|
|
|
|
assert(dateBC.diffMonths(Date(-1999, 6, 30)) == 1);
|
|
assert(dateBC.diffMonths(Date(-1999, 7, 1)) == 0);
|
|
assert(dateBC.diffMonths(Date(-1999, 7, 6)) == 0);
|
|
assert(dateBC.diffMonths(Date(-1999, 7, 11)) == 0);
|
|
assert(dateBC.diffMonths(Date(-1999, 7, 16)) == 0);
|
|
assert(dateBC.diffMonths(Date(-1999, 7, 21)) == 0);
|
|
assert(dateBC.diffMonths(Date(-1999, 7, 26)) == 0);
|
|
assert(dateBC.diffMonths(Date(-1999, 7, 31)) == 0);
|
|
assert(dateBC.diffMonths(Date(-1999, 8, 1)) == -1);
|
|
|
|
assert(dateBC.diffMonths(Date(-2008, 6, 30)) == 109);
|
|
assert(dateBC.diffMonths(Date(-2008, 7, 1)) == 108);
|
|
assert(dateBC.diffMonths(Date(-2008, 7, 6)) == 108);
|
|
assert(dateBC.diffMonths(Date(-2008, 7, 11)) == 108);
|
|
assert(dateBC.diffMonths(Date(-2008, 7, 16)) == 108);
|
|
assert(dateBC.diffMonths(Date(-2008, 7, 21)) == 108);
|
|
assert(dateBC.diffMonths(Date(-2008, 7, 26)) == 108);
|
|
assert(dateBC.diffMonths(Date(-2008, 7, 31)) == 108);
|
|
assert(dateBC.diffMonths(Date(-2008, 8, 1)) == 107);
|
|
|
|
assert(Date(-1999, 6, 30).diffMonths(dateBC) == -1);
|
|
assert(Date(-1999, 7, 1).diffMonths(dateBC) == 0);
|
|
assert(Date(-1999, 7, 6).diffMonths(dateBC) == 0);
|
|
assert(Date(-1999, 7, 11).diffMonths(dateBC) == 0);
|
|
assert(Date(-1999, 7, 16).diffMonths(dateBC) == 0);
|
|
assert(Date(-1999, 7, 21).diffMonths(dateBC) == 0);
|
|
assert(Date(-1999, 7, 26).diffMonths(dateBC) == 0);
|
|
assert(Date(-1999, 7, 31).diffMonths(dateBC) == 0);
|
|
assert(Date(-1999, 8, 1).diffMonths(dateBC) == 1);
|
|
|
|
assert(Date(-2008, 6, 30).diffMonths(dateBC) == -109);
|
|
assert(Date(-2008, 7, 1).diffMonths(dateBC) == -108);
|
|
assert(Date(-2008, 7, 6).diffMonths(dateBC) == -108);
|
|
assert(Date(-2008, 7, 11).diffMonths(dateBC) == -108);
|
|
assert(Date(-2008, 7, 16).diffMonths(dateBC) == -108);
|
|
assert(Date(-2008, 7, 21).diffMonths(dateBC) == -108);
|
|
assert(Date(-2008, 7, 26).diffMonths(dateBC) == -108);
|
|
assert(Date(-2008, 7, 31).diffMonths(dateBC) == -108);
|
|
assert(Date(-2008, 8, 1).diffMonths(dateBC) == -107);
|
|
|
|
//Test Both
|
|
assert(Date(3, 3, 3).diffMonths(Date(-5, 5, 5)) == 94);
|
|
assert(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)));
|
|
}
|
|
|
|
|
|
/++
|
|
Whether this $(LREF Date) is in a leap year.
|
|
+/
|
|
@property bool isLeapYear() @safe 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 $(LREF Date) is on.
|
|
+/
|
|
@property DayOfWeek dayOfWeek() @safe 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 $(LREF Date) is on.
|
|
+/
|
|
@property ushort dayOfYear() @safe const pure nothrow
|
|
{
|
|
if (_month >= Month.jan && _month <= Month.dec)
|
|
{
|
|
immutable int[] lastDay = isLeapYear ? lastDayLeap : lastDayNonLeap;
|
|
auto monthIndex = _month - Month.jan;
|
|
|
|
return cast(ushort)(lastDay[monthIndex] + _day);
|
|
}
|
|
assert(0, "Invalid month.");
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(Date(1999, 1, 1).dayOfYear == 1);
|
|
assert(Date(1999, 12, 31).dayOfYear == 365);
|
|
assert(Date(2000, 12, 31).dayOfYear == 366);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.range;
|
|
|
|
foreach(year; filter!((a){return !yearIsLeapYear(a);})
|
|
(chain(testYearsBC, testYearsAD)))
|
|
{
|
|
foreach(doy; testDaysOfYear)
|
|
{
|
|
assert(Date(year, doy.md.month, doy.md.day).dayOfYear ==
|
|
doy.day);
|
|
}
|
|
}
|
|
|
|
foreach(year; filter!((a){return yearIsLeapYear(a);})
|
|
(chain(testYearsBC, testYearsAD)))
|
|
{
|
|
foreach(doy; testDaysOfLeapYear)
|
|
{
|
|
assert(Date(year, doy.md.month, doy.md.day).dayOfYear ==
|
|
doy.day);
|
|
}
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
/++
|
|
Day of the year.
|
|
|
|
Params:
|
|
day = The day of the year to set which day of the year this
|
|
$(LREF Date) is on.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given day is an invalid day of the
|
|
year.
|
|
+/
|
|
@property void dayOfYear(int day) @safe pure
|
|
{
|
|
immutable int[] lastDay = isLeapYear ? lastDayLeap : lastDayNonLeap;
|
|
|
|
if(day <= 0 || day > (isLeapYear ? daysInLeapYear : daysInYear) )
|
|
throw new DateTimeException("Invalid day of the year.");
|
|
|
|
foreach (i; 1..lastDay.length)
|
|
{
|
|
if (day <= lastDay[i])
|
|
{
|
|
_month = cast(Month)(cast(int)Month.jan + i - 1);
|
|
_day = cast(ubyte)(day - lastDay[i - 1]);
|
|
return;
|
|
}
|
|
}
|
|
assert(0, "Invalid day of the year.");
|
|
}
|
|
|
|
unittest
|
|
{
|
|
static void test(Date date, int day, MonthDay expected, size_t line = __LINE__)
|
|
{
|
|
date.dayOfYear = day;
|
|
assert(date.month == expected.month);
|
|
assert(date.day == expected.day);
|
|
}
|
|
|
|
foreach(doy; testDaysOfYear)
|
|
{
|
|
test(Date(1999, 1, 1), doy.day, doy.md);
|
|
test(Date(-1, 1, 1), doy.day, doy.md);
|
|
}
|
|
|
|
foreach(doy; testDaysOfLeapYear)
|
|
{
|
|
test(Date(2000, 1, 1), doy.day, doy.md);
|
|
test(Date(-4, 1, 1), doy.day, doy.md);
|
|
}
|
|
|
|
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 $(LREF Date) is on.
|
|
+/
|
|
@property int dayOfGregorianCal() @safe 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
|
|
{
|
|
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);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.range;
|
|
|
|
foreach(gd; chain(testGregDaysBC, testGregDaysAD))
|
|
assert(gd.date.dayOfGregorianCal == gd.day);
|
|
|
|
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));
|
|
}
|
|
|
|
/++
|
|
The Xth day of the Gregorian Calendar that this $(LREF Date) is on.
|
|
|
|
Params:
|
|
day = The day of the Gregorian Calendar to set this $(LREF Date) to.
|
|
+/
|
|
@property void dayOfGregorianCal(int day) @safe pure nothrow
|
|
{
|
|
this = Date(day);
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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));
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
/++
|
|
The ISO 8601 week of the year that this $(LREF Date) is in.
|
|
|
|
See_Also:
|
|
$(WEB en.wikipedia.org/wiki/ISO_week_date, ISO Week Date)
|
|
+/
|
|
@property ubyte isoWeek() @safe 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.
|
|
assert(Date(2009, 12, 28).isoWeek == 53);
|
|
assert(Date(2009, 12, 29).isoWeek == 53);
|
|
assert(Date(2009, 12, 30).isoWeek == 53);
|
|
assert(Date(2009, 12, 31).isoWeek == 53);
|
|
assert(Date(2010, 1, 1).isoWeek == 53);
|
|
assert(Date(2010, 1, 2).isoWeek == 53);
|
|
assert(Date(2010, 1, 3).isoWeek == 53);
|
|
assert(Date(2010, 1, 4).isoWeek == 1);
|
|
assert(Date(2010, 1, 5).isoWeek == 1);
|
|
assert(Date(2010, 1, 6).isoWeek == 1);
|
|
assert(Date(2010, 1, 7).isoWeek == 1);
|
|
assert(Date(2010, 1, 8).isoWeek == 1);
|
|
assert(Date(2010, 1, 9).isoWeek == 1);
|
|
assert(Date(2010, 1, 10).isoWeek == 1);
|
|
assert(Date(2010, 1, 11).isoWeek == 2);
|
|
assert(Date(2010, 12, 31).isoWeek == 52);
|
|
|
|
assert(Date(2004, 12, 26).isoWeek == 52);
|
|
assert(Date(2004, 12, 27).isoWeek == 53);
|
|
assert(Date(2004, 12, 28).isoWeek == 53);
|
|
assert(Date(2004, 12, 29).isoWeek == 53);
|
|
assert(Date(2004, 12, 30).isoWeek == 53);
|
|
assert(Date(2004, 12, 31).isoWeek == 53);
|
|
assert(Date(2005, 1, 1).isoWeek == 53);
|
|
assert(Date(2005, 1, 2).isoWeek == 53);
|
|
|
|
assert(Date(2005, 12, 31).isoWeek == 52);
|
|
assert(Date(2007, 1, 1).isoWeek == 1);
|
|
|
|
assert(Date(2007, 12, 30).isoWeek == 52);
|
|
assert(Date(2007, 12, 31).isoWeek == 1);
|
|
assert(Date(2008, 1, 1).isoWeek == 1);
|
|
|
|
assert(Date(2008, 12, 28).isoWeek == 52);
|
|
assert(Date(2008, 12, 29).isoWeek == 1);
|
|
assert(Date(2008, 12, 30).isoWeek == 1);
|
|
assert(Date(2008, 12, 31).isoWeek == 1);
|
|
assert(Date(2009, 1, 1).isoWeek == 1);
|
|
assert(Date(2009, 1, 2).isoWeek == 1);
|
|
assert(Date(2009, 1, 3).isoWeek == 1);
|
|
assert(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.
|
|
assert(Date(0, 12, 31).isoWeek == 52);
|
|
assert(Date(0, 1, 4).isoWeek == 1);
|
|
assert(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));
|
|
}
|
|
|
|
|
|
/++
|
|
$(LREF Date) for the last day in the month that this $(LREF Date) is in.
|
|
+/
|
|
@property Date endOfMonth() @safe const pure nothrow
|
|
{
|
|
try
|
|
return Date(_year, _month, maxDay(_year, _month));
|
|
catch(Exception e)
|
|
assert(0, "Date's constructor threw.");
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
assert(Date(1999, 1, 1).endOfMonth == Date(1999, 1, 31));
|
|
assert(Date(1999, 2, 1).endOfMonth == Date(1999, 2, 28));
|
|
assert(Date(2000, 2, 1).endOfMonth == Date(2000, 2, 29));
|
|
assert(Date(1999, 3, 1).endOfMonth == Date(1999, 3, 31));
|
|
assert(Date(1999, 4, 1).endOfMonth == Date(1999, 4, 30));
|
|
assert(Date(1999, 5, 1).endOfMonth == Date(1999, 5, 31));
|
|
assert(Date(1999, 6, 1).endOfMonth == Date(1999, 6, 30));
|
|
assert(Date(1999, 7, 1).endOfMonth == Date(1999, 7, 31));
|
|
assert(Date(1999, 8, 1).endOfMonth == Date(1999, 8, 31));
|
|
assert(Date(1999, 9, 1).endOfMonth == Date(1999, 9, 30));
|
|
assert(Date(1999, 10, 1).endOfMonth == Date(1999, 10, 31));
|
|
assert(Date(1999, 11, 1).endOfMonth == Date(1999, 11, 30));
|
|
assert(Date(1999, 12, 1).endOfMonth == Date(1999, 12, 31));
|
|
|
|
//Test B.C.
|
|
assert(Date(-1999, 1, 1).endOfMonth == Date(-1999, 1, 31));
|
|
assert(Date(-1999, 2, 1).endOfMonth == Date(-1999, 2, 28));
|
|
assert(Date(-2000, 2, 1).endOfMonth == Date(-2000, 2, 29));
|
|
assert(Date(-1999, 3, 1).endOfMonth == Date(-1999, 3, 31));
|
|
assert(Date(-1999, 4, 1).endOfMonth == Date(-1999, 4, 30));
|
|
assert(Date(-1999, 5, 1).endOfMonth == Date(-1999, 5, 31));
|
|
assert(Date(-1999, 6, 1).endOfMonth == Date(-1999, 6, 30));
|
|
assert(Date(-1999, 7, 1).endOfMonth == Date(-1999, 7, 31));
|
|
assert(Date(-1999, 8, 1).endOfMonth == Date(-1999, 8, 31));
|
|
assert(Date(-1999, 9, 1).endOfMonth == Date(-1999, 9, 30));
|
|
assert(Date(-1999, 10, 1).endOfMonth == Date(-1999, 10, 31));
|
|
assert(Date(-1999, 11, 1).endOfMonth == Date(-1999, 11, 30));
|
|
assert(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)));
|
|
}
|
|
|
|
|
|
/++
|
|
The last day in the month that this $(LREF Date) is in.
|
|
+/
|
|
@property ubyte daysInMonth() @safe const pure nothrow
|
|
{
|
|
return maxDay(_year, _month);
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(Date(1999, 1, 6).daysInMonth == 31);
|
|
assert(Date(1999, 2, 7).daysInMonth == 28);
|
|
assert(Date(2000, 2, 7).daysInMonth == 29);
|
|
assert(Date(2000, 6, 4).daysInMonth == 30);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
assert(Date(1999, 1, 1).daysInMonth == 31);
|
|
assert(Date(1999, 2, 1).daysInMonth == 28);
|
|
assert(Date(2000, 2, 1).daysInMonth == 29);
|
|
assert(Date(1999, 3, 1).daysInMonth == 31);
|
|
assert(Date(1999, 4, 1).daysInMonth == 30);
|
|
assert(Date(1999, 5, 1).daysInMonth == 31);
|
|
assert(Date(1999, 6, 1).daysInMonth == 30);
|
|
assert(Date(1999, 7, 1).daysInMonth == 31);
|
|
assert(Date(1999, 8, 1).daysInMonth == 31);
|
|
assert(Date(1999, 9, 1).daysInMonth == 30);
|
|
assert(Date(1999, 10, 1).daysInMonth == 31);
|
|
assert(Date(1999, 11, 1).daysInMonth == 30);
|
|
assert(Date(1999, 12, 1).daysInMonth == 31);
|
|
|
|
//Test B.C.
|
|
assert(Date(-1999, 1, 1).daysInMonth == 31);
|
|
assert(Date(-1999, 2, 1).daysInMonth == 28);
|
|
assert(Date(-2000, 2, 1).daysInMonth == 29);
|
|
assert(Date(-1999, 3, 1).daysInMonth == 31);
|
|
assert(Date(-1999, 4, 1).daysInMonth == 30);
|
|
assert(Date(-1999, 5, 1).daysInMonth == 31);
|
|
assert(Date(-1999, 6, 1).daysInMonth == 30);
|
|
assert(Date(-1999, 7, 1).daysInMonth == 31);
|
|
assert(Date(-1999, 8, 1).daysInMonth == 31);
|
|
assert(Date(-1999, 9, 1).daysInMonth == 30);
|
|
assert(Date(-1999, 10, 1).daysInMonth == 31);
|
|
assert(Date(-1999, 11, 1).daysInMonth == 30);
|
|
assert(Date(-1999, 12, 1).daysInMonth == 31);
|
|
|
|
const cdate = Date(1999, 7, 6);
|
|
immutable idate = Date(1999, 7, 6);
|
|
static assert(!__traits(compiles, cdate.daysInMonth = 30));
|
|
static assert(!__traits(compiles, idate.daysInMonth = 30));
|
|
}
|
|
|
|
|
|
/++
|
|
Whether the current year is a date in A.D.
|
|
+/
|
|
@property bool isAD() @safe const pure nothrow
|
|
{
|
|
return _year > 0;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(Date(1, 1, 1).isAD);
|
|
assert(Date(2010, 12, 31).isAD);
|
|
assert(!Date(0, 12, 31).isAD);
|
|
assert(!Date(-2010, 1, 1).isAD);
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
/++
|
|
The $(WEB en.wikipedia.org/wiki/Julian_day, Julian day) for this $(LREF Date) at noon (since the Julian day changes
|
|
at noon).
|
|
+/
|
|
@property long julianDay() @safe const pure nothrow
|
|
{
|
|
return dayOfGregorianCal + 1_721_425;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(Date(-4713, 11, 24).julianDay == 0);
|
|
assert(Date(0, 12, 31).julianDay == 1_721_425);
|
|
assert(Date(1, 1, 1).julianDay == 1_721_426);
|
|
assert(Date(1582, 10, 15).julianDay == 2_299_161);
|
|
assert(Date(1858, 11, 17).julianDay == 2_400_001);
|
|
assert(Date(1982, 1, 4).julianDay == 2_444_974);
|
|
assert(Date(1996, 3, 31).julianDay == 2_450_174);
|
|
assert(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 $(WEB en.wikipedia.org/wiki/Julian_day, Julian day) for any time on this date (since, the modified
|
|
Julian day changes at midnight).
|
|
+/
|
|
@property long modJulianDay() @safe const pure nothrow
|
|
{
|
|
return julianDay - 2_400_001;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(Date(1858, 11, 17).modJulianDay == 0);
|
|
assert(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 $(LREF Date) to a string with the format YYYYMMDD.
|
|
+/
|
|
string toISOString() @safe const pure nothrow
|
|
{
|
|
import std.format : format;
|
|
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
|
|
{
|
|
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");
|
|
}
|
|
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
assert(Date(9, 12, 4).toISOString() == "00091204");
|
|
assert(Date(99, 12, 4).toISOString() == "00991204");
|
|
assert(Date(999, 12, 4).toISOString() == "09991204");
|
|
assert(Date(9999, 7, 4).toISOString() == "99990704");
|
|
assert(Date(10000, 10, 20).toISOString() == "+100001020");
|
|
|
|
//Test B.C.
|
|
assert(Date(0, 12, 4).toISOString() == "00001204");
|
|
assert(Date(-9, 12, 4).toISOString() == "-00091204");
|
|
assert(Date(-99, 12, 4).toISOString() == "-00991204");
|
|
assert(Date(-999, 12, 4).toISOString() == "-09991204");
|
|
assert(Date(-9999, 7, 4).toISOString() == "-99990704");
|
|
assert(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()));
|
|
}
|
|
|
|
/++
|
|
Converts this $(LREF Date) to a string with the format YYYY-MM-DD.
|
|
+/
|
|
string toISOExtString() @safe const pure nothrow
|
|
{
|
|
import std.format : format;
|
|
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
|
|
{
|
|
assert(Date(2010, 7, 4).toISOExtString() == "2010-07-04");
|
|
assert(Date(1998, 12, 25).toISOExtString() == "1998-12-25");
|
|
assert(Date(0, 1, 5).toISOExtString() == "0000-01-05");
|
|
assert(Date(-4, 1, 5).toISOExtString() == "-0004-01-05");
|
|
}
|
|
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
assert(Date(9, 12, 4).toISOExtString() == "0009-12-04");
|
|
assert(Date(99, 12, 4).toISOExtString() == "0099-12-04");
|
|
assert(Date(999, 12, 4).toISOExtString() == "0999-12-04");
|
|
assert(Date(9999, 7, 4).toISOExtString() == "9999-07-04");
|
|
assert(Date(10000, 10, 20).toISOExtString() == "+10000-10-20");
|
|
|
|
//Test B.C.
|
|
assert(Date(0, 12, 4).toISOExtString() == "0000-12-04");
|
|
assert(Date(-9, 12, 4).toISOExtString() == "-0009-12-04");
|
|
assert(Date(-99, 12, 4).toISOExtString() == "-0099-12-04");
|
|
assert(Date(-999, 12, 4).toISOExtString() == "-0999-12-04");
|
|
assert(Date(-9999, 7, 4).toISOExtString() == "-9999-07-04");
|
|
assert(Date(-10000, 10, 20).toISOExtString() == "-10000-10-20");
|
|
|
|
const cdate = Date(1999, 7, 6);
|
|
immutable idate = Date(1999, 7, 6);
|
|
static assert(__traits(compiles, cdate.toISOExtString()));
|
|
static assert(__traits(compiles, idate.toISOExtString()));
|
|
}
|
|
|
|
/++
|
|
Converts this $(LREF Date) to a string with the format YYYY-Mon-DD.
|
|
+/
|
|
string toSimpleString() @safe const pure nothrow
|
|
{
|
|
import std.format : format;
|
|
try
|
|
{
|
|
if(_year >= 0)
|
|
{
|
|
if(_year < 10_000)
|
|
return format("%04d-%s-%02d", _year, monthToString(_month), _day);
|
|
else
|
|
return format("+%05d-%s-%02d", _year, monthToString(_month), _day);
|
|
}
|
|
else if(_year > -10_000)
|
|
return format("%05d-%s-%02d", _year, monthToString(_month), _day);
|
|
else
|
|
return format("%06d-%s-%02d", _year, monthToString(_month), _day);
|
|
}
|
|
catch(Exception e)
|
|
assert(0, "format() threw.");
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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");
|
|
}
|
|
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
assert(Date(9, 12, 4).toSimpleString() == "0009-Dec-04");
|
|
assert(Date(99, 12, 4).toSimpleString() == "0099-Dec-04");
|
|
assert(Date(999, 12, 4).toSimpleString() == "0999-Dec-04");
|
|
assert(Date(9999, 7, 4).toSimpleString() == "9999-Jul-04");
|
|
assert(Date(10000, 10, 20).toSimpleString() == "+10000-Oct-20");
|
|
|
|
//Test B.C.
|
|
assert(Date(0, 12, 4).toSimpleString() == "0000-Dec-04");
|
|
assert(Date(-9, 12, 4).toSimpleString() == "-0009-Dec-04");
|
|
assert(Date(-99, 12, 4).toSimpleString() == "-0099-Dec-04");
|
|
assert(Date(-999, 12, 4).toSimpleString() == "-0999-Dec-04");
|
|
assert(Date(-9999, 7, 4).toSimpleString() == "-9999-Jul-04");
|
|
assert(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()));
|
|
}
|
|
|
|
|
|
/++
|
|
Converts this $(LREF Date) to a string.
|
|
+/
|
|
string toString() @safe const pure 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 $(LREF 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:
|
|
$(LREF DateTimeException) if the given string is not in the ISO format
|
|
or if the resulting $(LREF Date) would not be valid.
|
|
+/
|
|
static Date fromISOString(S)(in S isoString) @safe pure
|
|
if(isSomeString!S)
|
|
{
|
|
import std.ascii : isDigit;
|
|
import std.string : strip;
|
|
import std.conv : to;
|
|
import std.algorithm : all, startsWith;
|
|
import std.format : format;
|
|
|
|
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(all!isDigit(day), new DateTimeException(format("Invalid ISO String: %s", isoString)));
|
|
enforce(all!isDigit(month), new DateTimeException(format("Invalid ISO String: %s", isoString)));
|
|
|
|
if(year.length > 4)
|
|
{
|
|
enforce(year.startsWith('-', '+'),
|
|
new DateTimeException(format("Invalid ISO String: %s", isoString)));
|
|
enforce(all!isDigit(year[1..$]),
|
|
new DateTimeException(format("Invalid ISO String: %s", isoString)));
|
|
}
|
|
else
|
|
enforce(all!isDigit(year), new DateTimeException(format("Invalid ISO String: %s", isoString)));
|
|
|
|
return Date(to!short(year), to!ubyte(month), to!ubyte(day));
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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));
|
|
}
|
|
|
|
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"));
|
|
|
|
assert(Date.fromISOString("19990706") == Date(1999, 7, 6));
|
|
assert(Date.fromISOString("-19990706") == Date(-1999, 7, 6));
|
|
assert(Date.fromISOString("+019990706") == Date(1999, 7, 6));
|
|
assert(Date.fromISOString("19990706 ") == Date(1999, 7, 6));
|
|
assert(Date.fromISOString(" 19990706") == Date(1999, 7, 6));
|
|
assert(Date.fromISOString(" 19990706 ") == Date(1999, 7, 6));
|
|
}
|
|
|
|
|
|
/++
|
|
Creates a $(LREF 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:
|
|
$(LREF DateTimeException) if the given string is not in the ISO
|
|
Extended format or if the resulting $(LREF Date) would not be valid.
|
|
+/
|
|
static Date fromISOExtString(S)(in S isoExtString) @safe pure
|
|
if(isSomeString!(S))
|
|
{
|
|
import std.ascii : isDigit;
|
|
import std.string : strip;
|
|
import std.conv : to;
|
|
import std.algorithm : all, startsWith;
|
|
import std.format : format;
|
|
|
|
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(all!isDigit(day),
|
|
new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
|
|
enforce(all!isDigit(month),
|
|
new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
|
|
|
|
if(year.length > 4)
|
|
{
|
|
enforce(year.startsWith('-', '+'),
|
|
new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
|
|
enforce(all!isDigit(year[1..$]),
|
|
new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
|
|
}
|
|
else
|
|
enforce(all!isDigit(year),
|
|
new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
|
|
|
|
return Date(to!short(year), to!ubyte(month), to!ubyte(day));
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(Date.fromISOExtString("2010-07-04") == Date(2010, 7, 4));
|
|
assert(Date.fromISOExtString("1998-12-25") == Date(1998, 12, 25));
|
|
assert(Date.fromISOExtString("0000-01-05") == Date(0, 1, 5));
|
|
assert(Date.fromISOExtString("-0004-01-05") == Date(-4, 1, 5));
|
|
assert(Date.fromISOExtString(" 2010-07-04 ") == Date(2010, 7, 4));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assertThrown!DateTimeException(Date.fromISOExtString(""));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("990704"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("0100704"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010070"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010070 "));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("120100704"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("-0100704"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("+0100704"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010070a"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("20100a04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010a704"));
|
|
|
|
assertThrown!DateTimeException(Date.fromISOExtString("99-07-04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("010-07-04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0 "));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("12010-07-04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("-010-07-04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("+010-07-04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0a"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010-0a-04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010-a7-04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010/07/04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010/7/04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010/7/4"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010/07/4"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010-7-04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010-7-4"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010-07-4"));
|
|
|
|
assertThrown!DateTimeException(Date.fromISOExtString("99Jul04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("010Jul04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0 "));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("12010Jul04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("-010Jul04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("+010Jul04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0a"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010Jua04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010aul04"));
|
|
|
|
assertThrown!DateTimeException(Date.fromISOExtString("99-Jul-04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("010-Jul-04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0 "));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("12010-Jul-04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("-010-Jul-04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("+010-Jul-04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0a"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010-Jua-04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010-Jal-04"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010-aul-04"));
|
|
|
|
assertThrown!DateTimeException(Date.fromISOExtString("20100704"));
|
|
assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-04"));
|
|
|
|
assert(Date.fromISOExtString("1999-07-06") == Date(1999, 7, 6));
|
|
assert(Date.fromISOExtString("-1999-07-06") == Date(-1999, 7, 6));
|
|
assert(Date.fromISOExtString("+01999-07-06") == Date(1999, 7, 6));
|
|
assert(Date.fromISOExtString("1999-07-06 ") == Date(1999, 7, 6));
|
|
assert(Date.fromISOExtString(" 1999-07-06") == Date(1999, 7, 6));
|
|
assert(Date.fromISOExtString(" 1999-07-06 ") == Date(1999, 7, 6));
|
|
}
|
|
|
|
|
|
/++
|
|
Creates a $(LREF 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:
|
|
$(LREF DateTimeException) if the given string is not in the correct
|
|
format or if the resulting $(LREF Date) would not be valid.
|
|
+/
|
|
static Date fromSimpleString(S)(in S simpleString) @safe pure
|
|
if(isSomeString!(S))
|
|
{
|
|
import std.ascii : isDigit;
|
|
import std.string : strip;
|
|
import std.conv : to;
|
|
import std.algorithm : all, startsWith;
|
|
import std.format : format;
|
|
|
|
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(all!isDigit(day), new DateTimeException(format("Invalid string format: %s", simpleString)));
|
|
|
|
if(year.length > 4)
|
|
{
|
|
enforce(year.startsWith('-', '+'),
|
|
new DateTimeException(format("Invalid string format: %s", simpleString)));
|
|
enforce(all!isDigit(year[1..$]),
|
|
new DateTimeException(format("Invalid string format: %s", simpleString)));
|
|
}
|
|
else
|
|
enforce(all!isDigit(year),
|
|
new DateTimeException(format("Invalid string format: %s", simpleString)));
|
|
|
|
return Date(to!short(year), month, to!ubyte(day));
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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));
|
|
}
|
|
|
|
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"));
|
|
|
|
assert(Date.fromSimpleString("1999-Jul-06") == Date(1999, 7, 6));
|
|
assert(Date.fromSimpleString("-1999-Jul-06") == Date(-1999, 7, 6));
|
|
assert(Date.fromSimpleString("+01999-Jul-06") == Date(1999, 7, 6));
|
|
assert(Date.fromSimpleString("1999-Jul-06 ") == Date(1999, 7, 6));
|
|
assert(Date.fromSimpleString(" 1999-Jul-06") == Date(1999, 7, 6));
|
|
assert(Date.fromSimpleString(" 1999-Jul-06 ") == Date(1999, 7, 6));
|
|
}
|
|
|
|
|
|
/++
|
|
Returns the $(LREF Date) farthest in the past which is representable by
|
|
$(LREF Date).
|
|
+/
|
|
@property static Date min() @safe 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 $(LREF Date) farthest in the future which is representable by
|
|
$(LREF Date).
|
|
+/
|
|
@property static Date max() @safe 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) @safe pure nothrow
|
|
{
|
|
if(!valid!"months"(month))
|
|
return false;
|
|
|
|
return valid!"days"(year, month, day);
|
|
}
|
|
|
|
/+
|
|
Adds the given number of days to this $(LREF 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.
|
|
|
|
$(D _addDays(numDays)) is effectively equivalent to
|
|
$(D date.dayOfGregorianCal = date.dayOfGregorianCal + days).
|
|
|
|
Params:
|
|
days = The number of days to add to this Date.
|
|
+/
|
|
ref Date _addDays(long days) return @safe pure nothrow
|
|
{
|
|
dayOfGregorianCal = cast(int)(dayOfGregorianCal + days);
|
|
return this;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
{
|
|
auto date = Date(1999, 2, 28);
|
|
date._addDays(1);
|
|
assert(date == Date(1999, 3, 1));
|
|
date._addDays(-1);
|
|
assert(date == Date(1999, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(2000, 2, 28);
|
|
date._addDays(1);
|
|
assert(date == Date(2000, 2, 29));
|
|
date._addDays(1);
|
|
assert(date == Date(2000, 3, 1));
|
|
date._addDays(-1);
|
|
assert(date == Date(2000, 2, 29));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 6, 30);
|
|
date._addDays(1);
|
|
assert(date == Date(1999, 7, 1));
|
|
date._addDays(-1);
|
|
assert(date == Date(1999, 6, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 7, 31);
|
|
date._addDays(1);
|
|
assert(date == Date(1999, 8, 1));
|
|
date._addDays(-1);
|
|
assert(date == Date(1999, 7, 31));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 1, 1);
|
|
date._addDays(-1);
|
|
assert(date == Date(1998, 12, 31));
|
|
date._addDays(1);
|
|
assert(date == Date(1999, 1, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
date._addDays(9);
|
|
assert(date == Date(1999, 7, 15));
|
|
date._addDays(-11);
|
|
assert(date == Date(1999, 7, 4));
|
|
date._addDays(30);
|
|
assert(date == Date(1999, 8, 3));
|
|
date._addDays(-3);
|
|
assert(date == Date(1999, 7, 31));
|
|
}
|
|
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
date._addDays(365);
|
|
assert(date == Date(2000, 7, 5));
|
|
date._addDays(-365);
|
|
assert(date == Date(1999, 7, 6));
|
|
date._addDays(366);
|
|
assert(date == Date(2000, 7, 6));
|
|
date._addDays(730);
|
|
assert(date == Date(2002, 7, 6));
|
|
date._addDays(-1096);
|
|
assert(date == Date(1999, 7, 6));
|
|
}
|
|
|
|
//Test B.C.
|
|
{
|
|
auto date = Date(-1999, 2, 28);
|
|
date._addDays(1);
|
|
assert(date == Date(-1999, 3, 1));
|
|
date._addDays(-1);
|
|
assert(date == Date(-1999, 2, 28));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-2000, 2, 28);
|
|
date._addDays(1);
|
|
assert(date == Date(-2000, 2, 29));
|
|
date._addDays(1);
|
|
assert(date == Date(-2000, 3, 1));
|
|
date._addDays(-1);
|
|
assert(date == Date(-2000, 2, 29));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 6, 30);
|
|
date._addDays(1);
|
|
assert(date == Date(-1999, 7, 1));
|
|
date._addDays(-1);
|
|
assert(date == Date(-1999, 6, 30));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 7, 31);
|
|
date._addDays(1);
|
|
assert(date == Date(-1999, 8, 1));
|
|
date._addDays(-1);
|
|
assert(date == Date(-1999, 7, 31));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 1, 1);
|
|
date._addDays(-1);
|
|
assert(date == Date(-2000, 12, 31));
|
|
date._addDays(1);
|
|
assert(date == Date(-1999, 1, 1));
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 7, 6);
|
|
date._addDays(9);
|
|
assert(date == Date(-1999, 7, 15));
|
|
date._addDays(-11);
|
|
assert(date == Date(-1999, 7, 4));
|
|
date._addDays(30);
|
|
assert(date == Date(-1999, 8, 3));
|
|
date._addDays(-3);
|
|
}
|
|
|
|
{
|
|
auto date = Date(-1999, 7, 6);
|
|
date._addDays(365);
|
|
assert(date == Date(-1998, 7, 6));
|
|
date._addDays(-365);
|
|
assert(date == Date(-1999, 7, 6));
|
|
date._addDays(366);
|
|
assert(date == Date(-1998, 7, 7));
|
|
date._addDays(730);
|
|
assert(date == Date(-1996, 7, 6));
|
|
date._addDays(-1096);
|
|
assert(date == Date(-1999, 7, 6));
|
|
}
|
|
|
|
//Test Both
|
|
{
|
|
auto date = Date(1, 7, 6);
|
|
date._addDays(-365);
|
|
assert(date == Date(0, 7, 6));
|
|
date._addDays(365);
|
|
assert(date == Date(1, 7, 6));
|
|
date._addDays(-731);
|
|
assert(date == Date(-1, 7, 6));
|
|
date._addDays(730);
|
|
assert(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)));
|
|
}
|
|
|
|
|
|
@safe pure invariant()
|
|
{
|
|
import std.format : format;
|
|
assert(valid!"months"(_month),
|
|
format("Invariant Failure: year [%s] month [%s] day [%s]", _year, _month, _day));
|
|
assert(valid!"days"(_year, _month, _day),
|
|
format("Invariant Failure: year [%s] month [%s] day [%s]", _year, _month, _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:
|
|
$(LREF DateTimeException) if the resulting $(LREF TimeOfDay) would be not
|
|
be valid.
|
|
+/
|
|
this(int hour, int minute, int second = 0) @safe 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);
|
|
assert(tod._hour == 0);
|
|
assert(tod._minute == 0);
|
|
assert(tod._second == 0);
|
|
}
|
|
|
|
{
|
|
auto tod = TimeOfDay(12, 30, 33);
|
|
assert(tod._hour == 12);
|
|
assert(tod._minute == 30);
|
|
assert(tod._second == 33);
|
|
}
|
|
|
|
{
|
|
auto tod = TimeOfDay(23, 59, 59);
|
|
assert(tod._hour == 23);
|
|
assert(tod._minute == 59);
|
|
assert(tod._second == 59);
|
|
}
|
|
|
|
assertThrown!DateTimeException(TimeOfDay(24, 0, 0));
|
|
assertThrown!DateTimeException(TimeOfDay(0, 60, 0));
|
|
assertThrown!DateTimeException(TimeOfDay(0, 0, 60));
|
|
}
|
|
|
|
|
|
/++
|
|
Compares this $(LREF TimeOfDay) with the given $(LREF TimeOfDay).
|
|
|
|
Returns:
|
|
$(BOOKTABLE,
|
|
$(TR $(TD this < rhs) $(TD < 0))
|
|
$(TR $(TD this == rhs) $(TD 0))
|
|
$(TR $(TD this > rhs) $(TD > 0))
|
|
)
|
|
+/
|
|
int opCmp(in TimeOfDay rhs) @safe 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
|
|
{
|
|
assert(TimeOfDay(0, 0, 0).opCmp(TimeOfDay.init) == 0);
|
|
|
|
assert(TimeOfDay(0, 0, 0).opCmp(TimeOfDay(0, 0, 0)) == 0);
|
|
assert(TimeOfDay(12, 0, 0).opCmp(TimeOfDay(12, 0, 0)) == 0);
|
|
assert(TimeOfDay(0, 30, 0).opCmp(TimeOfDay(0, 30, 0)) == 0);
|
|
assert(TimeOfDay(0, 0, 33).opCmp(TimeOfDay(0, 0, 33)) == 0);
|
|
|
|
assert(TimeOfDay(12, 30, 0).opCmp(TimeOfDay(12, 30, 0)) == 0);
|
|
assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 30, 33)) == 0);
|
|
|
|
assert(TimeOfDay(0, 30, 33).opCmp(TimeOfDay(0, 30, 33)) == 0);
|
|
assert(TimeOfDay(0, 0, 33).opCmp(TimeOfDay(0, 0, 33)) == 0);
|
|
|
|
assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(13, 30, 33)) < 0);
|
|
assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 30, 33)) > 0);
|
|
assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 31, 33)) < 0);
|
|
assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(12, 30, 33)) > 0);
|
|
assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 30, 34)) < 0);
|
|
assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(12, 30, 33)) > 0);
|
|
|
|
assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 30, 34)) > 0);
|
|
assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(13, 30, 33)) < 0);
|
|
assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 31, 33)) > 0);
|
|
assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(13, 30, 33)) < 0);
|
|
|
|
assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(12, 30, 34)) > 0);
|
|
assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(12, 31, 33)) < 0);
|
|
|
|
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 past midnight.
|
|
+/
|
|
@property ubyte hour() @safe const pure nothrow
|
|
{
|
|
return _hour;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(TimeOfDay.init.hour == 0);
|
|
assert(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 past midnight.
|
|
|
|
Params:
|
|
hour = The hour of the day to set this $(LREF TimeOfDay)'s hour to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given hour would result in an invalid
|
|
$(LREF TimeOfDay).
|
|
+/
|
|
@property void hour(int hour) @safe 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;
|
|
assert(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 past the hour.
|
|
+/
|
|
@property ubyte minute() @safe const pure nothrow
|
|
{
|
|
return _minute;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(TimeOfDay.init.minute == 0);
|
|
assert(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 past the hour.
|
|
|
|
Params:
|
|
minute = The minute to set this $(LREF TimeOfDay)'s minute to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given minute would result in an
|
|
invalid $(LREF TimeOfDay).
|
|
+/
|
|
@property void minute(int minute) @safe 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;
|
|
assert(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 past the minute.
|
|
+/
|
|
@property ubyte second() @safe const pure nothrow
|
|
{
|
|
return _second;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(TimeOfDay.init.second == 0);
|
|
assert(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 past the minute.
|
|
|
|
Params:
|
|
second = The second to set this $(LREF TimeOfDay)'s second to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given second would result in an
|
|
invalid $(LREF TimeOfDay).
|
|
+/
|
|
@property void second(int second) @safe 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;
|
|
assert(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 units to this $(LREF TimeOfDay). A negative number
|
|
will subtract.
|
|
|
|
The difference between rolling and adding is that rolling does not
|
|
affect larger units. For instance, rolling a $(LREF TimeOfDay)
|
|
one hours's worth of minutes gets the exact same
|
|
$(LREF TimeOfDay).
|
|
|
|
Accepted units are $(D "hours"), $(D "minutes"), and $(D "seconds").
|
|
|
|
Params:
|
|
units = The units to add.
|
|
value = The number of $(D_PARAM units) to add to this
|
|
$(LREF TimeOfDay).
|
|
+/
|
|
ref TimeOfDay roll(string units)(long value) @safe pure nothrow
|
|
if(units == "hours")
|
|
{
|
|
return this += dur!"hours"(value);
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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, 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(23, 59, 59);
|
|
tod5.roll!"seconds"(1);
|
|
assert(tod5 == TimeOfDay(23, 59, 0));
|
|
|
|
auto tod6 = TimeOfDay(0, 0, 0);
|
|
tod6.roll!"seconds"(-1);
|
|
assert(tod6 == TimeOfDay(0, 0, 59));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto tod = TimeOfDay(12, 27, 2);
|
|
tod.roll!"hours"(22).roll!"hours"(-7);
|
|
assert(tod == TimeOfDay(3, 27, 2));
|
|
|
|
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)));
|
|
}
|
|
|
|
|
|
//Shares documentation with "hours" version.
|
|
ref TimeOfDay roll(string units)(long value) @safe pure nothrow
|
|
if(units == "minutes" ||
|
|
units == "seconds")
|
|
{
|
|
import std.format : format;
|
|
|
|
enum memberVarStr = units[0 .. $ - 1];
|
|
value %= 60;
|
|
mixin(format("auto newVal = cast(ubyte)(_%s) + value;", memberVarStr));
|
|
|
|
if(value < 0)
|
|
{
|
|
if(newVal < 0)
|
|
newVal += 60;
|
|
}
|
|
else if(newVal >= 60)
|
|
newVal -= 60;
|
|
|
|
mixin(format("_%s = cast(ubyte)newVal;", memberVarStr));
|
|
return this;
|
|
}
|
|
|
|
//Test roll!"minutes"().
|
|
unittest
|
|
{
|
|
static void testTOD(TimeOfDay orig, int minutes, in TimeOfDay expected, size_t line = __LINE__)
|
|
{
|
|
orig.roll!"minutes"(minutes);
|
|
assert(orig == expected);
|
|
}
|
|
|
|
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));
|
|
|
|
auto tod = TimeOfDay(12, 27, 2);
|
|
tod.roll!"minutes"(97).roll!"minutes"(-102);
|
|
assert(tod == TimeOfDay(12, 22, 2));
|
|
|
|
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)));
|
|
}
|
|
|
|
//Test roll!"seconds"().
|
|
unittest
|
|
{
|
|
static void testTOD(TimeOfDay orig, int seconds, in TimeOfDay expected, size_t line = __LINE__)
|
|
{
|
|
orig.roll!"seconds"(seconds);
|
|
assert(orig == expected);
|
|
}
|
|
|
|
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));
|
|
|
|
auto tod = TimeOfDay(12, 27, 2);
|
|
tod.roll!"seconds"(105).roll!"seconds"(-77);
|
|
assert(tod == TimeOfDay(12, 27, 30));
|
|
|
|
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
|
|
$(LREF TimeOfDay).
|
|
|
|
The legal types of arithmetic for $(LREF TimeOfDay) using this operator are
|
|
|
|
$(BOOKTABLE,
|
|
$(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
|
|
$(LREF TimeOfDay).
|
|
+/
|
|
TimeOfDay opBinary(string op, D)(in D duration) @safe const pure nothrow
|
|
if((op == "+" || op == "-") &&
|
|
(is(Unqual!D == Duration) ||
|
|
is(Unqual!D == TickDuration)))
|
|
{
|
|
import std.format : format;
|
|
|
|
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;
|
|
|
|
mixin(format(`return retval._addSeconds(convert!("hnsecs", "seconds")(%shnsecs));`, op));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto tod = TimeOfDay(12, 30, 33);
|
|
|
|
assert(tod + dur!"hours"(7) == TimeOfDay(19, 30, 33));
|
|
assert(tod + dur!"hours"(-7) == TimeOfDay(5, 30, 33));
|
|
assert(tod + dur!"minutes"(7) == TimeOfDay(12, 37, 33));
|
|
assert(tod + dur!"minutes"(-7) == TimeOfDay(12, 23, 33));
|
|
assert(tod + dur!"seconds"(7) == TimeOfDay(12, 30, 40));
|
|
assert(tod + dur!"seconds"(-7) == TimeOfDay(12, 30, 26));
|
|
|
|
assert(tod + dur!"msecs"(7000) == TimeOfDay(12, 30, 40));
|
|
assert(tod + dur!"msecs"(-7000) == TimeOfDay(12, 30, 26));
|
|
assert(tod + dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 40));
|
|
assert(tod + dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 26));
|
|
assert(tod + dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 40));
|
|
assert(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)
|
|
{
|
|
assert(tod + TickDuration.from!"usecs"(7_000_000) == TimeOfDay(12, 30, 40));
|
|
assert(tod + TickDuration.from!"usecs"(-7_000_000) == TimeOfDay(12, 30, 26));
|
|
}
|
|
|
|
assert(tod - dur!"hours"(-7) == TimeOfDay(19, 30, 33));
|
|
assert(tod - dur!"hours"(7) == TimeOfDay(5, 30, 33));
|
|
assert(tod - dur!"minutes"(-7) == TimeOfDay(12, 37, 33));
|
|
assert(tod - dur!"minutes"(7) == TimeOfDay(12, 23, 33));
|
|
assert(tod - dur!"seconds"(-7) == TimeOfDay(12, 30, 40));
|
|
assert(tod - dur!"seconds"(7) == TimeOfDay(12, 30, 26));
|
|
|
|
assert(tod - dur!"msecs"(-7000) == TimeOfDay(12, 30, 40));
|
|
assert(tod - dur!"msecs"(7000) == TimeOfDay(12, 30, 26));
|
|
assert(tod - dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 40));
|
|
assert(tod - dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 26));
|
|
assert(tod - dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 40));
|
|
assert(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)
|
|
{
|
|
assert(tod - TickDuration.from!"usecs"(-7_000_000) == TimeOfDay(12, 30, 40));
|
|
assert(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
|
|
$(LREF TimeOfDay), as well as assigning the result to this
|
|
$(LREF TimeOfDay).
|
|
|
|
The legal types of arithmetic for $(LREF TimeOfDay) using this operator are
|
|
|
|
$(BOOKTABLE,
|
|
$(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
|
|
$(LREF TimeOfDay).
|
|
+/
|
|
ref TimeOfDay opOpAssign(string op, D)(in D duration) @safe pure nothrow
|
|
if((op == "+" || op == "-") &&
|
|
(is(Unqual!D == Duration) ||
|
|
is(Unqual!D == TickDuration)))
|
|
{
|
|
import std.format : format;
|
|
static if(is(Unqual!D == Duration))
|
|
immutable hnsecs = duration.total!"hnsecs";
|
|
else static if(is(Unqual!D == TickDuration))
|
|
immutable hnsecs = duration.hnsecs;
|
|
|
|
mixin(format(`return _addSeconds(convert!("hnsecs", "seconds")(%shnsecs));`, op));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto duration = dur!"hours"(12);
|
|
|
|
assert(TimeOfDay(12, 30, 33) + dur!"hours"(7) == TimeOfDay(19, 30, 33));
|
|
assert(TimeOfDay(12, 30, 33) + dur!"hours"(-7) == TimeOfDay(5, 30, 33));
|
|
assert(TimeOfDay(12, 30, 33) + dur!"minutes"(7) == TimeOfDay(12, 37, 33));
|
|
assert(TimeOfDay(12, 30, 33) + dur!"minutes"(-7) == TimeOfDay(12, 23, 33));
|
|
assert(TimeOfDay(12, 30, 33) + dur!"seconds"(7) == TimeOfDay(12, 30, 40));
|
|
assert(TimeOfDay(12, 30, 33) + dur!"seconds"(-7) == TimeOfDay(12, 30, 26));
|
|
|
|
assert(TimeOfDay(12, 30, 33) + dur!"msecs"(7000) == TimeOfDay(12, 30, 40));
|
|
assert(TimeOfDay(12, 30, 33) + dur!"msecs"(-7000) == TimeOfDay(12, 30, 26));
|
|
assert(TimeOfDay(12, 30, 33) + dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 40));
|
|
assert(TimeOfDay(12, 30, 33) + dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 26));
|
|
assert(TimeOfDay(12, 30, 33) + dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 40));
|
|
assert(TimeOfDay(12, 30, 33) + dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 26));
|
|
|
|
assert(TimeOfDay(12, 30, 33) - dur!"hours"(-7) == TimeOfDay(19, 30, 33));
|
|
assert(TimeOfDay(12, 30, 33) - dur!"hours"(7) == TimeOfDay(5, 30, 33));
|
|
assert(TimeOfDay(12, 30, 33) - dur!"minutes"(-7) == TimeOfDay(12, 37, 33));
|
|
assert(TimeOfDay(12, 30, 33) - dur!"minutes"(7) == TimeOfDay(12, 23, 33));
|
|
assert(TimeOfDay(12, 30, 33) - dur!"seconds"(-7) == TimeOfDay(12, 30, 40));
|
|
assert(TimeOfDay(12, 30, 33) - dur!"seconds"(7) == TimeOfDay(12, 30, 26));
|
|
|
|
assert(TimeOfDay(12, 30, 33) - dur!"msecs"(-7000) == TimeOfDay(12, 30, 40));
|
|
assert(TimeOfDay(12, 30, 33) - dur!"msecs"(7000) == TimeOfDay(12, 30, 26));
|
|
assert(TimeOfDay(12, 30, 33) - dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 40));
|
|
assert(TimeOfDay(12, 30, 33) - dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 26));
|
|
assert(TimeOfDay(12, 30, 33) - dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 40));
|
|
assert(TimeOfDay(12, 30, 33) - dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 26));
|
|
|
|
auto tod = TimeOfDay(19, 17, 22);
|
|
(tod += dur!"seconds"(9)) += dur!"seconds"(-7292);
|
|
assert(tod == TimeOfDay(17, 15, 59));
|
|
|
|
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 $(LREF TimeOfDay)s.
|
|
|
|
The legal types of arithmetic for $(LREF TimeOfDay) using this operator are
|
|
|
|
$(BOOKTABLE,
|
|
$(TR $(TD TimeOfDay) $(TD -) $(TD TimeOfDay) $(TD -->) $(TD duration))
|
|
)
|
|
|
|
Params:
|
|
rhs = The $(LREF TimeOfDay) to subtract from this one.
|
|
+/
|
|
Duration opBinary(string op)(in TimeOfDay rhs) @safe 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);
|
|
|
|
assert(TimeOfDay(7, 12, 52) - TimeOfDay(12, 30, 33) == dur!"seconds"(-19_061));
|
|
assert(TimeOfDay(12, 30, 33) - TimeOfDay(7, 12, 52) == dur!"seconds"(19_061));
|
|
assert(TimeOfDay(12, 30, 33) - TimeOfDay(14, 30, 33) == dur!"seconds"(-7200));
|
|
assert(TimeOfDay(14, 30, 33) - TimeOfDay(12, 30, 33) == dur!"seconds"(7200));
|
|
assert(TimeOfDay(12, 30, 33) - TimeOfDay(12, 34, 33) == dur!"seconds"(-240));
|
|
assert(TimeOfDay(12, 34, 33) - TimeOfDay(12, 30, 33) == dur!"seconds"(240));
|
|
assert(TimeOfDay(12, 30, 33) - TimeOfDay(12, 30, 34) == dur!"seconds"(-1));
|
|
assert(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 $(LREF TimeOfDay) to a string with the format HHMMSS.
|
|
+/
|
|
string toISOString() @safe const pure nothrow
|
|
{
|
|
import std.format : format;
|
|
try
|
|
return format("%02d%02d%02d", _hour, _minute, _second);
|
|
catch(Exception e)
|
|
assert(0, "format() threw.");
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(TimeOfDay(0, 0, 0).toISOString() == "000000");
|
|
assert(TimeOfDay(12, 30, 33).toISOString() == "123033");
|
|
}
|
|
|
|
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()));
|
|
}
|
|
|
|
|
|
/++
|
|
Converts this $(LREF TimeOfDay) to a string with the format HH:MM:SS.
|
|
+/
|
|
string toISOExtString() @safe const pure nothrow
|
|
{
|
|
import std.format : format;
|
|
try
|
|
return format("%02d:%02d:%02d", _hour, _minute, _second);
|
|
catch(Exception e)
|
|
assert(0, "format() threw.");
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(TimeOfDay(0, 0, 0).toISOExtString() == "00:00:00");
|
|
assert(TimeOfDay(12, 30, 33).toISOExtString() == "12:30:33");
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto tod = TimeOfDay(12, 30, 33);
|
|
const ctod = TimeOfDay(12, 30, 33);
|
|
immutable itod = TimeOfDay(12, 30, 33);
|
|
static assert(__traits(compiles, tod.toISOExtString()));
|
|
static assert(__traits(compiles, ctod.toISOExtString()));
|
|
static assert(__traits(compiles, itod.toISOExtString()));
|
|
}
|
|
|
|
|
|
/++
|
|
Converts this TimeOfDay to a string.
|
|
+/
|
|
string toString() @safe const pure nothrow
|
|
{
|
|
return toISOExtString();
|
|
}
|
|
|
|
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()));
|
|
}
|
|
|
|
|
|
/++
|
|
Creates a $(LREF 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:
|
|
$(LREF DateTimeException) if the given string is not in the ISO format
|
|
or if the resulting $(LREF TimeOfDay) would not be valid.
|
|
+/
|
|
static TimeOfDay fromISOString(S)(in S isoString) @safe pure
|
|
if(isSomeString!S)
|
|
{
|
|
import std.ascii : isDigit;
|
|
import std.string : strip;
|
|
import std.conv : to;
|
|
import std.algorithm : all;
|
|
import std.format : format;
|
|
|
|
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(all!isDigit(hours), new DateTimeException(format("Invalid ISO String: %s", isoString)));
|
|
enforce(all!isDigit(minutes), new DateTimeException(format("Invalid ISO String: %s", isoString)));
|
|
enforce(all!isDigit(seconds), new DateTimeException(format("Invalid ISO String: %s", isoString)));
|
|
|
|
return TimeOfDay(to!int(hours), to!int(minutes), to!int(seconds));
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(TimeOfDay.fromISOString("000000") == TimeOfDay(0, 0, 0));
|
|
assert(TimeOfDay.fromISOString("123033") == TimeOfDay(12, 30, 33));
|
|
assert(TimeOfDay.fromISOString(" 123033 ") == TimeOfDay(12, 30, 33));
|
|
}
|
|
|
|
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"));
|
|
|
|
assert(TimeOfDay.fromISOString("011217") == TimeOfDay(1, 12, 17));
|
|
assert(TimeOfDay.fromISOString("001412") == TimeOfDay(0, 14, 12));
|
|
assert(TimeOfDay.fromISOString("000007") == TimeOfDay(0, 0, 7));
|
|
assert(TimeOfDay.fromISOString("011217 ") == TimeOfDay(1, 12, 17));
|
|
assert(TimeOfDay.fromISOString(" 011217") == TimeOfDay(1, 12, 17));
|
|
assert(TimeOfDay.fromISOString(" 011217 ") == TimeOfDay(1, 12, 17));
|
|
}
|
|
|
|
|
|
/++
|
|
Creates a $(LREF TimeOfDay) from a string with the format HH:MM:SS.
|
|
Whitespace is stripped from the given string.
|
|
|
|
Params:
|
|
isoExtString = A string formatted in the ISO Extended format for times.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given string is not in the ISO
|
|
Extended format or if the resulting $(LREF TimeOfDay) would not be
|
|
valid.
|
|
+/
|
|
static TimeOfDay fromISOExtString(S)(in S isoExtString) @safe pure
|
|
if(isSomeString!S)
|
|
{
|
|
import std.ascii : isDigit;
|
|
import std.string : strip;
|
|
import std.conv : to;
|
|
import std.algorithm : all;
|
|
import std.format : format;
|
|
|
|
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(all!isDigit(hours),
|
|
new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
|
|
enforce(all!isDigit(minutes),
|
|
new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
|
|
enforce(all!isDigit(seconds),
|
|
new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
|
|
|
|
return TimeOfDay(to!int(hours), to!int(minutes), to!int(seconds));
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(TimeOfDay.fromISOExtString("00:00:00") == TimeOfDay(0, 0, 0));
|
|
assert(TimeOfDay.fromISOExtString("12:30:33") == TimeOfDay(12, 30, 33));
|
|
assert(TimeOfDay.fromISOExtString(" 12:30:33 ") == TimeOfDay(12, 30, 33));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString(""));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("000"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0000"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00000"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("13033"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1277"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12707"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12070"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12303a"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1230a3"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("123a33"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12a033"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1a0033"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("a20033"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1200330"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0120033"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("-120033"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("+120033"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033am"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033pm"));
|
|
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0::"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString(":0:"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("::0"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:0:0"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:0:00"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:00:0"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:0:0"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:00:0"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:0:00"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("13:0:33"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:7:7"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:7:07"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:07:0"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:30:3a"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:30:a3"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:3a:33"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:a0:33"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1a:00:33"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("a2:00:33"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:003:30"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120:03:30"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("012:00:33"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("01:200:33"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("-12:00:33"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("+12:00:33"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:00:33am"));
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:00:33pm"));
|
|
|
|
assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033"));
|
|
|
|
assert(TimeOfDay.fromISOExtString("01:12:17") == TimeOfDay(1, 12, 17));
|
|
assert(TimeOfDay.fromISOExtString("00:14:12") == TimeOfDay(0, 14, 12));
|
|
assert(TimeOfDay.fromISOExtString("00:00:07") == TimeOfDay(0, 0, 7));
|
|
assert(TimeOfDay.fromISOExtString("01:12:17 ") == TimeOfDay(1, 12, 17));
|
|
assert(TimeOfDay.fromISOExtString(" 01:12:17") == TimeOfDay(1, 12, 17));
|
|
assert(TimeOfDay.fromISOExtString(" 01:12:17 ") == TimeOfDay(1, 12, 17));
|
|
}
|
|
|
|
|
|
/++
|
|
Returns midnight.
|
|
+/
|
|
@property static TimeOfDay min() @safe 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() @safe 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) return @safe 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);
|
|
assert(orig == expected);
|
|
}
|
|
|
|
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 $(LREF TimeOfDay).
|
|
+/
|
|
static bool _valid(int hour, int minute, int second) @safe pure nothrow
|
|
{
|
|
return valid!"hours"(hour) && valid!"minutes"(minute) && valid!"seconds"(second);
|
|
}
|
|
|
|
|
|
@safe pure invariant()
|
|
{
|
|
import std.format : format;
|
|
assert(_valid(_hour, _minute, _second),
|
|
format("Invariant Failure: hour [%s] minute [%s] second [%s]", _hour, _minute, _second));
|
|
}
|
|
|
|
ubyte _hour;
|
|
ubyte _minute;
|
|
ubyte _second;
|
|
|
|
enum ubyte maxHour = 24 - 1;
|
|
enum ubyte maxMinute = 60 - 1;
|
|
enum ubyte maxSecond = 60 - 1;
|
|
}
|
|
|
|
|
|
/++
|
|
Combines the $(LREF Date) and $(LREF TimeOfDay) structs to give an object
|
|
which holds both the date and the time. It is optimized for calendar-based
|
|
operations and has no concept of time zone. For an object which is
|
|
optimized for time operations based on the system time, use
|
|
$(LREF SysTime). $(LREF SysTime) has a concept of time zone and has much higher
|
|
precision (hnsecs). $(D DateTime) is intended primarily for calendar-based
|
|
uses rather than precise time operations.
|
|
+/
|
|
struct DateTime
|
|
{
|
|
public:
|
|
|
|
/++
|
|
Params:
|
|
date = The date portion of $(LREF DateTime).
|
|
tod = The time portion of $(LREF DateTime).
|
|
+/
|
|
this(in Date date, in TimeOfDay tod = TimeOfDay.init) @safe pure nothrow
|
|
{
|
|
_date = date;
|
|
_tod = tod;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
{
|
|
auto dt = DateTime.init;
|
|
assert(dt._date == Date.init);
|
|
assert(dt._tod == TimeOfDay.init);
|
|
}
|
|
|
|
{
|
|
auto dt = DateTime(Date(1999, 7 ,6));
|
|
assert(dt._date == Date(1999, 7, 6));
|
|
assert(dt._tod == TimeOfDay.init);
|
|
}
|
|
|
|
{
|
|
auto dt = DateTime(Date(1999, 7 ,6), TimeOfDay(12, 30, 33));
|
|
assert(dt._date == Date(1999, 7, 6));
|
|
assert(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) @safe pure
|
|
{
|
|
_date = Date(year, month, day);
|
|
_tod = TimeOfDay(hour, minute, second);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
{
|
|
auto dt = DateTime(1999, 7 ,6);
|
|
assert(dt._date == Date(1999, 7, 6));
|
|
assert(dt._tod == TimeOfDay.init);
|
|
}
|
|
|
|
{
|
|
auto dt = DateTime(1999, 7 ,6, 12, 30, 33);
|
|
assert(dt._date == Date(1999, 7, 6));
|
|
assert(dt._tod == TimeOfDay(12, 30, 33));
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
Compares this $(LREF DateTime) with the given $(D DateTime.).
|
|
|
|
Returns:
|
|
$(BOOKTABLE,
|
|
$(TR $(TD this < rhs) $(TD < 0))
|
|
$(TR $(TD this == rhs) $(TD 0))
|
|
$(TR $(TD this > rhs) $(TD > 0))
|
|
)
|
|
+/
|
|
int opCmp(in DateTime rhs) @safe const pure nothrow
|
|
{
|
|
immutable dateResult = _date.opCmp(rhs._date);
|
|
|
|
if(dateResult != 0)
|
|
return dateResult;
|
|
|
|
return _tod.opCmp(rhs._tod);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
assert(DateTime(Date.init, TimeOfDay.init).opCmp(DateTime.init) == 0);
|
|
|
|
assert(DateTime(Date(1999, 1, 1)).opCmp(DateTime(Date(1999, 1, 1))) == 0);
|
|
assert(DateTime(Date(1, 7, 1)).opCmp(DateTime(Date(1, 7, 1))) == 0);
|
|
assert(DateTime(Date(1, 1, 6)).opCmp(DateTime(Date(1, 1, 6))) == 0);
|
|
|
|
assert(DateTime(Date(1999, 7, 1)).opCmp(DateTime(Date(1999, 7, 1))) == 0);
|
|
assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(1999, 7, 6))) == 0);
|
|
|
|
assert(DateTime(Date(1, 7, 6)).opCmp(DateTime(Date(1, 7, 6))) == 0);
|
|
|
|
assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(2000, 7, 6))) < 0);
|
|
assert(DateTime(Date(2000, 7, 6)).opCmp(DateTime(Date(1999, 7, 6))) > 0);
|
|
assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(1999, 8, 6))) < 0);
|
|
assert(DateTime(Date(1999, 8, 6)).opCmp(DateTime(Date(1999, 7, 6))) > 0);
|
|
assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(1999, 7, 7))) < 0);
|
|
assert(DateTime(Date(1999, 7, 7)).opCmp(DateTime(Date(1999, 7, 6))) > 0);
|
|
|
|
assert(DateTime(Date(1999, 8, 7)).opCmp(DateTime(Date(2000, 7, 6))) < 0);
|
|
assert(DateTime(Date(2000, 8, 6)).opCmp(DateTime(Date(1999, 7, 7))) > 0);
|
|
assert(DateTime(Date(1999, 7, 7)).opCmp(DateTime(Date(2000, 7, 6))) < 0);
|
|
assert(DateTime(Date(2000, 7, 6)).opCmp(DateTime(Date(1999, 7, 7))) > 0);
|
|
assert(DateTime(Date(1999, 7, 7)).opCmp(DateTime(Date(1999, 8, 6))) < 0);
|
|
assert(DateTime(Date(1999, 8, 6)).opCmp(DateTime(Date(1999, 7, 7))) > 0);
|
|
|
|
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0))) == 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0))) == 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 0)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 0))) == 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))) == 0);
|
|
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))) == 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) == 0);
|
|
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))) == 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))) == 0);
|
|
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) < 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) < 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) < 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0);
|
|
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) < 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) > 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) < 0);
|
|
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) < 0);
|
|
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp(
|
|
DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))) < 0);
|
|
assert(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) > 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp(
|
|
DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))) < 0);
|
|
assert(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) > 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp(
|
|
DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))) < 0);
|
|
assert(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0);
|
|
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))) < 0);
|
|
assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) > 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp(
|
|
DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))) < 0);
|
|
assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) > 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp(
|
|
DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))) < 0);
|
|
assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0);
|
|
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33))) < 0);
|
|
assert(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) > 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 7), TimeOfDay(12, 31, 33))) < 0);
|
|
assert(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp(
|
|
DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33))) < 0);
|
|
assert(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0);
|
|
|
|
//Test B.C.
|
|
assert(DateTime(Date(-1, 1, 1), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1, 1, 1), TimeOfDay(12, 30, 33))) == 0);
|
|
assert(DateTime(Date(-1, 7, 1), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1, 7, 1), TimeOfDay(12, 30, 33))) == 0);
|
|
assert(DateTime(Date(-1, 1, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1, 1, 6), TimeOfDay(12, 30, 33))) == 0);
|
|
|
|
assert(DateTime(Date(-1999, 7, 1), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1999, 7, 1), TimeOfDay(12, 30, 33))) == 0);
|
|
assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) == 0);
|
|
|
|
assert(DateTime(Date(-1, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1, 7, 6), TimeOfDay(12, 30, 33))) == 0);
|
|
|
|
assert(DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) < 0);
|
|
assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))) > 0);
|
|
assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))) < 0);
|
|
assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0);
|
|
assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) < 0);
|
|
assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0);
|
|
|
|
assert(DateTime(Date(-2000, 8, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) < 0);
|
|
assert(DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))) > 0);
|
|
assert(DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) < 0);
|
|
assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))) > 0);
|
|
assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))) < 0);
|
|
assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) > 0);
|
|
|
|
//Test Both
|
|
assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0);
|
|
|
|
assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))) > 0);
|
|
|
|
assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) > 0);
|
|
|
|
assert(DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33))) > 0);
|
|
|
|
assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(1999, 6, 6), TimeOfDay(12, 30, 33))) < 0);
|
|
assert(DateTime(Date(1999, 6, 8), TimeOfDay(12, 30, 33)).opCmp(
|
|
DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0);
|
|
|
|
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 $(LREF DateTime).
|
|
+/
|
|
@property Date date() @safe const pure nothrow
|
|
{
|
|
return _date;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
{
|
|
auto dt = DateTime.init;
|
|
assert(dt.date == Date.init);
|
|
}
|
|
|
|
{
|
|
auto dt = DateTime(Date(1999, 7, 6));
|
|
assert(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 $(LREF DateTime).
|
|
|
|
Params:
|
|
date = The Date to set this $(LREF DateTime)'s date portion to.
|
|
+/
|
|
@property void date(in Date date) @safe pure nothrow
|
|
{
|
|
_date = date;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto dt = DateTime.init;
|
|
dt.date = Date(1999, 7, 6);
|
|
assert(dt._date == Date(1999, 7, 6));
|
|
assert(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 $(LREF DateTime).
|
|
+/
|
|
@property TimeOfDay timeOfDay() @safe const pure nothrow
|
|
{
|
|
return _tod;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
{
|
|
auto dt = DateTime.init;
|
|
assert(dt.timeOfDay == TimeOfDay.init);
|
|
}
|
|
|
|
{
|
|
auto dt = DateTime(Date.init, TimeOfDay(12, 30, 33));
|
|
assert(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 $(LREF DateTime).
|
|
|
|
Params:
|
|
tod = The $(LREF TimeOfDay) to set this $(LREF DateTime)'s time portion
|
|
to.
|
|
+/
|
|
@property void timeOfDay(in TimeOfDay tod) @safe pure nothrow
|
|
{
|
|
_tod = tod;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto dt = DateTime.init;
|
|
dt.timeOfDay = TimeOfDay(12, 30, 33);
|
|
assert(dt._date == Date.init);
|
|
assert(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() @safe const pure nothrow
|
|
{
|
|
return _date.year;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(Date.init.year == 1);
|
|
assert(Date(1999, 7, 6).year == 1999);
|
|
assert(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 $(LREF DateTime)'s year to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the new year is not a leap year and if the
|
|
resulting date would be on February 29th.
|
|
+/
|
|
@property void year(int year) @safe pure
|
|
{
|
|
_date.year = year;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
static void testDT(DateTime dt, int year, in DateTime expected, size_t line = __LINE__)
|
|
{
|
|
dt.year = year;
|
|
assert(dt == expected);
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
/++
|
|
Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if $(D isAD) is true.
|
|
+/
|
|
@property short yearBC() @safe const pure
|
|
{
|
|
return _date.yearBC;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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);
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
/++
|
|
Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
|
|
|
|
Params:
|
|
year = The year B.C. to set this $(LREF DateTime)'s year to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if a non-positive value is given.
|
|
+/
|
|
@property void yearBC(int year) @safe pure
|
|
{
|
|
_date.yearBC = year;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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)));
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
/++
|
|
Month of a Gregorian Year.
|
|
+/
|
|
@property Month month() @safe const pure nothrow
|
|
{
|
|
return _date.month;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(DateTime.init.month == 1);
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).month == 7);
|
|
assert(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));
|
|
}
|
|
|
|
|
|
/++
|
|
Month of a Gregorian Year.
|
|
|
|
Params:
|
|
month = The month to set this $(LREF DateTime)'s month to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given month is not a valid month.
|
|
+/
|
|
@property void month(Month month) @safe 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);
|
|
assert(dt == expected);
|
|
}
|
|
|
|
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.
|
|
+/
|
|
@property ubyte day() @safe const pure nothrow
|
|
{
|
|
return _date.day;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.range;
|
|
import std.format : format;
|
|
|
|
static void test(DateTime dateTime, int expected)
|
|
{
|
|
assert(dateTime.day == expected, format("Value given: %s", dateTime));
|
|
}
|
|
|
|
foreach(year; chain(testYearsBC, testYearsAD))
|
|
{
|
|
foreach(md; testMonthDays)
|
|
{
|
|
foreach(tod; testTODs)
|
|
test(DateTime(Date(year, md.month, md.day), tod), md.day);
|
|
}
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
/++
|
|
Day of a Gregorian Month.
|
|
|
|
Params:
|
|
day = The day of the month to set this $(LREF DateTime)'s day to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given day is not a valid day of the
|
|
current month.
|
|
+/
|
|
@property void day(int day) @safe 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;
|
|
assert(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;
|
|
assert(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 past midnight.
|
|
+/
|
|
@property ubyte hour() @safe const pure nothrow
|
|
{
|
|
return _tod.hour;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(DateTime.init.hour == 0);
|
|
assert(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 past midnight.
|
|
|
|
Params:
|
|
hour = The hour of the day to set this $(LREF DateTime)'s hour to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given hour would result in an invalid
|
|
$(LREF DateTime).
|
|
+/
|
|
@property void hour(int hour) @safe 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;
|
|
assert(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 past the hour.
|
|
+/
|
|
@property ubyte minute() @safe const pure nothrow
|
|
{
|
|
return _tod.minute;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(DateTime.init.minute == 0);
|
|
assert(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 past the hour.
|
|
|
|
Params:
|
|
minute = The minute to set this $(LREF DateTime)'s minute to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given minute would result in an
|
|
invalid $(LREF DateTime).
|
|
+/
|
|
@property void minute(int minute) @safe pure
|
|
{
|
|
_tod.minute = minute;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assertThrown!DateTimeException((){DateTime.init.minute = 60;}());
|
|
|
|
auto dt = DateTime.init;
|
|
dt.minute = 30;
|
|
assert(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 past the minute.
|
|
+/
|
|
@property ubyte second() @safe const pure nothrow
|
|
{
|
|
return _tod.second;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(DateTime.init.second == 0);
|
|
assert(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 past the minute.
|
|
|
|
Params:
|
|
second = The second to set this $(LREF DateTime)'s second to.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given seconds would result in an
|
|
invalid $(LREF DateTime).
|
|
+/
|
|
@property void second(int second) @safe pure
|
|
{
|
|
_tod.second = second;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assertThrown!DateTimeException((){DateTime.init.second = 60;}());
|
|
|
|
auto dt = DateTime.init;
|
|
dt.second = 33;
|
|
assert(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 $(LREF 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 day 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
|
|
$(LREF DateTime).
|
|
allowOverflow = Whether the days should be allowed to overflow,
|
|
causing the month to increment.
|
|
+/
|
|
ref DateTime add(string units)
|
|
(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow
|
|
if(units == "years" ||
|
|
units == "months")
|
|
{
|
|
_date.add!units(value, allowOverflow);
|
|
return this;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
auto dt1 = DateTime(2010, 1, 1, 12, 30, 33);
|
|
dt1.add!"months"(11);
|
|
assert(dt1 == DateTime(2010, 12, 1, 12, 30, 33));
|
|
|
|
auto dt2 = DateTime(2010, 1, 1, 12, 30, 33);
|
|
dt2.add!"months"(-11);
|
|
assert(dt2 == DateTime(2009, 2, 1, 12, 30, 33));
|
|
|
|
auto dt3 = DateTime(2000, 2, 29, 12, 30, 33);
|
|
dt3.add!"years"(1);
|
|
assert(dt3 == DateTime(2001, 3, 1, 12, 30, 33));
|
|
|
|
auto dt4 = DateTime(2000, 2, 29, 12, 30, 33);
|
|
dt4.add!"years"(1, AllowDayOverflow.no);
|
|
assert(dt4 == DateTime(2001, 2, 28, 12, 30, 33));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto dt = DateTime(2000, 1, 31);
|
|
dt.add!"years"(7).add!"months"(-4);
|
|
assert(dt == DateTime(2006, 10, 1));
|
|
|
|
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)));
|
|
}
|
|
|
|
|
|
/++
|
|
Adds the given number of years or months to this $(LREF DateTime). A
|
|
negative number will subtract.
|
|
|
|
The difference between rolling and adding is that rolling does not
|
|
affect larger units. Rolling a $(LREF DateTime) 12 months
|
|
gets the exact same $(LREF DateTime). However, the days can still be
|
|
affected due to the differing number of days in each month.
|
|
|
|
Because there are no units larger than years, there is no difference
|
|
between adding and rolling years.
|
|
|
|
Params:
|
|
units = The type of units to add ("years" or "months").
|
|
value = The number of months or years to add to this
|
|
$(LREF DateTime).
|
|
allowOverflow = Whether the days should be allowed to overflow,
|
|
causing the month to increment.
|
|
+/
|
|
ref DateTime roll(string units)
|
|
(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow
|
|
if(units == "years" ||
|
|
units == "months")
|
|
{
|
|
_date.roll!units(value, allowOverflow);
|
|
return this;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
auto dt1 = DateTime(2010, 1, 1, 12, 33, 33);
|
|
dt1.roll!"months"(1);
|
|
assert(dt1 == DateTime(2010, 2, 1, 12, 33, 33));
|
|
|
|
auto dt2 = DateTime(2010, 1, 1, 12, 33, 33);
|
|
dt2.roll!"months"(-1);
|
|
assert(dt2 == DateTime(2010, 12, 1, 12, 33, 33));
|
|
|
|
auto dt3 = DateTime(1999, 1, 29, 12, 33, 33);
|
|
dt3.roll!"months"(1);
|
|
assert(dt3 == DateTime(1999, 3, 1, 12, 33, 33));
|
|
|
|
auto dt4 = DateTime(1999, 1, 29, 12, 33, 33);
|
|
dt4.roll!"months"(1, AllowDayOverflow.no);
|
|
assert(dt4 == DateTime(1999, 2, 28, 12, 33, 33));
|
|
|
|
auto dt5 = DateTime(2000, 2, 29, 12, 30, 33);
|
|
dt5.roll!"years"(1);
|
|
assert(dt5 == DateTime(2001, 3, 1, 12, 30, 33));
|
|
|
|
auto dt6 = DateTime(2000, 2, 29, 12, 30, 33);
|
|
dt6.roll!"years"(1, AllowDayOverflow.no);
|
|
assert(dt6 == DateTime(2001, 2, 28, 12, 30, 33));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto dt = DateTime(2000, 1, 31);
|
|
dt.roll!"years"(7).roll!"months"(-4);
|
|
assert(dt == DateTime(2007, 10, 1));
|
|
|
|
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)));
|
|
}
|
|
|
|
|
|
/++
|
|
Adds the given number of units to this $(LREF DateTime). A negative number
|
|
will subtract.
|
|
|
|
The difference between rolling and adding is that rolling does not
|
|
affect larger units. For instance, rolling a $(LREF DateTime) one
|
|
year's worth of days gets the exact same $(LREF DateTime).
|
|
|
|
Accepted units are $(D "days"), $(D "minutes"), $(D "hours"),
|
|
$(D "minutes"), and $(D "seconds").
|
|
|
|
Params:
|
|
units = The units to add.
|
|
value = The number of $(D_PARAM units) to add to this $(LREF DateTime).
|
|
+/
|
|
ref DateTime roll(string units)(long value) @safe pure nothrow
|
|
if(units == "days")
|
|
{
|
|
_date.roll!"days"(value);
|
|
return this;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
auto dt1 = DateTime(2010, 1, 1, 11, 23, 12);
|
|
dt1.roll!"days"(1);
|
|
assert(dt1 == DateTime(2010, 1, 2, 11, 23, 12));
|
|
dt1.roll!"days"(365);
|
|
assert(dt1 == DateTime(2010, 1, 26, 11, 23, 12));
|
|
dt1.roll!"days"(-32);
|
|
assert(dt1 == DateTime(2010, 1, 25, 11, 23, 12));
|
|
|
|
auto dt2 = DateTime(2010, 7, 4, 12, 0, 0);
|
|
dt2.roll!"hours"(1);
|
|
assert(dt2 == DateTime(2010, 7, 4, 13, 0, 0));
|
|
|
|
auto dt3 = DateTime(2010, 1, 1, 0, 0, 0);
|
|
dt3.roll!"seconds"(-1);
|
|
assert(dt3 == DateTime(2010, 1, 1, 0, 0, 59));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto dt = DateTime(2000, 1, 31);
|
|
dt.roll!"days"(7).roll!"days"(-4);
|
|
assert(dt == DateTime(2000, 1, 3));
|
|
|
|
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)));
|
|
}
|
|
|
|
|
|
//Shares documentation with "days" version.
|
|
ref DateTime roll(string units)(long value) @safe pure nothrow
|
|
if(units == "hours" ||
|
|
units == "minutes" ||
|
|
units == "seconds")
|
|
{
|
|
_tod.roll!units(value);
|
|
return this;
|
|
}
|
|
|
|
//Test roll!"hours"().
|
|
unittest
|
|
{
|
|
static void testDT(DateTime orig, int hours, in DateTime expected, size_t line = __LINE__)
|
|
{
|
|
orig.roll!"hours"(hours);
|
|
assert(orig == expected);
|
|
}
|
|
|
|
//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)));
|
|
|
|
auto dt = DateTime(2000, 1, 31, 9, 7, 6);
|
|
dt.roll!"hours"(27).roll!"hours"(-9);
|
|
assert(dt == DateTime(2000, 1, 31, 3, 7, 6));
|
|
|
|
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)));
|
|
}
|
|
|
|
//Test roll!"minutes"().
|
|
unittest
|
|
{
|
|
static void testDT(DateTime orig, int minutes, in DateTime expected, size_t line = __LINE__)
|
|
{
|
|
orig.roll!"minutes"(minutes);
|
|
assert(orig == expected);
|
|
}
|
|
|
|
//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)));
|
|
|
|
auto dt = DateTime(2000, 1, 31, 9, 7, 6);
|
|
dt.roll!"minutes"(92).roll!"minutes"(-292);
|
|
assert(dt == DateTime(2000, 1, 31, 9, 47, 6));
|
|
|
|
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);
|
|
assert(orig == expected);
|
|
}
|
|
|
|
//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)));
|
|
|
|
auto dt = DateTime(2000, 1, 31, 9, 7, 6);
|
|
dt.roll!"seconds"(92).roll!"seconds"(-292);
|
|
assert(dt == DateTime(2000, 1, 31, 9, 7, 46));
|
|
|
|
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
|
|
$(LREF DateTime).
|
|
|
|
The legal types of arithmetic for $(LREF DateTime) using this operator are
|
|
|
|
$(BOOKTABLE,
|
|
$(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
|
|
$(LREF DateTime).
|
|
+/
|
|
DateTime opBinary(string op, D)(in D duration) @safe const pure nothrow
|
|
if((op == "+" || op == "-") &&
|
|
(is(Unqual!D == Duration) ||
|
|
is(Unqual!D == TickDuration)))
|
|
{
|
|
import std.format : format;
|
|
|
|
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;
|
|
|
|
mixin(format(`return retval._addSeconds(convert!("hnsecs", "seconds")(%shnsecs));`, op));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
|
|
|
|
assert(dt + dur!"weeks"(7) == DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33)));
|
|
assert(dt + dur!"weeks"(-7) == DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33)));
|
|
assert(dt + dur!"days"(7) == DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33)));
|
|
assert(dt + dur!"days"(-7) == DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33)));
|
|
|
|
assert(dt + dur!"hours"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33)));
|
|
assert(dt + dur!"hours"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33)));
|
|
assert(dt + dur!"minutes"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33)));
|
|
assert(dt + dur!"minutes"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33)));
|
|
assert(dt + dur!"seconds"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
|
|
assert(dt + dur!"seconds"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
|
|
assert(dt + dur!"msecs"(7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
|
|
assert(dt + dur!"msecs"(-7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
|
|
assert(dt + dur!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
|
|
assert(dt + dur!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
|
|
assert(dt + dur!"hnsecs"(70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
|
|
assert(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)
|
|
{
|
|
assert(dt + TickDuration.from!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
|
|
assert(dt + TickDuration.from!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
|
|
}
|
|
|
|
assert(dt - dur!"weeks"(-7) == DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33)));
|
|
assert(dt - dur!"weeks"(7) == DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33)));
|
|
assert(dt - dur!"days"(-7) == DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33)));
|
|
assert(dt - dur!"days"(7) == DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33)));
|
|
|
|
assert(dt - dur!"hours"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33)));
|
|
assert(dt - dur!"hours"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33)));
|
|
assert(dt - dur!"minutes"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33)));
|
|
assert(dt - dur!"minutes"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33)));
|
|
assert(dt - dur!"seconds"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
|
|
assert(dt - dur!"seconds"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
|
|
assert(dt - dur!"msecs"(-7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
|
|
assert(dt - dur!"msecs"(7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
|
|
assert(dt - dur!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
|
|
assert(dt - dur!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
|
|
assert(dt - dur!"hnsecs"(-70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
|
|
assert(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)
|
|
{
|
|
assert(dt - TickDuration.from!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
|
|
assert(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
|
|
$(LREF DateTime), as well as assigning the result to this $(LREF DateTime).
|
|
|
|
The legal types of arithmetic for $(LREF DateTime) using this operator are
|
|
|
|
$(BOOKTABLE,
|
|
$(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
|
|
$(LREF DateTime).
|
|
+/
|
|
ref DateTime opOpAssign(string op, D)(in D duration) @safe pure nothrow
|
|
if((op == "+" || op == "-") &&
|
|
(is(Unqual!D == Duration) ||
|
|
is(Unqual!D == TickDuration)))
|
|
{
|
|
import std.format : format;
|
|
|
|
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;
|
|
|
|
mixin(format(`return _addSeconds(convert!("hnsecs", "seconds")(%shnsecs));`, op));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"weeks"(7) == DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"weeks"(-7) == DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"days"(7) == DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"days"(-7) == DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33)));
|
|
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hours"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hours"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"minutes"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"minutes"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"seconds"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"seconds"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"msecs"(7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"msecs"(-7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hnsecs"(70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hnsecs"(-70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
|
|
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"weeks"(-7) == DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"weeks"(7) == DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"days"(-7) == DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"days"(7) == DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33)));
|
|
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hours"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hours"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"minutes"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"minutes"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"seconds"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"seconds"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"msecs"(-7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"msecs"(7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hnsecs"(-70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hnsecs"(70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
|
|
|
|
auto dt = DateTime(2000, 1, 31, 9, 7, 6);
|
|
(dt += dur!"seconds"(92)) -= dur!"days"(-500);
|
|
assert(dt == DateTime(2001, 6, 14, 9, 8, 38));
|
|
|
|
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 $(LREF DateTime)s.
|
|
|
|
The legal types of arithmetic for $(LREF DateTime) using this operator are
|
|
|
|
$(BOOKTABLE,
|
|
$(TR $(TD DateTime) $(TD -) $(TD DateTime) $(TD -->) $(TD duration))
|
|
)
|
|
+/
|
|
Duration opBinary(string op)(in DateTime rhs) @safe 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);
|
|
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) -
|
|
DateTime(Date(1998, 7, 6), TimeOfDay(12, 30, 33)) ==
|
|
dur!"seconds"(31_536_000));
|
|
assert(DateTime(Date(1998, 7, 6), TimeOfDay(12, 30, 33)) -
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) ==
|
|
dur!"seconds"(-31_536_000));
|
|
|
|
assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)) -
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) ==
|
|
dur!"seconds"(26_78_400));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) -
|
|
DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)) ==
|
|
dur!"seconds"(-26_78_400));
|
|
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) -
|
|
DateTime(Date(1999, 7, 5), TimeOfDay(12, 30, 33)) ==
|
|
dur!"seconds"(86_400));
|
|
assert(DateTime(Date(1999, 7, 5), TimeOfDay(12, 30, 33)) -
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) ==
|
|
dur!"seconds"(-86_400));
|
|
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) -
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)) ==
|
|
dur!"seconds"(3600));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)) -
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) ==
|
|
dur!"seconds"(-3600));
|
|
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)) -
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) ==
|
|
dur!"seconds"(60));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) -
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)) ==
|
|
dur!"seconds"(-60));
|
|
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)) -
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) ==
|
|
dur!"seconds"(1));
|
|
assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) -
|
|
DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)) ==
|
|
dur!"seconds"(-1));
|
|
|
|
assert(DateTime(1, 1, 1, 12, 30, 33) - DateTime(1, 1, 1, 0, 0, 0) == dur!"seconds"(45033));
|
|
assert(DateTime(1, 1, 1, 0, 0, 0) - DateTime(1, 1, 1, 12, 30, 33) == dur!"seconds"(-45033));
|
|
assert(DateTime(0, 12, 31, 12, 30, 33) - DateTime(1, 1, 1, 0, 0, 0) == dur!"seconds"(-41367));
|
|
assert(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 $(LREF DateTime)s in months.
|
|
|
|
To get the difference in years, subtract the year property
|
|
of two $(LREF SysTime)s. To get the difference in days or weeks,
|
|
subtract the $(LREF SysTime)s themselves and use the $(CXREF time, Duration)
|
|
that results. Because converting between months and smaller
|
|
units requires a specific date (which $(CXREF time, Duration)s don't have),
|
|
getting the difference in months requires 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 $(LREF DateTime) to subtract from this one.
|
|
+/
|
|
int diffMonths(in DateTime rhs) @safe const pure nothrow
|
|
{
|
|
return _date.diffMonths(rhs._date);
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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);
|
|
}
|
|
|
|
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)));
|
|
}
|
|
|
|
|
|
/++
|
|
Whether this $(LREF DateTime) is in a leap year.
|
|
+/
|
|
@property bool isLeapYear() @safe 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 $(LREF DateTime) is on.
|
|
+/
|
|
@property DayOfWeek dayOfWeek() @safe 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 $(LREF DateTime) is on.
|
|
+/
|
|
@property ushort dayOfYear() @safe const pure nothrow
|
|
{
|
|
return _date.dayOfYear;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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);
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
/++
|
|
Day of the year.
|
|
|
|
Params:
|
|
day = The day of the year to set which day of the year this
|
|
$(LREF DateTime) is on.
|
|
+/
|
|
@property void dayOfYear(int day) @safe 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 $(LREF DateTime) is on.
|
|
+/
|
|
@property int dayOfGregorianCal() @safe const pure nothrow
|
|
{
|
|
return _date.dayOfGregorianCal;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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);
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
/++
|
|
The Xth day of the Gregorian Calendar that this $(LREF DateTime) is on.
|
|
Setting this property does not affect the time portion of
|
|
$(LREF DateTime).
|
|
|
|
Params:
|
|
days = The day of the Gregorian Calendar to set this $(LREF DateTime)
|
|
to.
|
|
+/
|
|
@property void dayOfGregorianCal(int days) @safe pure nothrow
|
|
{
|
|
_date.dayOfGregorianCal = days;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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)));
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
/++
|
|
The ISO 8601 week of the year that this $(LREF DateTime) is in.
|
|
|
|
See_Also:
|
|
$(WEB en.wikipedia.org/wiki/ISO_week_date, ISO Week Date)
|
|
+/
|
|
@property ubyte isoWeek() @safe 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));
|
|
}
|
|
|
|
|
|
/++
|
|
$(LREF DateTime) for the last day in the month that this $(LREF DateTime) is
|
|
in. The time portion of endOfMonth is always 23:59:59.
|
|
+/
|
|
@property DateTime endOfMonth() @safe const pure nothrow
|
|
{
|
|
try
|
|
return DateTime(_date.endOfMonth, TimeOfDay(23, 59, 59));
|
|
catch(Exception e)
|
|
assert(0, "DateTime constructor threw.");
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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)));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
assert(DateTime(1999, 1, 1, 0, 13, 26).endOfMonth == DateTime(1999, 1, 31, 23, 59, 59));
|
|
assert(DateTime(1999, 2, 1, 1, 14, 27).endOfMonth == DateTime(1999, 2, 28, 23, 59, 59));
|
|
assert(DateTime(2000, 2, 1, 2, 15, 28).endOfMonth == DateTime(2000, 2, 29, 23, 59, 59));
|
|
assert(DateTime(1999, 3, 1, 3, 16, 29).endOfMonth == DateTime(1999, 3, 31, 23, 59, 59));
|
|
assert(DateTime(1999, 4, 1, 4, 17, 30).endOfMonth == DateTime(1999, 4, 30, 23, 59, 59));
|
|
assert(DateTime(1999, 5, 1, 5, 18, 31).endOfMonth == DateTime(1999, 5, 31, 23, 59, 59));
|
|
assert(DateTime(1999, 6, 1, 6, 19, 32).endOfMonth == DateTime(1999, 6, 30, 23, 59, 59));
|
|
assert(DateTime(1999, 7, 1, 7, 20, 33).endOfMonth == DateTime(1999, 7, 31, 23, 59, 59));
|
|
assert(DateTime(1999, 8, 1, 8, 21, 34).endOfMonth == DateTime(1999, 8, 31, 23, 59, 59));
|
|
assert(DateTime(1999, 9, 1, 9, 22, 35).endOfMonth == DateTime(1999, 9, 30, 23, 59, 59));
|
|
assert(DateTime(1999, 10, 1, 10, 23, 36).endOfMonth == DateTime(1999, 10, 31, 23, 59, 59));
|
|
assert(DateTime(1999, 11, 1, 11, 24, 37).endOfMonth == DateTime(1999, 11, 30, 23, 59, 59));
|
|
assert(DateTime(1999, 12, 1, 12, 25, 38).endOfMonth == DateTime(1999, 12, 31, 23, 59, 59));
|
|
|
|
//Test B.C.
|
|
assert(DateTime(-1999, 1, 1, 0, 13, 26).endOfMonth == DateTime(-1999, 1, 31, 23, 59, 59));
|
|
assert(DateTime(-1999, 2, 1, 1, 14, 27).endOfMonth == DateTime(-1999, 2, 28, 23, 59, 59));
|
|
assert(DateTime(-2000, 2, 1, 2, 15, 28).endOfMonth == DateTime(-2000, 2, 29, 23, 59, 59));
|
|
assert(DateTime(-1999, 3, 1, 3, 16, 29).endOfMonth == DateTime(-1999, 3, 31, 23, 59, 59));
|
|
assert(DateTime(-1999, 4, 1, 4, 17, 30).endOfMonth == DateTime(-1999, 4, 30, 23, 59, 59));
|
|
assert(DateTime(-1999, 5, 1, 5, 18, 31).endOfMonth == DateTime(-1999, 5, 31, 23, 59, 59));
|
|
assert(DateTime(-1999, 6, 1, 6, 19, 32).endOfMonth == DateTime(-1999, 6, 30, 23, 59, 59));
|
|
assert(DateTime(-1999, 7, 1, 7, 20, 33).endOfMonth == DateTime(-1999, 7, 31, 23, 59, 59));
|
|
assert(DateTime(-1999, 8, 1, 8, 21, 34).endOfMonth == DateTime(-1999, 8, 31, 23, 59, 59));
|
|
assert(DateTime(-1999, 9, 1, 9, 22, 35).endOfMonth == DateTime(-1999, 9, 30, 23, 59, 59));
|
|
assert(DateTime(-1999, 10, 1, 10, 23, 36).endOfMonth == DateTime(-1999, 10, 31, 23, 59, 59));
|
|
assert(DateTime(-1999, 11, 1, 11, 24, 37).endOfMonth == DateTime(-1999, 11, 30, 23, 59, 59));
|
|
assert(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));
|
|
}
|
|
|
|
|
|
/++
|
|
The last day in the month that this $(LREF DateTime) is in.
|
|
+/
|
|
@property ubyte daysInMonth() @safe const pure nothrow
|
|
{
|
|
return _date.daysInMonth;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).daysInMonth == 31);
|
|
assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).daysInMonth == 28);
|
|
assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).daysInMonth == 29);
|
|
assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).daysInMonth == 30);
|
|
}
|
|
|
|
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.daysInMonth));
|
|
static assert(__traits(compiles, idt.daysInMonth));
|
|
}
|
|
|
|
|
|
/++
|
|
Whether the current year is a date in A.D.
|
|
+/
|
|
@property bool isAD() @safe const pure nothrow
|
|
{
|
|
return _date.isAD;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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);
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
/++
|
|
The $(WEB en.wikipedia.org/wiki/Julian_day, Julian day) for this
|
|
$(LREF 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, the julian day number would
|
|
be 2_450_174, so this function returns 2_450_174.
|
|
+/
|
|
@property long julianDay() @safe const pure nothrow
|
|
{
|
|
if(_tod._hour < 12)
|
|
return _date.julianDay - 1;
|
|
else
|
|
return _date.julianDay;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(DateTime(Date(-4713, 11, 24), TimeOfDay(0, 0, 0)).julianDay == -1);
|
|
assert(DateTime(Date(-4713, 11, 24), TimeOfDay(12, 0, 0)).julianDay == 0);
|
|
|
|
assert(DateTime(Date(0, 12, 31), TimeOfDay(0, 0, 0)).julianDay == 1_721_424);
|
|
assert(DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0)).julianDay == 1_721_425);
|
|
|
|
assert(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).julianDay == 1_721_425);
|
|
assert(DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0)).julianDay == 1_721_426);
|
|
|
|
assert(DateTime(Date(1582, 10, 15), TimeOfDay(0, 0, 0)).julianDay == 2_299_160);
|
|
assert(DateTime(Date(1582, 10, 15), TimeOfDay(12, 0, 0)).julianDay == 2_299_161);
|
|
|
|
assert(DateTime(Date(1858, 11, 17), TimeOfDay(0, 0, 0)).julianDay == 2_400_000);
|
|
assert(DateTime(Date(1858, 11, 17), TimeOfDay(12, 0, 0)).julianDay == 2_400_001);
|
|
|
|
assert(DateTime(Date(1982, 1, 4), TimeOfDay(0, 0, 0)).julianDay == 2_444_973);
|
|
assert(DateTime(Date(1982, 1, 4), TimeOfDay(12, 0, 0)).julianDay == 2_444_974);
|
|
|
|
assert(DateTime(Date(1996, 3, 31), TimeOfDay(0, 0, 0)).julianDay == 2_450_173);
|
|
assert(DateTime(Date(1996, 3, 31), TimeOfDay(12, 0, 0)).julianDay == 2_450_174);
|
|
|
|
assert(DateTime(Date(2010, 8, 24), TimeOfDay(0, 0, 0)).julianDay == 2_455_432);
|
|
assert(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 $(WEB en.wikipedia.org/wiki/Julian_day, Julian day) for any
|
|
time on this date (since, the modified Julian day changes at midnight).
|
|
+/
|
|
@property long modJulianDay() @safe const pure nothrow
|
|
{
|
|
return _date.modJulianDay;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(DateTime(Date(1858, 11, 17), TimeOfDay(0, 0, 0)).modJulianDay == 0);
|
|
assert(DateTime(Date(1858, 11, 17), TimeOfDay(12, 0, 0)).modJulianDay == 0);
|
|
|
|
assert(DateTime(Date(2010, 8, 24), TimeOfDay(0, 0, 0)).modJulianDay == 55_432);
|
|
assert(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 $(LREF DateTime) to a string with the format YYYYMMDDTHHMMSS.
|
|
+/
|
|
string toISOString() @safe const pure nothrow
|
|
{
|
|
import std.format : format;
|
|
try
|
|
return format("%sT%s", _date.toISOString(), _tod.toISOString());
|
|
catch(Exception e)
|
|
assert(0, "format() threw.");
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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");
|
|
}
|
|
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toISOString() == "00091204T000000");
|
|
assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toISOString() == "00991204T050612");
|
|
assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toISOString() == "09991204T134459");
|
|
assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toISOString() == "99990704T235959");
|
|
assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toISOString() == "+100001020T010101");
|
|
|
|
//Test B.C.
|
|
assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toISOString() == "00001204T001204");
|
|
assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toISOString() == "-00091204T000000");
|
|
assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toISOString() == "-00991204T050612");
|
|
assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toISOString() == "-09991204T134459");
|
|
assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toISOString() == "-99990704T235959");
|
|
assert(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()));
|
|
}
|
|
|
|
|
|
/++
|
|
Converts this $(LREF DateTime) to a string with the format
|
|
YYYY-MM-DDTHH:MM:SS.
|
|
+/
|
|
string toISOExtString() @safe const pure nothrow
|
|
{
|
|
import std.format : format;
|
|
try
|
|
return format("%sT%s", _date.toISOExtString(), _tod.toISOExtString());
|
|
catch(Exception e)
|
|
assert(0, "format() threw.");
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOExtString() ==
|
|
"2010-07-04T07:06:12");
|
|
|
|
assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOExtString() ==
|
|
"1998-12-25T02:15:00");
|
|
|
|
assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOExtString() ==
|
|
"0000-01-05T23:09:59");
|
|
|
|
assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOExtString() ==
|
|
"-0004-01-05T00:00:02");
|
|
}
|
|
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toISOExtString() == "0009-12-04T00:00:00");
|
|
assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toISOExtString() == "0099-12-04T05:06:12");
|
|
assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toISOExtString() == "0999-12-04T13:44:59");
|
|
assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toISOExtString() == "9999-07-04T23:59:59");
|
|
assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toISOExtString() == "+10000-10-20T01:01:01");
|
|
|
|
//Test B.C.
|
|
assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toISOExtString() == "0000-12-04T00:12:04");
|
|
assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toISOExtString() == "-0009-12-04T00:00:00");
|
|
assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toISOExtString() == "-0099-12-04T05:06:12");
|
|
assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toISOExtString() == "-0999-12-04T13:44:59");
|
|
assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toISOExtString() == "-9999-07-04T23:59:59");
|
|
assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toISOExtString() == "-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.toISOExtString()));
|
|
static assert(__traits(compiles, idt.toISOExtString()));
|
|
}
|
|
|
|
/++
|
|
Converts this $(LREF DateTime) to a string with the format
|
|
YYYY-Mon-DD HH:MM:SS.
|
|
+/
|
|
string toSimpleString() @safe const pure nothrow
|
|
{
|
|
import std.format : format;
|
|
try
|
|
return format("%s %s", _date.toSimpleString(), _tod.toString());
|
|
catch(Exception e)
|
|
assert(0, "format() threw.");
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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");
|
|
}
|
|
|
|
unittest
|
|
{
|
|
//Test A.D.
|
|
assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toSimpleString() == "0009-Dec-04 00:00:00");
|
|
assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toSimpleString() == "0099-Dec-04 05:06:12");
|
|
assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toSimpleString() == "0999-Dec-04 13:44:59");
|
|
assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toSimpleString() == "9999-Jul-04 23:59:59");
|
|
assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toSimpleString() == "+10000-Oct-20 01:01:01");
|
|
|
|
//Test B.C.
|
|
assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toSimpleString() == "0000-Dec-04 00:12:04");
|
|
assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toSimpleString() == "-0009-Dec-04 00:00:00");
|
|
assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toSimpleString() == "-0099-Dec-04 05:06:12");
|
|
assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toSimpleString() == "-0999-Dec-04 13:44:59");
|
|
assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toSimpleString() == "-9999-Jul-04 23:59:59");
|
|
assert(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()));
|
|
}
|
|
|
|
|
|
/++
|
|
Converts this $(LREF DateTime) to a string.
|
|
+/
|
|
string toString() @safe const pure 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 $(LREF 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:
|
|
$(LREF DateTimeException) if the given string is not in the ISO format
|
|
or if the resulting $(LREF DateTime) would not be valid.
|
|
+/
|
|
static DateTime fromISOString(S)(in S isoString) @safe pure
|
|
if(isSomeString!S)
|
|
{
|
|
import std.string : strip;
|
|
import std.conv : to;
|
|
import std.algorithm : countUntil;
|
|
import std.format : format;
|
|
|
|
immutable dstr = to!dstring(strip(isoString));
|
|
|
|
enforce(dstr.length >= 15, new DateTimeException(format("Invalid ISO String: %s", isoString)));
|
|
auto t = dstr.countUntil('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
|
|
{
|
|
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)));
|
|
}
|
|
|
|
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"));
|
|
|
|
assert(DateTime.fromISOString("20101222T172201") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01)));
|
|
assert(DateTime.fromISOString("19990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime.fromISOString("-19990706T123033") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime.fromISOString("+019990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime.fromISOString("19990706T123033 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime.fromISOString(" 19990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime.fromISOString(" 19990706T123033 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
|
|
}
|
|
|
|
|
|
/++
|
|
Creates a $(LREF DateTime) from a string with the format
|
|
YYYY-MM-DDTHH:MM:SS. Whitespace is stripped from the given string.
|
|
|
|
Params:
|
|
isoExtString = A string formatted in the ISO Extended format for dates
|
|
and times.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given string is not in the ISO
|
|
Extended format or if the resulting $(LREF DateTime) would not be
|
|
valid.
|
|
+/
|
|
static DateTime fromISOExtString(S)(in S isoExtString) @safe pure
|
|
if(isSomeString!(S))
|
|
{
|
|
import std.string : strip;
|
|
import std.conv : to;
|
|
import std.algorithm : countUntil;
|
|
import std.format : format;
|
|
|
|
immutable dstr = to!dstring(strip(isoExtString));
|
|
|
|
enforce(dstr.length >= 15, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
|
|
auto t = dstr.countUntil('T');
|
|
|
|
enforce(t != -1, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
|
|
|
|
immutable date = Date.fromISOExtString(dstr[0..t]);
|
|
immutable tod = TimeOfDay.fromISOExtString(dstr[t+1 .. $]);
|
|
|
|
return DateTime(date, tod);
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
assert(DateTime.fromISOExtString("2010-07-04T07:06:12") ==
|
|
DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
|
|
|
|
assert(DateTime.fromISOExtString("1998-12-25T02:15:00") ==
|
|
DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)));
|
|
|
|
assert(DateTime.fromISOExtString("0000-01-05T23:09:59") ==
|
|
DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)));
|
|
|
|
assert(DateTime.fromISOExtString("-0004-01-05T00:00:02") ==
|
|
DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)));
|
|
|
|
assert(DateTime.fromISOExtString(" 2010-07-04T07:06:12 ") ==
|
|
DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assertThrown!DateTimeException(DateTime.fromISOExtString(""));
|
|
assertThrown!DateTimeException(DateTime.fromISOExtString("20100704000000"));
|
|
assertThrown!DateTimeException(DateTime.fromISOExtString("20100704 000000"));
|
|
assertThrown!DateTimeException(DateTime.fromISOExtString("20100704t000000"));
|
|
assertThrown!DateTimeException(DateTime.fromISOExtString("20100704T000000."));
|
|
assertThrown!DateTimeException(DateTime.fromISOExtString("20100704T000000.0"));
|
|
|
|
assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07:0400:00:00"));
|
|
assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04 00:00:00"));
|
|
assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04 00:00:00"));
|
|
assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04t00:00:00"));
|
|
assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04T00:00:00."));
|
|
assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04T00:00:00.0"));
|
|
|
|
assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-0400:00:00"));
|
|
assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04t00:00:00"));
|
|
assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04 00:00:00."));
|
|
assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04 00:00:00.0"));
|
|
|
|
assertThrown!DateTimeException(DateTime.fromISOExtString("20101222T172201"));
|
|
assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Dec-22 17:22:01"));
|
|
|
|
assert(DateTime.fromISOExtString("2010-12-22T17:22:01") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01)));
|
|
assert(DateTime.fromISOExtString("1999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime.fromISOExtString("-1999-07-06T12:30:33") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime.fromISOExtString("+01999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime.fromISOExtString("1999-07-06T12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime.fromISOExtString(" 1999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime.fromISOExtString(" 1999-07-06T12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
|
|
}
|
|
|
|
|
|
/++
|
|
Creates a $(LREF 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:
|
|
$(LREF DateTimeException) if the given string is not in the correct
|
|
format or if the resulting $(LREF DateTime) would not be valid.
|
|
+/
|
|
static DateTime fromSimpleString(S)(in S simpleString) @safe pure
|
|
if(isSomeString!(S))
|
|
{
|
|
import std.string : strip;
|
|
import std.conv : to;
|
|
import std.algorithm : countUntil;
|
|
import std.format : format;
|
|
|
|
immutable dstr = to!dstring(strip(simpleString));
|
|
|
|
enforce(dstr.length >= 15, new DateTimeException(format("Invalid string format: %s", simpleString)));
|
|
auto t = dstr.countUntil(' ');
|
|
|
|
enforce(t != -1, new DateTimeException(format("Invalid string format: %s", simpleString)));
|
|
|
|
immutable date = Date.fromSimpleString(dstr[0..t]);
|
|
immutable tod = TimeOfDay.fromISOExtString(dstr[t+1 .. $]);
|
|
|
|
return DateTime(date, tod);
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
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)));
|
|
}
|
|
|
|
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"));
|
|
|
|
assert(DateTime.fromSimpleString("2010-Dec-22 17:22:01") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01)));
|
|
assert(DateTime.fromSimpleString("1999-Jul-06 12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime.fromSimpleString("-1999-Jul-06 12:30:33") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime.fromSimpleString("+01999-Jul-06 12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime.fromSimpleString("1999-Jul-06 12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime.fromSimpleString(" 1999-Jul-06 12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
|
|
assert(DateTime.fromSimpleString(" 1999-Jul-06 12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
|
|
}
|
|
|
|
|
|
/++
|
|
Returns the $(LREF DateTime) farthest in the past which is representable by
|
|
$(LREF DateTime).
|
|
+/
|
|
@property static DateTime min() @safe 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 $(LREF DateTime) farthest in the future which is representable
|
|
by $(LREF DateTime).
|
|
+/
|
|
@property static DateTime max() @safe 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 $(LREF DateTime).
|
|
+/
|
|
ref DateTime _addSeconds(long seconds) return @safe 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);
|
|
assert(orig == expected);
|
|
}
|
|
|
|
//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;
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
// Section with intervals.
|
|
//==============================================================================
|
|
|
|
/++
|
|
Represents an interval of time.
|
|
|
|
An $(D Interval) has a starting point and an end point. The interval of time
|
|
is therefore the time starting at the starting point up to, but not
|
|
including, the end point. e.g.
|
|
|
|
$(BOOKTABLE,
|
|
$(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 iteration 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:
|
|
$(LREF DateTimeException) if $(D_PARAM end) is before $(D_PARAM 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 starting point to the end point.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the resulting $(D end) is before
|
|
$(D 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 $(LREF2 .Interval, 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 $(LREF2 .Interval, 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 starting 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 starting point of the interval. It is included in the interval.
|
|
|
|
Params:
|
|
timePoint = The time point to set $(D begin) to.
|
|
|
|
Throws:
|
|
$(LREF 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:
|
|
$(LREF 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 $(D begin) and $(D end).
|
|
|
|
Examples:
|
|
--------------------
|
|
assert(Interval!Date(Date(1996, 1, 2), Date(2012, 3, 1)).length ==
|
|
dur!"days"(5903));
|
|
--------------------
|
|
+/
|
|
@property auto length() const pure nothrow
|
|
{
|
|
return _end - _begin;
|
|
}
|
|
|
|
|
|
/++
|
|
Whether the interval's length is 0, that is, whether $(D 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:
|
|
$(LREF DateTimeException) if this interval is empty.
|
|
|
|
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:
|
|
$(LREF 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:
|
|
$(LREF 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 beginning at negative infinity can never be contained in a
|
|
finite interval.
|
|
|
|
Params:
|
|
interval = The interval to check for inclusion in this interval.
|
|
|
|
Throws:
|
|
$(LREF 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:
|
|
$(LREF DateTimeException) if this interval is empty.
|
|
|
|
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:
|
|
$(LREF 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:
|
|
$(LREF 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:
|
|
$(LREF 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:
|
|
$(LREF DateTimeException) if this interval is empty.
|
|
|
|
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
|
|
it.
|
|
|
|
Params:
|
|
interval = The interval to check against this interval.
|
|
|
|
Throws:
|
|
$(LREF 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
|
|
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:
|
|
$(LREF 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
|
|
it.
|
|
|
|
Params:
|
|
interval = The interval to check against this interval.
|
|
|
|
Throws:
|
|
$(LREF 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 this interval.
|
|
|
|
Params:
|
|
interval = The interval to check for intersection with this interval.
|
|
|
|
Throws:
|
|
$(LREF 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 this interval.
|
|
|
|
Params:
|
|
interval = The interval to check for intersection with this interval.
|
|
|
|
Throws:
|
|
$(LREF 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 this interval.
|
|
|
|
Params:
|
|
interval = The interval to check for intersection with this interval.
|
|
|
|
Throws:
|
|
$(LREF 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:
|
|
$(LREF 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
|
|
{
|
|
import std.format : format;
|
|
|
|
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:
|
|
$(LREF 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
|
|
{
|
|
import std.format : format;
|
|
|
|
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:
|
|
$(LREF 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
|
|
{
|
|
import std.format : format;
|
|
|
|
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 adjecent to this
|
|
interval.
|
|
|
|
Throws:
|
|
$(LREF 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 adjecent to this
|
|
interval.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if this interval 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 adjecent to this
|
|
interval.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if this interval 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:
|
|
$(LREF 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
|
|
{
|
|
import std.format : format;
|
|
|
|
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:
|
|
$(LREF 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
|
|
{
|
|
import std.format : format;
|
|
|
|
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:
|
|
$(LREF 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
|
|
{
|
|
import std.format : format;
|
|
|
|
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:
|
|
$(LREF 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:
|
|
$(LREF 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:
|
|
$(LREF 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:
|
|
$(LREF DateTimeException) this interval is empty 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 $(D begin) and $(D end), causing their month
|
|
to increment.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if this interval is empty 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
|
|
$(D_PARAM dir).
|
|
|
|
Params:
|
|
duration = The duration to expand the interval by.
|
|
dir = The direction in time to expand the interval.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) this interval is empty 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 $(D begin) and
|
|
adds them to $(D end). Whether it expands forwards and/or backwards
|
|
in time is determined by $(D_PARAM dir).
|
|
|
|
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 $(D begin) and $(D end), causing their month
|
|
to increment.
|
|
dir = The direction in time to expand the interval.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if this interval is empty 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 $(D begin), using $(D_PARAM func) to generate each successive time
|
|
point.
|
|
|
|
The range's $(D front) is the interval's $(D begin). $(D_PARAM func) is
|
|
used to generate the next $(D front) when $(D popFront) is called. If
|
|
$(D_PARAM 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_PARAM func) would generate).
|
|
|
|
If $(D_PARAM func) ever generates a time point less than or equal to the
|
|
current $(D front) of the range, then a $(LREF DateTimeException) will be
|
|
thrown. The range will be empty and iteration complete when
|
|
$(D_PARAM func) generates a time point equal to or beyond the $(D end)
|
|
of the interval.
|
|
|
|
There are helper functions in this module which generate common
|
|
delegates to pass to $(D fwdRange). Their documentation starts with
|
|
"Range-generating function," making them easily searchable.
|
|
|
|
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:
|
|
$(LREF DateTimeException) if this interval is empty.
|
|
|
|
Warning:
|
|
$(D_PARAM func) must be logically pure. Ideally, $(D_PARAM func)
|
|
would be a function pointer to a pure function, but forcing
|
|
$(D_PARAM 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_PARAM func) must be a
|
|
delegate.
|
|
|
|
If $(D_PARAM 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.
|
|
To avoid such bugs, don't pass a delegate which is
|
|
not logically pure to $(D fwdRange). If $(D_PARAM 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 when creating a custom 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);
|
|
|
|
//An odd day. Using PopFirst.yes would have made this Date(2010, 9, 2).
|
|
assert(range.front == Date(2010, 9, 1));
|
|
|
|
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 $(D end), using $(D_PARAM func) to generate each successive time
|
|
point.
|
|
|
|
The range's $(D front) is the interval's $(D end). $(D_PARAM func) is
|
|
used to generate the next $(D front) when $(D popFront) is called. If
|
|
$(D_PARAM 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_PARAM func) would generate).
|
|
|
|
If $(D_PARAM func) ever generates a time point greater than or equal to
|
|
the current $(D front) of the range, then a $(LREF DateTimeException) will
|
|
be thrown. The range will be empty and iteration complete when
|
|
$(D_PARAM 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
|
|
"Range-generating function," making them easily searchable.
|
|
|
|
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:
|
|
$(LREF DateTimeException) if this interval is empty.
|
|
|
|
Warning:
|
|
$(D_PARAM func) must be logically pure. Ideally, $(D_PARAM func)
|
|
would be a function pointer to a pure function, but forcing
|
|
$(D_PARAM 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_PARAM func) must be a
|
|
delegate.
|
|
|
|
If $(D_PARAM 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.
|
|
To avoid such bugs, don't pass a delegate which is
|
|
not logically pure to $(D fwdRange). If $(D_PARAM 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 for custom delegates.
|
|
|
|
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);
|
|
|
|
//An odd day. Using PopFirst.yes would have made this Date(2010, 9, 8).
|
|
assert(range.front == Date(2010, 9, 9));
|
|
|
|
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
|
|
{
|
|
import std.format : format;
|
|
try
|
|
return format("[%s - %s)", _begin, _end);
|
|
catch(Exception e)
|
|
assert(0, "format() threw.");
|
|
}
|
|
|
|
|
|
/+
|
|
Throws:
|
|
$(LREF DateTimeException) if this interval is empty.
|
|
+/
|
|
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 starting 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
|
|
{
|
|
assert(Interval!Date(Date(1, 1, 1), Date(2010, 1, 1)).begin == Date(1, 1, 1));
|
|
assert(Interval!Date(Date(2010, 1, 1), Date(2010, 1, 1)).begin == Date(2010, 1, 1));
|
|
assert(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
|
|
{
|
|
assert(Interval!Date(Date(1, 1, 1), Date(2010, 1, 1)).end == Date(2010, 1, 1));
|
|
assert(Interval!Date(Date(2010, 1, 1), Date(2010, 1, 1)).end == Date(2010, 1, 1));
|
|
assert(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
|
|
{
|
|
assert(Interval!Date(Date(2010, 1, 1), Date(2010, 1, 1)).length == dur!"days"(0));
|
|
assert(Interval!Date(Date(2010, 1, 1), Date(2010, 4, 1)).length == dur!"days"(90));
|
|
assert(Interval!TimeOfDay(TimeOfDay(0, 30, 0), TimeOfDay(12, 22, 7)).length == dur!"seconds"(42_727));
|
|
assert(Interval!DateTime(DateTime(2010, 1, 1, 0, 30, 0), DateTime(2010, 1, 2, 12, 22, 7)).length == dur!"seconds"(129_127));
|
|
assert(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))));
|
|
|
|
assert(interval.intersection(interval) == interval);
|
|
assert(interval.intersection(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(interval.intersection(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5)));
|
|
assert(interval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(interval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(interval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) ==
|
|
Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)));
|
|
assert(interval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) ==
|
|
Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)));
|
|
assert(interval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) ==
|
|
Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
|
|
assert(interval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) ==
|
|
Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
|
|
|
|
assert(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).intersection(interval) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).intersection(interval) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5)));
|
|
assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).intersection(interval) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).intersection(interval) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).intersection(interval) ==
|
|
Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)));
|
|
assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).intersection(interval) ==
|
|
Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)));
|
|
assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).intersection(interval) ==
|
|
Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
|
|
assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).intersection(interval) ==
|
|
Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
|
|
|
|
assert(interval.intersection(PosInfInterval!Date(Date(2010, 7, 3))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(interval.intersection(PosInfInterval!Date(Date(2010, 7, 4))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(interval.intersection(PosInfInterval!Date(Date(2010, 7, 5))) ==
|
|
Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)));
|
|
assert(interval.intersection(PosInfInterval!Date(Date(2012, 1, 6))) ==
|
|
Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
|
|
|
|
assert(interval.intersection(NegInfInterval!Date(Date(2010, 7, 5))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5)));
|
|
assert(interval.intersection(NegInfInterval!Date(Date(2012, 1, 6))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 6)));
|
|
assert(interval.intersection(NegInfInterval!Date(Date(2012, 1, 7))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(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))));
|
|
|
|
assert(interval.merge(interval) == interval);
|
|
assert(interval.merge(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) ==
|
|
Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)));
|
|
assert(interval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
|
|
assert(interval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
|
|
assert(interval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
|
|
assert(interval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)));
|
|
assert(interval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(interval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(interval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(interval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
|
|
assert(interval.merge(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
|
|
|
|
assert(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).merge(interval) ==
|
|
Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)));
|
|
assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).merge(interval) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
|
|
assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).merge(interval) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
|
|
assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).merge(interval) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
|
|
assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).merge(interval) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)));
|
|
assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).merge(interval) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).merge(interval) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).merge(interval) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).merge(interval) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
|
|
assert(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).merge(interval) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
|
|
|
|
assert(interval.merge(PosInfInterval!Date(Date(2010, 7, 3))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 3)));
|
|
assert(interval.merge(PosInfInterval!Date(Date(2010, 7, 4))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(interval.merge(PosInfInterval!Date(Date(2010, 7, 5))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(interval.merge(PosInfInterval!Date(Date(2012, 1, 6))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(interval.merge(PosInfInterval!Date(Date(2012, 1, 7))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
|
|
assert(interval.merge(NegInfInterval!Date(Date(2010, 7, 4))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(interval.merge(NegInfInterval!Date(Date(2010, 7, 5))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(interval.merge(NegInfInterval!Date(Date(2012, 1, 6))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(interval.merge(NegInfInterval!Date(Date(2012, 1, 7))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(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))));
|
|
|
|
assert(interval.span(interval) == interval);
|
|
assert(interval.span(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))) ==
|
|
Interval!Date(Date(2010, 7, 1), Date(2012, 1, 7)));
|
|
assert(interval.span(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) ==
|
|
Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)));
|
|
assert(interval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
|
|
assert(interval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
|
|
assert(interval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
|
|
assert(interval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)));
|
|
assert(interval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(interval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(interval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(interval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
|
|
assert(interval.span(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
|
|
assert(interval.span(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 9)));
|
|
|
|
assert(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)).span(interval) ==
|
|
Interval!Date(Date(2010, 7, 1), Date(2012, 1, 7)));
|
|
assert(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)).span(interval) ==
|
|
Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3)));
|
|
assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)).span(interval) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
|
|
assert(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)).span(interval) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
|
|
assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)).span(interval) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
|
|
assert(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)).span(interval) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8)));
|
|
assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)).span(interval) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)).span(interval) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)).span(interval) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)).span(interval) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
|
|
assert(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)).span(interval) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
|
|
assert(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)).span(interval) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 9)));
|
|
|
|
assert(interval.span(PosInfInterval!Date(Date(2010, 7, 3))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 3)));
|
|
assert(interval.span(PosInfInterval!Date(Date(2010, 7, 4))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(interval.span(PosInfInterval!Date(Date(2010, 7, 5))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(interval.span(PosInfInterval!Date(Date(2012, 1, 6))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(interval.span(PosInfInterval!Date(Date(2012, 1, 7))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(interval.span(PosInfInterval!Date(Date(2012, 1, 8))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
|
|
assert(interval.span(NegInfInterval!Date(Date(2010, 7, 3))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(interval.span(NegInfInterval!Date(Date(2010, 7, 4))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(interval.span(NegInfInterval!Date(Date(2010, 7, 5))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(interval.span(NegInfInterval!Date(Date(2012, 1, 6))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(interval.span(NegInfInterval!Date(Date(2012, 1, 7))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(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);
|
|
assert(interval == expected);
|
|
}
|
|
|
|
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);
|
|
assert(interval == expected);
|
|
}
|
|
|
|
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);
|
|
assert(interval == expected);
|
|
}
|
|
|
|
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);
|
|
assert(interval == expected);
|
|
}
|
|
|
|
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);
|
|
|
|
assert(Interval!Date(Date(2010, 9, 12), Date(2010, 10, 1)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).front ==
|
|
Date(2010, 9, 12));
|
|
|
|
assert(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 = delegate (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);
|
|
|
|
assert(Interval!Date(Date(2010, 9, 19), Date(2010, 10, 1)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).front ==
|
|
Date(2010, 10, 1));
|
|
|
|
assert(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 = delegate (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
|
|
{
|
|
assert(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 $(D 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 $(D PosInfInterval) to assign to this one.
|
|
+/
|
|
ref PosInfInterval opAssign(PosInfInterval rhs) pure nothrow
|
|
{
|
|
_begin = cast(TP)rhs._begin;
|
|
return this;
|
|
}
|
|
|
|
|
|
/++
|
|
The starting 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 starting point of the interval. It is included in the interval.
|
|
|
|
Params:
|
|
timePoint = The time point to set $(D 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:
|
|
$(LREF 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 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:
|
|
$(LREF DateTimeException) if the given 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 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 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
|
|
it.
|
|
|
|
Params:
|
|
interval = The interval to check against this interval.
|
|
|
|
Throws:
|
|
$(LREF 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
|
|
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
|
|
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 this interval.
|
|
|
|
Params:
|
|
interval = The interval to check for intersection with this interval.
|
|
|
|
Throws:
|
|
$(LREF 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 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 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:
|
|
$(LREF 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
|
|
{
|
|
import std.format : format;
|
|
|
|
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:
|
|
$(LREF 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
|
|
{
|
|
import std.format : format;
|
|
|
|
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 adjecent to this
|
|
interval.
|
|
|
|
Throws:
|
|
$(LREF 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 adjecent to 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 adjecent to 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:
|
|
$(LREF 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
|
|
$(D NegInfInterval), because an interval
|
|
going from negative infinity to positive infinity
|
|
is not possible.
|
|
|
|
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
|
|
{
|
|
import std.format : format;
|
|
|
|
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
|
|
$(D NegInfInterval), because an interval
|
|
going from negative infinity to positive infinity
|
|
is not possible.
|
|
|
|
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:
|
|
$(LREF DateTimeException) if the given interval is empty.
|
|
|
|
Note:
|
|
There is no overload for $(D span) which takes a
|
|
$(D NegInfInterval), because an interval
|
|
going from negative infinity to positive infinity
|
|
is not possible.
|
|
|
|
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
|
|
$(D NegInfInterval), because an interval
|
|
going from negative infinity to positive infinity
|
|
is not possible.
|
|
|
|
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 $(D 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 $(D 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
|
|
$(D begin). It effectively calls $(D add!"years"()) and then
|
|
$(D add!"months"()) on $(D begin) 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 $(D begin), causing its month to increment.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if this interval is empty 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.
|
|
|
|
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 $(D 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 $(D begin), causing its month to increment.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if this interval is empty 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 $(D begin), using $(D_PARAM func) to generate each successive time
|
|
point.
|
|
|
|
The range's $(D front) is the interval's $(D begin). $(D_PARAM func) is
|
|
used to generate the next $(D front) when $(D popFront) is called. If
|
|
$(D_PARAM 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_PARAM func) would generate).
|
|
|
|
If $(D_PARAM func) ever generates a time point less than or equal to the
|
|
current $(D front) of the range, then a $(LREF DateTimeException) will be
|
|
thrown.
|
|
|
|
There are helper functions in this module which generate common
|
|
delegates to pass to $(D fwdRange). Their documentation starts with
|
|
"Range-generating function," to make them easily searchable.
|
|
|
|
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:
|
|
$(LREF DateTimeException) if this interval is empty.
|
|
|
|
Warning:
|
|
$(D_PARAM func) must be logically pure. Ideally, $(D_PARAM func)
|
|
would be a function pointer to a pure function, but forcing
|
|
$(D_PARAM 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_PARAM func) must be a
|
|
delegate.
|
|
|
|
If $(D_PARAM 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.
|
|
To avoid such bugs, don't pass a delegate which is
|
|
not logically pure to $(D fwdRange). If $(D_PARAM 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 for custom delegates.
|
|
|
|
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);
|
|
|
|
//An odd day. Using PopFirst.yes would have made this Date(2010, 9, 2).
|
|
assert(range.front == Date(2010, 9, 1));
|
|
|
|
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
|
|
{
|
|
import std.format : format;
|
|
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
|
|
{
|
|
assert(PosInfInterval!Date(Date(1, 1, 1)).begin == Date(1, 1, 1));
|
|
assert(PosInfInterval!Date(Date(2010, 1, 1)).begin == Date(2010, 1, 1));
|
|
assert(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))));
|
|
|
|
assert(posInfInterval.intersection(posInfInterval) ==
|
|
posInfInterval);
|
|
assert(posInfInterval.intersection(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2013, 7, 3)));
|
|
assert(posInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5)));
|
|
assert(posInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(posInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 8)));
|
|
assert(posInfInterval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) ==
|
|
Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)));
|
|
assert(posInfInterval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) ==
|
|
Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)));
|
|
assert(posInfInterval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) ==
|
|
Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
|
|
assert(posInfInterval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) ==
|
|
Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8)));
|
|
assert(posInfInterval.intersection(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) ==
|
|
Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8)));
|
|
assert(posInfInterval.intersection(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))) ==
|
|
Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9)));
|
|
|
|
assert(posInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 3))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 4))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 5))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 5)));
|
|
assert(posInfInterval.intersection(PosInfInterval!Date(Date(2012, 1, 6))) ==
|
|
PosInfInterval!Date(Date(2012, 1, 6)));
|
|
assert(posInfInterval.intersection(PosInfInterval!Date(Date(2012, 1, 7))) ==
|
|
PosInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(posInfInterval.intersection(PosInfInterval!Date(Date(2012, 1, 8))) ==
|
|
PosInfInterval!Date(Date(2012, 1, 8)));
|
|
|
|
assert(PosInfInterval!Date(Date(2010, 7, 3)).intersection(posInfInterval) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(PosInfInterval!Date(Date(2010, 7, 4)).intersection(posInfInterval) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(PosInfInterval!Date(Date(2010, 7, 5)).intersection(posInfInterval) ==
|
|
PosInfInterval!Date(Date(2010, 7, 5)));
|
|
assert(PosInfInterval!Date(Date(2012, 1, 6)).intersection(posInfInterval) ==
|
|
PosInfInterval!Date(Date(2012, 1, 6)));
|
|
assert(PosInfInterval!Date(Date(2012, 1, 7)).intersection(posInfInterval) ==
|
|
PosInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(PosInfInterval!Date(Date(2012, 1, 8)).intersection(posInfInterval) ==
|
|
PosInfInterval!Date(Date(2012, 1, 8)));
|
|
|
|
assert(posInfInterval.intersection(NegInfInterval!Date(Date(2010, 7, 5))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2010, 7, 5)));
|
|
assert(posInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 6))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 6)));
|
|
assert(posInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 7))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1, 7)));
|
|
assert(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))));
|
|
|
|
assert(posInfInterval.merge(posInfInterval) ==
|
|
posInfInterval);
|
|
assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 1)));
|
|
assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 3)));
|
|
assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 3)));
|
|
assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 3)));
|
|
assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 3)));
|
|
assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.merge(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.merge(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
|
|
assert(posInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 3))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 3)));
|
|
assert(posInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 4))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.merge(PosInfInterval!Date(Date(2010, 7, 5))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 6))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 7))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.merge(PosInfInterval!Date(Date(2012, 1, 8))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
|
|
assert(PosInfInterval!Date(Date(2010, 7, 3)).merge(posInfInterval) ==
|
|
PosInfInterval!Date(Date(2010, 7, 3)));
|
|
assert(PosInfInterval!Date(Date(2010, 7, 4)).merge(posInfInterval) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(PosInfInterval!Date(Date(2010, 7, 5)).merge(posInfInterval) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(PosInfInterval!Date(Date(2012, 1, 6)).merge(posInfInterval) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(PosInfInterval!Date(Date(2012, 1, 7)).merge(posInfInterval) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(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))));
|
|
|
|
assert(posInfInterval.span(posInfInterval) ==
|
|
posInfInterval);
|
|
assert(posInfInterval.span(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 1)));
|
|
assert(posInfInterval.span(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 1)));
|
|
assert(posInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 3)));
|
|
assert(posInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 3)));
|
|
assert(posInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 3)));
|
|
assert(posInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 3)));
|
|
assert(posInfInterval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.span(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.span(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
|
|
assert(posInfInterval.span(PosInfInterval!Date(Date(2010, 7, 3))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 3)));
|
|
assert(posInfInterval.span(PosInfInterval!Date(Date(2010, 7, 4))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.span(PosInfInterval!Date(Date(2010, 7, 5))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.span(PosInfInterval!Date(Date(2012, 1, 6))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.span(PosInfInterval!Date(Date(2012, 1, 7))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(posInfInterval.span(PosInfInterval!Date(Date(2012, 1, 8))) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
|
|
assert(PosInfInterval!Date(Date(2010, 7, 3)).span(posInfInterval) ==
|
|
PosInfInterval!Date(Date(2010, 7, 3)));
|
|
assert(PosInfInterval!Date(Date(2010, 7, 4)).span(posInfInterval) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(PosInfInterval!Date(Date(2010, 7, 5)).span(posInfInterval) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(PosInfInterval!Date(Date(2012, 1, 6)).span(posInfInterval) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(PosInfInterval!Date(Date(2012, 1, 7)).span(posInfInterval) ==
|
|
PosInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(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);
|
|
assert(interval == expected);
|
|
}
|
|
|
|
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);
|
|
assert(interval == expected);
|
|
}
|
|
|
|
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);
|
|
assert(interval == expected);
|
|
}
|
|
|
|
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);
|
|
assert(interval == expected);
|
|
}
|
|
|
|
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));
|
|
|
|
assert(PosInfInterval!Date(Date(2010, 9, 12)).fwdRange(everyDayOfWeek!Date(DayOfWeek.fri)).front ==
|
|
Date(2010, 9, 12));
|
|
|
|
assert(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 = delegate (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
|
|
{
|
|
assert(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 starting
|
|
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.
|
|
Iterate over it in reverse.
|
|
+/
|
|
struct NegInfInterval(TP)
|
|
{
|
|
public:
|
|
|
|
/++
|
|
Params:
|
|
end = The time point which ends the interval.
|
|
|
|
Examples:
|
|
--------------------
|
|
auto interval = PosInfInterval!Date(Date(1996, 1, 2));
|
|
--------------------
|
|
+/
|
|
this(in TP end) pure nothrow
|
|
{
|
|
_end = cast(TP)end;
|
|
}
|
|
|
|
|
|
/++
|
|
Params:
|
|
rhs = The $(D 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 $(D 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:
|
|
$(LREF 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 it.
|
|
|
|
Params:
|
|
interval = The interval to check for against this interval.
|
|
|
|
Throws:
|
|
$(LREF 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 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 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 beginning 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 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:
|
|
$(LREF 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
|
|
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
|
|
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 this interval.
|
|
|
|
Params:
|
|
interval = The interval to check for intersection with this interval.
|
|
|
|
Throws:
|
|
$(LREF 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 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 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:
|
|
$(LREF 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
|
|
{
|
|
import std.format : format;
|
|
|
|
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:
|
|
$(LREF 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
|
|
{
|
|
import std.format : format;
|
|
|
|
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 adjecent to this
|
|
interval.
|
|
|
|
Throws:
|
|
$(LREF 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 adjecent to 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 adjecent to 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:
|
|
$(LREF 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
|
|
$(D PosInfInterval), because an interval
|
|
going from negative infinity to positive infinity
|
|
is not possible.
|
|
|
|
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
|
|
{
|
|
import std.format : format;
|
|
|
|
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
|
|
$(D PosInfInterval), because an interval
|
|
going from negative infinity to positive infinity
|
|
is not possible.
|
|
|
|
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:
|
|
$(LREF DateTimeException) if the given interval is empty.
|
|
|
|
Note:
|
|
There is no overload for $(D span) which takes a
|
|
$(D PosInfInterval), because an interval
|
|
going from negative infinity to positive infinity
|
|
is not possible.
|
|
|
|
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
|
|
$(D PosInfInterval), because an interval
|
|
going from negative infinity to positive infinity
|
|
is not possible.
|
|
|
|
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 $(D 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 $(D 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 $(D end), causing its month to increment.
|
|
|
|
Throws:
|
|
$(LREF 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.
|
|
|
|
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 $(D end), causing their month to increment.
|
|
|
|
Throws:
|
|
$(LREF 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 $(D end), using $(D_PARAM func) to generate each successive time
|
|
point.
|
|
|
|
The range's $(D front) is the interval's $(D end). $(D_PARAM func) is
|
|
used to generate the next $(D front) when $(D popFront) is called. If
|
|
$(D_PARAM 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_PARAM func) would generate).
|
|
|
|
If $(D_PARAM func) ever generates a time point greater than or equal to
|
|
the current $(D front) of the range, then a $(LREF DateTimeException) will
|
|
be thrown.
|
|
|
|
There are helper functions in this module which generate common
|
|
delegates to pass to $(D bwdRange). Their documentation starts with
|
|
"Range-generating function," to make them easily searchable.
|
|
|
|
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:
|
|
$(LREF DateTimeException) if this interval is empty.
|
|
|
|
Warning:
|
|
$(D_PARAM func) must be logically pure. Ideally, $(D_PARAM func)
|
|
would be a function pointer to a pure function, but forcing
|
|
$(D_PARAM 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_PARAM func) must be a
|
|
delegate.
|
|
|
|
If $(D_PARAM 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.
|
|
To avoid such bugs, don't pass a delegate which is
|
|
not logically pure to $(D fwdRange). If $(D_PARAM 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 for custom delegates.
|
|
|
|
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
|
|
{
|
|
import std.format : format;
|
|
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
|
|
{
|
|
assert(NegInfInterval!Date(Date(2010, 1, 1)).end == Date(2010, 1, 1));
|
|
assert(NegInfInterval!Date(Date(2010, 1, 1)).end == Date(2010, 1, 1));
|
|
assert(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))));
|
|
|
|
assert(negInfInterval.intersection(negInfInterval) ==
|
|
negInfInterval);
|
|
assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))) ==
|
|
Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3)));
|
|
assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) ==
|
|
Interval!Date(Date(2010, 7, 1), Date(2012, 1, 7)));
|
|
assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4)));
|
|
assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5)));
|
|
assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
|
|
assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7)));
|
|
assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) ==
|
|
Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6)));
|
|
assert(negInfInterval.intersection(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) ==
|
|
Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7)));
|
|
assert(negInfInterval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) ==
|
|
Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
|
|
assert(negInfInterval.intersection(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) ==
|
|
Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7)));
|
|
|
|
assert(negInfInterval.intersection(NegInfInterval!Date(Date(2010, 7, 3))) ==
|
|
NegInfInterval!Date(Date(2010, 7, 3)));
|
|
assert(negInfInterval.intersection(NegInfInterval!Date(Date(2010, 7, 4))) ==
|
|
NegInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(negInfInterval.intersection(NegInfInterval!Date(Date(2010, 7, 5))) ==
|
|
NegInfInterval!Date(Date(2010, 7, 5)));
|
|
assert(negInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 6))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 6)));
|
|
assert(negInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 7))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.intersection(NegInfInterval!Date(Date(2012, 1, 8))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
|
|
assert(NegInfInterval!Date(Date(2010, 7, 3)).intersection(negInfInterval) ==
|
|
NegInfInterval!Date(Date(2010, 7, 3)));
|
|
assert(NegInfInterval!Date(Date(2010, 7, 4)).intersection(negInfInterval) ==
|
|
NegInfInterval!Date(Date(2010, 7, 4)));
|
|
assert(NegInfInterval!Date(Date(2010, 7, 5)).intersection(negInfInterval) ==
|
|
NegInfInterval!Date(Date(2010, 7, 5)));
|
|
assert(NegInfInterval!Date(Date(2012, 1, 6)).intersection(negInfInterval) ==
|
|
NegInfInterval!Date(Date(2012, 1, 6)));
|
|
assert(NegInfInterval!Date(Date(2012, 1, 7)).intersection(negInfInterval) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(NegInfInterval!Date(Date(2012, 1, 8)).intersection(negInfInterval) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
|
|
assert(negInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 3))) ==
|
|
Interval!Date(Date(2010, 7, 3), Date(2012, 1 ,7)));
|
|
assert(negInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 4))) ==
|
|
Interval!Date(Date(2010, 7, 4), Date(2012, 1 ,7)));
|
|
assert(negInfInterval.intersection(PosInfInterval!Date(Date(2010, 7, 5))) ==
|
|
Interval!Date(Date(2010, 7, 5), Date(2012, 1 ,7)));
|
|
assert(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))));
|
|
|
|
assert(negInfInterval.merge(negInfInterval) ==
|
|
negInfInterval);
|
|
assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) ==
|
|
NegInfInterval!Date(Date(2013, 7, 3)));
|
|
assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 8)));
|
|
assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.merge(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.merge(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 8)));
|
|
assert(negInfInterval.merge(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 8)));
|
|
|
|
assert(negInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 3))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 4))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.merge(NegInfInterval!Date(Date(2010, 7, 5))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 6))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 7))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.merge(NegInfInterval!Date(Date(2012, 1, 8))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 8)));
|
|
|
|
assert(NegInfInterval!Date(Date(2010, 7, 3)).merge(negInfInterval) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(NegInfInterval!Date(Date(2010, 7, 4)).merge(negInfInterval) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(NegInfInterval!Date(Date(2010, 7, 5)).merge(negInfInterval) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(NegInfInterval!Date(Date(2012, 1, 6)).merge(negInfInterval) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(NegInfInterval!Date(Date(2012, 1, 7)).merge(negInfInterval) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(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))));
|
|
|
|
assert(negInfInterval.span(negInfInterval) ==
|
|
negInfInterval);
|
|
assert(negInfInterval.span(Interval!Date(Date(2010, 7, 1), Date(2010, 7, 3))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.span(Interval!Date(Date(2010, 7, 1), Date(2013, 7, 3))) ==
|
|
NegInfInterval!Date(Date(2013, 7, 3)));
|
|
assert(negInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 4))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2010, 7, 5))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 7))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.span(Interval!Date(Date(2010, 7, 3), Date(2012, 1, 8))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 8)));
|
|
assert(negInfInterval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 6))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.span(Interval!Date(Date(2010, 7, 5), Date(2012, 1, 7))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 7))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.span(Interval!Date(Date(2012, 1, 6), Date(2012, 1, 8))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 8)));
|
|
assert(negInfInterval.span(Interval!Date(Date(2012, 1, 7), Date(2012, 1, 8))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 8)));
|
|
assert(negInfInterval.span(Interval!Date(Date(2012, 1, 8), Date(2012, 1, 9))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 9)));
|
|
|
|
assert(negInfInterval.span(NegInfInterval!Date(Date(2010, 7, 3))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.span(NegInfInterval!Date(Date(2010, 7, 4))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.span(NegInfInterval!Date(Date(2010, 7, 5))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.span(NegInfInterval!Date(Date(2012, 1, 6))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.span(NegInfInterval!Date(Date(2012, 1, 7))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(negInfInterval.span(NegInfInterval!Date(Date(2012, 1, 8))) ==
|
|
NegInfInterval!Date(Date(2012, 1, 8)));
|
|
|
|
assert(NegInfInterval!Date(Date(2010, 7, 3)).span(negInfInterval) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(NegInfInterval!Date(Date(2010, 7, 4)).span(negInfInterval) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(NegInfInterval!Date(Date(2010, 7, 5)).span(negInfInterval) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(NegInfInterval!Date(Date(2012, 1, 6)).span(negInfInterval) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(NegInfInterval!Date(Date(2012, 1, 7)).span(negInfInterval) ==
|
|
NegInfInterval!Date(Date(2012, 1, 7)));
|
|
assert(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);
|
|
assert(interval == expected);
|
|
}
|
|
|
|
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);
|
|
assert(interval == expected);
|
|
}
|
|
|
|
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);
|
|
assert(interval == expected);
|
|
}
|
|
|
|
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);
|
|
assert(interval == expected);
|
|
}
|
|
|
|
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));
|
|
|
|
assert(NegInfInterval!Date(Date(2010, 10, 1)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.fri)).front ==
|
|
Date(2010, 10, 1));
|
|
|
|
assert(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 = delegate (in Date date)
|
|
{
|
|
if((date.day & 1) == 0)
|
|
return date - dur!"days"(2);
|
|
|
|
return date - dur!"days"(1);
|
|
};
|
|
auto range = interval.bwdRange(func);
|
|
|
|
//An odd day. Using PopFirst.yes would have made this Date(2010, 9, 8).
|
|
assert(range.front == Date(2010, 9, 9));
|
|
|
|
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
|
|
{
|
|
assert(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()));
|
|
}
|
|
|
|
|
|
/++
|
|
Range-generating function.
|
|
|
|
Returns a delegate which returns the next time point with the given
|
|
$(D DayOfWeek) in a range.
|
|
|
|
Using this delegate allows iteration over successive time points which
|
|
are all the same day of the week. e.g. passing $(D 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.
|
|
+/
|
|
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(typeof(TP.dayOfWeek) == DayOfWeek))
|
|
{
|
|
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 interval = Interval!Date(Date(2010, 9, 2), Date(2010, 9, 27));
|
|
auto func = everyDayOfWeek!Date(DayOfWeek.mon);
|
|
auto range = interval.fwdRange(func);
|
|
|
|
//A Thursday. Using PopFirst.yes would have made this Date(2010, 9, 6).
|
|
assert(range.front == Date(2010, 9, 2));
|
|
|
|
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);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto funcFwd = everyDayOfWeek!Date(DayOfWeek.mon);
|
|
auto funcBwd = everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.mon);
|
|
|
|
assert(funcFwd(Date(2010, 8, 28)) == Date(2010, 8, 30));
|
|
assert(funcFwd(Date(2010, 8, 29)) == Date(2010, 8, 30));
|
|
assert(funcFwd(Date(2010, 8, 30)) == Date(2010, 9, 6));
|
|
assert(funcFwd(Date(2010, 8, 31)) == Date(2010, 9, 6));
|
|
assert(funcFwd(Date(2010, 9, 1)) == Date(2010, 9, 6));
|
|
assert(funcFwd(Date(2010, 9, 2)) == Date(2010, 9, 6));
|
|
assert(funcFwd(Date(2010, 9, 3)) == Date(2010, 9, 6));
|
|
assert(funcFwd(Date(2010, 9, 4)) == Date(2010, 9, 6));
|
|
assert(funcFwd(Date(2010, 9, 5)) == Date(2010, 9, 6));
|
|
assert(funcFwd(Date(2010, 9, 6)) == Date(2010, 9, 13));
|
|
assert(funcFwd(Date(2010, 9, 7)) == Date(2010, 9, 13));
|
|
|
|
assert(funcBwd(Date(2010, 8, 28)) == Date(2010, 8, 23));
|
|
assert(funcBwd(Date(2010, 8, 29)) == Date(2010, 8, 23));
|
|
assert(funcBwd(Date(2010, 8, 30)) == Date(2010, 8, 23));
|
|
assert(funcBwd(Date(2010, 8, 31)) == Date(2010, 8, 30));
|
|
assert(funcBwd(Date(2010, 9, 1)) == Date(2010, 8, 30));
|
|
assert(funcBwd(Date(2010, 9, 2)) == Date(2010, 8, 30));
|
|
assert(funcBwd(Date(2010, 9, 3)) == Date(2010, 8, 30));
|
|
assert(funcBwd(Date(2010, 9, 4)) == Date(2010, 8, 30));
|
|
assert(funcBwd(Date(2010, 9, 5)) == Date(2010, 8, 30));
|
|
assert(funcBwd(Date(2010, 9, 6)) == Date(2010, 8, 30));
|
|
assert(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)));
|
|
}
|
|
|
|
|
|
/++
|
|
Range-generating function.
|
|
|
|
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 iteration over successive time points
|
|
which are in the same month but different years. For example,
|
|
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.
|
|
+/
|
|
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(typeof(TP.month) == Month))
|
|
{
|
|
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 interval = Interval!Date(Date(2000, 1, 30), Date(2004, 8, 5));
|
|
auto func = everyMonth!(Date)(Month.feb);
|
|
auto range = interval.fwdRange(func);
|
|
|
|
//Using PopFirst.yes would have made this Date(2010, 2, 29).
|
|
assert(range.front == Date(2000, 1, 30));
|
|
|
|
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);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto funcFwd = everyMonth!Date(Month.jun);
|
|
auto funcBwd = everyMonth!(Date, Direction.bwd)(Month.jun);
|
|
|
|
assert(funcFwd(Date(2010, 5, 31)) == Date(2010, 6, 30));
|
|
assert(funcFwd(Date(2010, 6, 30)) == Date(2011, 6, 30));
|
|
assert(funcFwd(Date(2010, 7, 31)) == Date(2011, 6, 30));
|
|
assert(funcFwd(Date(2010, 8, 31)) == Date(2011, 6, 30));
|
|
assert(funcFwd(Date(2010, 9, 30)) == Date(2011, 6, 30));
|
|
assert(funcFwd(Date(2010, 10, 31)) == Date(2011, 6, 30));
|
|
assert(funcFwd(Date(2010, 11, 30)) == Date(2011, 6, 30));
|
|
assert(funcFwd(Date(2010, 12, 31)) == Date(2011, 6, 30));
|
|
assert(funcFwd(Date(2011, 1, 31)) == Date(2011, 6, 30));
|
|
assert(funcFwd(Date(2011, 2, 28)) == Date(2011, 6, 28));
|
|
assert(funcFwd(Date(2011, 3, 31)) == Date(2011, 6, 30));
|
|
assert(funcFwd(Date(2011, 4, 30)) == Date(2011, 6, 30));
|
|
assert(funcFwd(Date(2011, 5, 31)) == Date(2011, 6, 30));
|
|
assert(funcFwd(Date(2011, 6, 30)) == Date(2012, 6, 30));
|
|
assert(funcFwd(Date(2011, 7, 31)) == Date(2012, 6, 30));
|
|
|
|
assert(funcBwd(Date(2010, 5, 31)) == Date(2009, 6, 30));
|
|
assert(funcBwd(Date(2010, 6, 30)) == Date(2009, 6, 30));
|
|
assert(funcBwd(Date(2010, 7, 31)) == Date(2010, 6, 30));
|
|
assert(funcBwd(Date(2010, 8, 31)) == Date(2010, 6, 30));
|
|
assert(funcBwd(Date(2010, 9, 30)) == Date(2010, 6, 30));
|
|
assert(funcBwd(Date(2010, 10, 31)) == Date(2010, 6, 30));
|
|
assert(funcBwd(Date(2010, 11, 30)) == Date(2010, 6, 30));
|
|
assert(funcBwd(Date(2010, 12, 31)) == Date(2010, 6, 30));
|
|
assert(funcBwd(Date(2011, 1, 31)) == Date(2010, 6, 30));
|
|
assert(funcBwd(Date(2011, 2, 28)) == Date(2010, 6, 28));
|
|
assert(funcBwd(Date(2011, 3, 31)) == Date(2010, 6, 30));
|
|
assert(funcBwd(Date(2011, 4, 30)) == Date(2010, 6, 30));
|
|
assert(funcBwd(Date(2011, 5, 31)) == Date(2010, 6, 30));
|
|
assert(funcBwd(Date(2011, 6, 30)) == Date(2010, 6, 30));
|
|
assert(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)));
|
|
}
|
|
|
|
|
|
/++
|
|
Range-generating function.
|
|
|
|
Returns a delegate which returns the next time point which is the given
|
|
duration later.
|
|
|
|
Using this delegate allows iteration 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.
|
|
+/
|
|
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 interval = Interval!Date(Date(2010, 9, 2), Date(2010, 9, 27));
|
|
auto func = everyDuration!Date(dur!"days"(8));
|
|
auto range = interval.fwdRange(func);
|
|
|
|
//Using PopFirst.yes would have made this Date(2010, 9, 10).
|
|
assert(range.front == Date(2010, 9, 2));
|
|
|
|
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);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto funcFwd = everyDuration!Date(dur!"days"(27));
|
|
auto funcBwd = everyDuration!(Date, Direction.bwd)(dur!"days"(27));
|
|
|
|
assert(funcFwd(Date(2009, 12, 25)) == Date(2010, 1, 21));
|
|
assert(funcFwd(Date(2009, 12, 26)) == Date(2010, 1, 22));
|
|
assert(funcFwd(Date(2009, 12, 27)) == Date(2010, 1, 23));
|
|
assert(funcFwd(Date(2009, 12, 28)) == Date(2010, 1, 24));
|
|
|
|
assert(funcBwd(Date(2010, 1, 21)) == Date(2009, 12, 25));
|
|
assert(funcBwd(Date(2010, 1, 22)) == Date(2009, 12, 26));
|
|
assert(funcBwd(Date(2010, 1, 23)) == Date(2009, 12, 27));
|
|
assert(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))));
|
|
}
|
|
|
|
|
|
/++
|
|
Range-generating function.
|
|
|
|
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 $(CXREF time, Duration) is that this one also takes the number of
|
|
years and months (along with an $(D 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
|
|
$(D AllowDayOverflow.yes) or $(D AllowDayOverflow.no) is used), it can't be
|
|
guaranteed that iterating backwards will give 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 $(D 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
|
|
$(D begin) and $(D end), causing their month to
|
|
increment.
|
|
duration = The duration to add to the time point passed to the
|
|
delegate.
|
|
+/
|
|
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 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);
|
|
|
|
//Using PopFirst.yes would have made this Date(2014, 10, 12).
|
|
assert(range.front == Date(2010, 9, 2));
|
|
|
|
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);
|
|
}
|
|
|
|
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));
|
|
|
|
assert(funcFwd(Date(2009, 12, 25)) == Date(2011, 2, 28));
|
|
assert(funcFwd(Date(2009, 12, 26)) == Date(2011, 3, 1));
|
|
assert(funcFwd(Date(2009, 12, 27)) == Date(2011, 3, 2));
|
|
assert(funcFwd(Date(2009, 12, 28)) == Date(2011, 3, 3));
|
|
assert(funcFwd(Date(2009, 12, 29)) == Date(2011, 3, 4));
|
|
|
|
assert(funcBwd(Date(2011, 2, 28)) == Date(2009, 12, 25));
|
|
assert(funcBwd(Date(2011, 3, 1)) == Date(2009, 12, 26));
|
|
assert(funcBwd(Date(2011, 3, 2)) == Date(2009, 12, 27));
|
|
assert(funcBwd(Date(2011, 3, 3)) == Date(2009, 12, 28));
|
|
assert(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));
|
|
|
|
assert(funcFwd(Date(2009, 12, 25)) == Date(2011, 2, 28));
|
|
assert(funcFwd(Date(2009, 12, 26)) == Date(2011, 3, 1));
|
|
assert(funcFwd(Date(2009, 12, 27)) == Date(2011, 3, 2));
|
|
assert(funcFwd(Date(2009, 12, 28)) == Date(2011, 3, 3));
|
|
assert(funcFwd(Date(2009, 12, 29)) == Date(2011, 3, 3));
|
|
|
|
assert(funcBwd(Date(2011, 2, 28)) == Date(2009, 12, 25));
|
|
assert(funcBwd(Date(2011, 3, 1)) == Date(2009, 12, 26));
|
|
assert(funcBwd(Date(2011, 3, 2)) == Date(2009, 12, 27));
|
|
assert(funcBwd(Date(2011, 3, 3)) == Date(2009, 12, 28));
|
|
assert(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))));
|
|
}
|
|
|
|
|
|
//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 $(LREF2 .Interval, Interval).
|
|
|
|
$(D IntervalRange) is only ever constructed by $(LREF2 .Interval, 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. For instance,
|
|
to iterate over all of the days in
|
|
the interval $(D Interval!Date), pass a function to $(LREF2 .Interval, Interval)'s $(D fwdRange)
|
|
where that function took a $(LREF Date) and returned a $(LREF Date) which was one
|
|
day later. That function would then be used by $(D IntervalRange)'s
|
|
$(D popFront) to iterate over the $(LREF Date)s in the interval.
|
|
|
|
If $(D dir == Direction.fwd), then a range iterates forward in time, whereas
|
|
if $(D dir == Direction.bwd), then it iterates backwards in time. So, if
|
|
$(D dir == Direction.fwd) then $(D front == interval.begin), whereas 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
|
|
$(LREF DateTimeException) will be thrown. So, to iterate forward in
|
|
time, the time point 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
|
|
$(LREF DateTimeException) will be thrown. To iterate 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
|
|
$(D end), then $(D front) becomes $(D end). If iterating backwards, and the
|
|
generated time point is before $(D begin), then $(D front) becomes
|
|
$(D begin). In either case, the range would then be empty.
|
|
|
|
Also note that while normally the $(D begin) of an interval is included in
|
|
it and its $(D end) is excluded from it, if $(D dir == Direction.bwd), then
|
|
$(D begin) is treated as excluded and $(D end) is treated as included. This
|
|
allows for the same behavior in both directions. This works because none of
|
|
$(LREF2 .Interval, Interval)'s functions which care about whether $(D begin) or $(D 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 $(LREF2 .Interval, Interval) functions which are
|
|
called on it which care about whether $(D begin) or $(D end) are included or
|
|
excluded will treat $(D begin) as included and $(D end) as excluded.
|
|
+/
|
|
struct IntervalRange(TP, Direction dir)
|
|
if(isTimePoint!TP && dir != Direction.both)
|
|
{
|
|
public:
|
|
|
|
/++
|
|
Params:
|
|
rhs = The $(D IntervalRange) to assign to this one.
|
|
+/
|
|
ref IntervalRange opAssign(ref IntervalRange rhs) pure nothrow
|
|
{
|
|
_interval = rhs._interval;
|
|
_func = rhs._func;
|
|
return this;
|
|
}
|
|
|
|
|
|
/++ Ditto +/
|
|
ref IntervalRange opAssign(IntervalRange rhs) pure nothrow
|
|
{
|
|
return this = rhs;
|
|
}
|
|
|
|
|
|
/++
|
|
Whether this $(D IntervalRange) is empty.
|
|
+/
|
|
@property bool empty() const pure nothrow
|
|
{
|
|
return _interval.empty;
|
|
}
|
|
|
|
|
|
/++
|
|
The first time point in the range.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the range is empty.
|
|
+/
|
|
@property TP front() const pure
|
|
{
|
|
_enforceNotEmpty();
|
|
|
|
static if(dir == Direction.fwd)
|
|
return _interval.begin;
|
|
else
|
|
return _interval.end;
|
|
}
|
|
|
|
|
|
/++
|
|
Pops $(D 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 $(D front) is set to that edge, and the range is then
|
|
empty. So, if iterating forwards, and the generated time point is
|
|
greater than the interval's $(D end), then $(D front) is set to
|
|
$(D end). If iterating backwards, and the generated time point is less
|
|
than the interval's $(D begin), then $(D front) is set to $(D begin).
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the range is empty or if the generated
|
|
time point is in the wrong direction (i.e. if iterating
|
|
forward and the generated time point is before $(D front), or if
|
|
iterating backwards and the generated time point is after
|
|
$(D 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 $(D 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 $(D 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:
|
|
$(LREF DateTimeException) if this interval is empty.
|
|
+/
|
|
void _enforceNotEmpty(size_t line = __LINE__) const pure
|
|
{
|
|
if(empty)
|
|
throw new DateTimeException("Invalid operation for an empty IntervalRange.", __FILE__, line);
|
|
}
|
|
|
|
|
|
/+
|
|
Throws:
|
|
$(LREF DateTimeException) if $(D_PARAM newTP) is in the wrong
|
|
direction.
|
|
+/
|
|
void _enforceCorrectDirection(in TP newTP, size_t line = __LINE__) const
|
|
{
|
|
import std.format : format;
|
|
|
|
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));
|
|
assert(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);
|
|
assert(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));
|
|
assert(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);
|
|
assert(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)
|
|
{
|
|
assert(date == expected);
|
|
expected += dur!"days"(7);
|
|
}
|
|
|
|
assert(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)
|
|
{
|
|
assert(date == expected);
|
|
expected += dur!"days"(-7);
|
|
}
|
|
|
|
assert(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. For
|
|
instance, to iterate
|
|
over all of the days in the interval $(D PosInfInterval!Date), pass a function to
|
|
$(D PosInfInterval)'s $(D fwdRange) where that function took a $(LREF Date) and
|
|
returned a $(LREF Date) which was one day later. That function would then be
|
|
used by $(D PosInfIntervalRange)'s $(D popFront) to iterate over the
|
|
$(LREF Date)s in the interval - though obviously, since the range is infinite,
|
|
use a function such as $(D std.range.take) with it rather than
|
|
iterating over $(I 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 $(LREF 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 $(LREF DateTimeException) will be thrown.
|
|
+/
|
|
struct PosInfIntervalRange(TP)
|
|
if(isTimePoint!TP)
|
|
{
|
|
public:
|
|
|
|
/++
|
|
Params:
|
|
rhs = The $(D PosInfIntervalRange) to assign to this one.
|
|
+/
|
|
ref PosInfIntervalRange opAssign(ref PosInfIntervalRange rhs) pure nothrow
|
|
{
|
|
_interval = rhs._interval;
|
|
_func = rhs._func;
|
|
|
|
return this;
|
|
}
|
|
|
|
|
|
/++ Ditto +/
|
|
ref PosInfIntervalRange opAssign(PosInfIntervalRange rhs) pure nothrow
|
|
{
|
|
return this = rhs;
|
|
}
|
|
|
|
|
|
/++
|
|
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 $(D front) from the range, using $(D func) to generate the next
|
|
time point in the range.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the generated time point is less than
|
|
$(D 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:
|
|
$(LREF DateTimeException) if $(D_PARAME newTP) is in the wrong
|
|
direction.
|
|
+/
|
|
void _enforceCorrectDirection(in TP newTP, size_t line = __LINE__) const
|
|
{
|
|
import std.format : format;
|
|
|
|
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));
|
|
assert(range.front == Date(2010, 7, 4));
|
|
|
|
auto poppedRange = PosInfInterval!Date(Date(2010, 7, 4)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes);
|
|
assert(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
|
|
{
|
|
import std.range;
|
|
auto range = PosInfInterval!Date(Date(2010, 7, 4)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes);
|
|
auto expected = range.front;
|
|
|
|
foreach(date; take(range, 79))
|
|
{
|
|
assert(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. For
|
|
instance, to iterate
|
|
over all of the days in the interval $(D NegInfInterval!Date), pass a function to
|
|
$(D NegInfInterval)'s $(D bwdRange) where that function took a $(LREF Date) and
|
|
returned a $(LREF Date) which was one day earlier. That function would then be
|
|
used by $(D NegInfIntervalRange)'s $(D popFront) to iterate over the
|
|
$(LREF Date)s in the interval - though obviously, since the range is infinite,
|
|
use a function such as $(D std.range.take) with it rather than
|
|
iterating over $(I 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 $(LREF 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
|
|
$(LREF DateTimeException) will be thrown.
|
|
|
|
Also note that while normally the $(D end) of an interval is excluded from
|
|
it, $(D NegInfIntervalRange) treats it as if it were included. This allows
|
|
for the same behavior as with $(D PosInfIntervalRange). This works
|
|
because none of $(D NegInfInterval)'s functions which care about whether
|
|
$(D 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 $(D end) is included or excluded will treat $(D end) as excluded.
|
|
+/
|
|
struct NegInfIntervalRange(TP)
|
|
if(isTimePoint!TP)
|
|
{
|
|
public:
|
|
|
|
/++
|
|
Params:
|
|
rhs = The $(D NegInfIntervalRange) to assign to this one.
|
|
+/
|
|
ref NegInfIntervalRange opAssign(ref NegInfIntervalRange rhs) pure nothrow
|
|
{
|
|
_interval = rhs._interval;
|
|
_func = rhs._func;
|
|
|
|
return this;
|
|
}
|
|
|
|
|
|
/++ Ditto +/
|
|
ref NegInfIntervalRange opAssign(NegInfIntervalRange rhs) pure nothrow
|
|
{
|
|
return this = rhs;
|
|
}
|
|
|
|
|
|
/++
|
|
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 $(D front) from the range, using $(D func) to generate the next
|
|
time point in the range.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the generated time point is greater than
|
|
$(D 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:
|
|
$(LREF DateTimeException) if $(D_PARAM newTP) is in the wrong
|
|
direction.
|
|
+/
|
|
void _enforceCorrectDirection(in TP newTP, size_t line = __LINE__) const
|
|
{
|
|
import std.format : format;
|
|
|
|
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));
|
|
assert(range.front == Date(2012, 1, 7));
|
|
|
|
auto poppedRange = NegInfInterval!Date(Date(2012, 1, 7)).bwdRange(everyDayOfWeek!(Date, Direction.bwd)(DayOfWeek.wed), PopFirst.yes);
|
|
assert(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
|
|
{
|
|
import std.range;
|
|
|
|
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))
|
|
{
|
|
assert(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 $(LREF SysTime) to indicate the time
|
|
zone of a $(LREF SysTime).
|
|
+/
|
|
abstract class TimeZone
|
|
{
|
|
public:
|
|
|
|
/++
|
|
The name of the time zone per the TZ Database. This is the name used to
|
|
get a $(LREF2 .TimeZone, TimeZone) by name with $(D TimeZone.getTimeZone).
|
|
|
|
See_Also:
|
|
$(WEB en.wikipedia.org/wiki/Tz_database, Wikipedia entry on TZ
|
|
Database)<br>
|
|
$(WEB en.wikipedia.org/wiki/List_of_tz_database_time_zones, List of
|
|
Time Zones)
|
|
+/
|
|
@property string name() @safe 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() @safe 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() @safe 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 $(D hasDST) because the time zone did at
|
|
some point have DST.
|
|
+/
|
|
@property abstract bool hasDST() @safe const nothrow;
|
|
|
|
|
|
/++
|
|
Takes the number of hnsecs (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) @safe const nothrow;
|
|
|
|
|
|
/++
|
|
Takes the number of hnsecs (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) @safe const nothrow;
|
|
|
|
|
|
/++
|
|
Takes the number of hnsecs (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) @safe const nothrow;
|
|
|
|
|
|
/++
|
|
Returns what the offset from UTC is at the given std time.
|
|
It includes the DST offset in effect at that time (if any).
|
|
|
|
Params:
|
|
stdTime = The UTC time for which to get the offset from UTC for this
|
|
time zone.
|
|
+/
|
|
Duration utcOffsetAt(long stdTime) @safe const nothrow
|
|
{
|
|
return dur!"hnsecs"(utcToTZ(stdTime) - stdTime);
|
|
}
|
|
|
|
|
|
/++
|
|
Returns a $(LREF2 .TimeZone, TimeZone) with the give name per the TZ Database.
|
|
|
|
This returns a $(LREF PosixTimeZone) on Posix systems and a
|
|
$(LREF WindowsTimeZone) on Windows systems. For
|
|
$(LREF PosixTimeZone) on Windows, call $(D PosixTimeZone.getTimeZone)
|
|
directly and give it the location of the TZ Database time zone files on
|
|
disk.
|
|
|
|
On Windows, the given TZ Database name is converted to the corresponding
|
|
time zone name on Windows prior to calling
|
|
$(D WindowsTimeZone.getTimeZone). This function allows for
|
|
the same time zone names on both Windows and Posix systems.
|
|
|
|
See_Also:
|
|
$(WEB en.wikipedia.org/wiki/Tz_database, Wikipedia entry on TZ
|
|
Database)<br>
|
|
$(WEB en.wikipedia.org/wiki/List_of_tz_database_time_zones, List of
|
|
Time Zones)<br>
|
|
$(WEB unicode.org/repos/cldr-tmp/trunk/diff/supplemental/zone_tzid.html,
|
|
Windows <-> TZ Database Name Conversion Table)
|
|
|
|
Params:
|
|
name = The TZ Database name of the desired time zone
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given time zone could not be found.
|
|
|
|
Examples:
|
|
--------------------
|
|
auto tz = TimeZone.getTimeZone("America/Los_Angeles");
|
|
--------------------
|
|
+/
|
|
static immutable(TimeZone) getTimeZone(string name) @safe
|
|
{
|
|
version(Posix)
|
|
return PosixTimeZone.getTimeZone(name);
|
|
else version(Windows)
|
|
{
|
|
import std.format : format;
|
|
auto windowsTZName = tzDatabaseNameToWindowsTZName(name);
|
|
if(windowsTZName != null)
|
|
{
|
|
try
|
|
return WindowsTimeZone.getTimeZone(windowsTZName);
|
|
catch(DateTimeException dte)
|
|
{
|
|
auto oldName = _getOldName(windowsTZName);
|
|
if(oldName != null)
|
|
return WindowsTimeZone.getTimeZone(oldName);
|
|
throw dte;
|
|
}
|
|
}
|
|
else
|
|
throw new DateTimeException(format("%s does not have an equivalent Windows time zone.", name));
|
|
}
|
|
}
|
|
|
|
// The purpose of this is to handle the case where a Windows time zone is
|
|
// new and exists on an up-to-date Windows box but does not exist on Windows
|
|
// boxes which have not been properly updated. The "date added" is included
|
|
// on the theory that we'll be able to remove them at some point in the
|
|
// the future once enough time has passed, and that way, we know how much
|
|
// time has passed.
|
|
private static string _getOldName(string windowsTZName) @safe pure nothrow
|
|
{
|
|
switch(windowsTZName)
|
|
{
|
|
case "Belarus Standard Time": return "Kaliningrad Standard Time"; // Added 2014-10-08
|
|
case "Russia Time Zone 10": return "Magadan Standard Time"; // Added 2014-10-08
|
|
case "Russia Time Zone 11": return "Magadan Standard Time"; // Added 2014-10-08
|
|
case "Russia Time Zone 3": return "Russian Standard Time"; // Added 2014-10-08
|
|
default: return null;
|
|
}
|
|
}
|
|
|
|
//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
|
|
{
|
|
import std.path : buildPath;
|
|
import std.file : exists, isFile;
|
|
import std.conv : to;
|
|
import std.format : format;
|
|
|
|
|
|
version(Posix) scope(exit) clearTZEnvVar();
|
|
|
|
static immutable(TimeZone) testTZ(string tzName,
|
|
string stdName,
|
|
string dstName,
|
|
Duration utcOffset,
|
|
Duration dstOffset,
|
|
bool north = true)
|
|
{
|
|
scope(failure) writefln("Failed time zone: %s", tzName);
|
|
|
|
immutable tz = TimeZone.getTimeZone(tzName);
|
|
immutable hasDST = dstOffset != dur!"hnsecs"(0);
|
|
|
|
version(Posix)
|
|
assert(tz.name == tzName);
|
|
else version(Windows)
|
|
assert(tz.name == stdName);
|
|
|
|
//assert(tz.stdName == stdName); //Locale-dependent
|
|
//assert(tz.dstName == dstName); //Locale-dependent
|
|
assert(tz.hasDST == hasDST);
|
|
|
|
immutable stdDate = DateTime(2010, north ? 1 : 7, 1, 6, 0, 0);
|
|
immutable dstDate = DateTime(2010, north ? 7 : 1, 1, 6, 0, 0);
|
|
auto std = SysTime(stdDate, tz);
|
|
auto dst = SysTime(dstDate, tz);
|
|
auto stdUTC = SysTime(stdDate - utcOffset, UTC());
|
|
auto dstUTC = SysTime(stdDate - utcOffset + dstOffset, UTC());
|
|
|
|
assert(!std.dstInEffect);
|
|
assert(dst.dstInEffect == hasDST);
|
|
assert(tz.utcOffsetAt(std.stdTime) == utcOffset);
|
|
assert(tz.utcOffsetAt(dst.stdTime) == utcOffset + dstOffset);
|
|
|
|
assert(cast(DateTime)std == stdDate);
|
|
assert(cast(DateTime)dst == dstDate);
|
|
assert(std == stdUTC);
|
|
|
|
version(Posix)
|
|
{
|
|
setTZEnvVar(tzName);
|
|
|
|
static void testTM(in SysTime st)
|
|
{
|
|
time_t unixTime = st.toUnixTime();
|
|
tm* osTimeInfo = localtime(&unixTime);
|
|
tm ourTimeInfo = st.toTM();
|
|
|
|
assert(ourTimeInfo.tm_sec == osTimeInfo.tm_sec);
|
|
assert(ourTimeInfo.tm_min == osTimeInfo.tm_min);
|
|
assert(ourTimeInfo.tm_hour == osTimeInfo.tm_hour);
|
|
assert(ourTimeInfo.tm_mday == osTimeInfo.tm_mday);
|
|
assert(ourTimeInfo.tm_mon == osTimeInfo.tm_mon);
|
|
assert(ourTimeInfo.tm_year == osTimeInfo.tm_year);
|
|
assert(ourTimeInfo.tm_wday == osTimeInfo.tm_wday);
|
|
assert(ourTimeInfo.tm_yday == osTimeInfo.tm_yday);
|
|
assert(ourTimeInfo.tm_isdst == osTimeInfo.tm_isdst);
|
|
assert(ourTimeInfo.tm_gmtoff == osTimeInfo.tm_gmtoff);
|
|
assert(to!string(ourTimeInfo.tm_zone) ==
|
|
to!string(osTimeInfo.tm_zone));
|
|
}
|
|
|
|
testTM(std);
|
|
testTM(dst);
|
|
|
|
//Apparently, right/ does not exist on Mac OS X. I don't know
|
|
//whether or not it exists on FreeBSD. It's rather pointless
|
|
//normally, since the Posix standard requires that leap seconds
|
|
//be ignored, so it does make some sense that right/ wouldn't
|
|
//be there, but since PosixTimeZone _does_ use leap seconds if
|
|
//the time zone file does, we'll test that functionality if the
|
|
//appropriate files exist.
|
|
if(buildPath(PosixTimeZone.defaultTZDatabaseDir, "right", tzName).exists)
|
|
{
|
|
auto leapTZ = PosixTimeZone.getTimeZone("right/" ~ tzName);
|
|
|
|
assert(leapTZ.name == "right/" ~ tzName);
|
|
//assert(leapTZ.stdName == stdName); //Locale-dependent
|
|
//assert(leapTZ.dstName == dstName); //Locale-dependent
|
|
assert(leapTZ.hasDST == hasDST);
|
|
|
|
auto leapSTD = SysTime(std.stdTime, leapTZ);
|
|
auto leapDST = SysTime(dst.stdTime, leapTZ);
|
|
|
|
assert(!leapSTD.dstInEffect);
|
|
assert(leapDST.dstInEffect == hasDST);
|
|
|
|
assert(leapSTD.stdTime == std.stdTime);
|
|
assert(leapDST.stdTime == dst.stdTime);
|
|
|
|
//Whenever a leap second is added/removed,
|
|
//this will have to be adjusted.
|
|
//enum leapDiff = convert!("seconds", "hnsecs")(25);
|
|
//assert(leapSTD.adjTime - leapDiff == std.adjTime);
|
|
//assert(leapDST.adjTime - leapDiff == dst.adjTime);
|
|
}
|
|
}
|
|
|
|
return tz;
|
|
}
|
|
|
|
auto dstSwitches = [/+America/Los_Angeles+/ tuple(DateTime(2012, 3, 11), DateTime(2012, 11, 4), 2, 2),
|
|
/+America/New_York+/ tuple(DateTime(2012, 3, 11), DateTime(2012, 11, 4), 2, 2),
|
|
///+America/Santiago+/ tuple(DateTime(2011, 8, 21), DateTime(2011, 5, 8), 0, 0),
|
|
/+Europe/London+/ tuple(DateTime(2012, 3, 25), DateTime(2012, 10, 28), 1, 2),
|
|
/+Europe/Paris+/ tuple(DateTime(2012, 3, 25), DateTime(2012, 10, 28), 2, 3),
|
|
/+Australia/Adelaide+/ tuple(DateTime(2012, 10, 7), DateTime(2012, 4, 1), 2, 3)];
|
|
|
|
version(Posix)
|
|
{
|
|
version(FreeBSD) enum utcZone = "Etc/UTC";
|
|
else version(linux) enum utcZone = "UTC";
|
|
else version(OSX) enum utcZone = "UTC";
|
|
else version(Android) enum utcZone = "UTC";
|
|
else static assert(0, "The location of the UTC timezone file on this Posix platform must be set.");
|
|
|
|
auto tzs = [testTZ("America/Los_Angeles", "PST", "PDT", dur!"hours"(-8), dur!"hours"(1)),
|
|
testTZ("America/New_York", "EST", "EDT", dur!"hours"(-5), dur!"hours"(1)),
|
|
//testTZ("America/Santiago", "CLT", "CLST", dur!"hours"(-4), dur!"hours"(1), false),
|
|
testTZ("Europe/London", "GMT", "BST", dur!"hours"(0), dur!"hours"(1)),
|
|
testTZ("Europe/Paris", "CET", "CEST", dur!"hours"(1), dur!"hours"(1)),
|
|
//Per www.timeanddate.com, it should be "CST" and "CDT",
|
|
//but the OS insists that it's "CST" for both. We should
|
|
//probably figure out how to report an error in the TZ
|
|
//database and report it.
|
|
testTZ("Australia/Adelaide", "CST", "CST",
|
|
dur!"hours"(9) + dur!"minutes"(30), dur!"hours"(1), false)];
|
|
|
|
testTZ(utcZone, "UTC", "UTC", dur!"hours"(0), dur!"hours"(0));
|
|
assertThrown!DateTimeException(PosixTimeZone.getTimeZone("hello_world"));
|
|
}
|
|
else version(Windows)
|
|
{
|
|
auto tzs = [testTZ("America/Los_Angeles", "Pacific Standard Time",
|
|
"Pacific Daylight Time", dur!"hours"(-8), dur!"hours"(1)),
|
|
testTZ("America/New_York", "Eastern Standard Time",
|
|
"Eastern Daylight Time", dur!"hours"(-5), dur!"hours"(1)),
|
|
//testTZ("America/Santiago", "Pacific SA Standard Time",
|
|
//"Pacific SA Daylight Time", dur!"hours"(-4), dur!"hours"(1), false),
|
|
testTZ("Europe/London", "GMT Standard Time",
|
|
"GMT Daylight Time", dur!"hours"(0), dur!"hours"(1)),
|
|
testTZ("Europe/Paris", "Romance Standard Time",
|
|
"Romance Daylight Time", dur!"hours"(1), dur!"hours"(1)),
|
|
testTZ("Australia/Adelaide", "Cen. Australia Standard Time",
|
|
"Cen. Australia Daylight Time",
|
|
dur!"hours"(9) + dur!"minutes"(30), dur!"hours"(1), false)];
|
|
|
|
testTZ("Atlantic/Reykjavik", "Greenwich Standard Time",
|
|
"Greenwich Daylight Time", dur!"hours"(0), dur!"hours"(0));
|
|
assertThrown!DateTimeException(WindowsTimeZone.getTimeZone("hello_world"));
|
|
}
|
|
else
|
|
assert(0, "OS not supported.");
|
|
|
|
foreach(i; 0 .. tzs.length)
|
|
{
|
|
auto tz = tzs[i];
|
|
immutable spring = dstSwitches[i][2];
|
|
immutable fall = dstSwitches[i][3];
|
|
auto stdOffset = SysTime(dstSwitches[i][0] + dur!"days"(-1), tz).utcOffset;
|
|
auto dstOffset = stdOffset + dur!"hours"(1);
|
|
|
|
//Verify that creating a SysTime in the given time zone results
|
|
//in a SysTime with the correct std time during and surrounding
|
|
//a DST switch.
|
|
foreach(hour; -12 .. 13)
|
|
{
|
|
auto st = SysTime(dstSwitches[i][0] + dur!"hours"(hour), tz);
|
|
immutable targetHour = hour < 0 ? hour + 24 : hour;
|
|
|
|
static void testHour(SysTime st, int hour, string tzName, size_t line = __LINE__)
|
|
{
|
|
enforce(st.hour == hour,
|
|
new AssertError(format("[%s] [%s]: [%s] [%s]", st, tzName, st.hour, hour),
|
|
__FILE__, line));
|
|
}
|
|
|
|
void testOffset1(Duration offset, bool dstInEffect, size_t line = __LINE__)
|
|
{
|
|
AssertError msg(string tag)
|
|
{
|
|
return new AssertError(format("%s [%s] [%s]: [%s] [%s] [%s]",
|
|
tag, st, tz.name, st.utcOffset, stdOffset, dstOffset),
|
|
__FILE__, line);
|
|
}
|
|
|
|
enforce(st.dstInEffect == dstInEffect, msg("1"));
|
|
enforce(st.utcOffset == offset, msg("2"));
|
|
enforce((st + dur!"minutes"(1)).utcOffset == offset, msg("3"));
|
|
}
|
|
|
|
if(hour == spring)
|
|
{
|
|
testHour(st, spring + 1, tz.name);
|
|
testHour(st + dur!"minutes"(1), spring + 1, tz.name);
|
|
}
|
|
else
|
|
{
|
|
testHour(st, targetHour, tz.name);
|
|
testHour(st + dur!"minutes"(1), targetHour, tz.name);
|
|
}
|
|
|
|
if(hour < spring)
|
|
testOffset1(stdOffset, false);
|
|
else
|
|
testOffset1(dstOffset, true);
|
|
|
|
st = SysTime(dstSwitches[i][1] + dur!"hours"(hour), tz);
|
|
testHour(st, targetHour, tz.name);
|
|
|
|
//Verify that 01:00 is the first 01:00 (or whatever hour before the switch is).
|
|
if(hour == fall - 1)
|
|
testHour(st + dur!"hours"(1), targetHour, tz.name);
|
|
|
|
if(hour < fall)
|
|
testOffset1(dstOffset, true);
|
|
else
|
|
testOffset1(stdOffset, false);
|
|
}
|
|
|
|
//Verify that converting a time in UTC to a time in another
|
|
//time zone results in the correct time during and surrounding
|
|
//a DST switch.
|
|
bool first = true;
|
|
auto springSwitch = SysTime(dstSwitches[i][0] + dur!"hours"(spring), UTC()) - stdOffset;
|
|
auto fallSwitch = SysTime(dstSwitches[i][1] + dur!"hours"(fall), UTC()) - dstOffset;
|
|
//@@@BUG@@@ 3659 makes this necessary.
|
|
auto fallSwitchMinus1 = fallSwitch - dur!"hours"(1);
|
|
|
|
foreach(hour; -24 .. 25)
|
|
{
|
|
auto utc = SysTime(dstSwitches[i][0] + dur!"hours"(hour), UTC());
|
|
auto local = utc.toOtherTZ(tz);
|
|
|
|
void testOffset2(Duration offset, size_t line = __LINE__)
|
|
{
|
|
AssertError msg(string tag)
|
|
{
|
|
return new AssertError(format("%s [%s] [%s]: [%s] [%s]", tag, hour, tz.name, utc, local),
|
|
__FILE__, line);
|
|
}
|
|
|
|
enforce((utc + offset).hour == local.hour, msg("1"));
|
|
enforce((utc + offset + dur!"minutes"(1)).hour == local.hour, msg("2"));
|
|
}
|
|
|
|
if(utc < springSwitch)
|
|
testOffset2(stdOffset);
|
|
else
|
|
testOffset2(dstOffset);
|
|
|
|
utc = SysTime(dstSwitches[i][1] + dur!"hours"(hour), UTC());
|
|
local = utc.toOtherTZ(tz);
|
|
|
|
if(utc == fallSwitch || utc == fallSwitchMinus1)
|
|
{
|
|
if(first)
|
|
{
|
|
testOffset2(dstOffset);
|
|
first = false;
|
|
}
|
|
else
|
|
testOffset2(stdOffset);
|
|
}
|
|
else if(utc > fallSwitch)
|
|
testOffset2(stdOffset);
|
|
else
|
|
testOffset2(dstOffset);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
Returns a list of the names of the time zones installed on the system.
|
|
|
|
Providing a sub-name narrows down the list of time zones (which
|
|
can number in the thousands). For example,
|
|
passing in "America" as the sub-name returns only the time zones which
|
|
begin with "America".
|
|
|
|
On Windows, this function will convert the Windows time zone names to
|
|
the corresponding TZ Database names with
|
|
$(D windowsTZNameToTZDatabaseName). To get the actual Windows time
|
|
zone names, use $(D WindowsTimeZone.getInstalledTZNames) directly.
|
|
|
|
Params:
|
|
subName = The first part of the time zones desired.
|
|
|
|
Throws:
|
|
$(D FileException) on Posix systems if it fails to read from disk.
|
|
$(LREF DateTimeException) on Windows systems if it fails to read the
|
|
registry.
|
|
+/
|
|
static string[] getInstalledTZNames(string subName = "") @safe
|
|
{
|
|
version(Posix)
|
|
return PosixTimeZone.getInstalledTZNames(subName);
|
|
else version(Windows)
|
|
{
|
|
import std.array : appender;
|
|
import std.algorithm : startsWith, sort;
|
|
import std.format : format;
|
|
|
|
auto windowsNames = WindowsTimeZone.getInstalledTZNames();
|
|
auto retval = appender!(string[])();
|
|
|
|
foreach(winName; windowsNames)
|
|
{
|
|
auto tzName = windowsTZNameToTZDatabaseName(winName);
|
|
|
|
version(unittest)
|
|
{
|
|
import std.string;
|
|
assert(tzName !is null, format("TZName which is missing: %s", winName));
|
|
}
|
|
|
|
if(tzName !is null && tzName.startsWith(subName))
|
|
retval.put(tzName);
|
|
}
|
|
|
|
sort(retval.data);
|
|
return retval.data;
|
|
}
|
|
}
|
|
|
|
unittest
|
|
{
|
|
static void testPZSuccess(string tzName)
|
|
{
|
|
scope(failure) writefln("TZName which threw: %s", tzName);
|
|
TimeZone.getTimeZone(tzName);
|
|
}
|
|
|
|
auto tzNames = getInstalledTZNames();
|
|
// This was not previously tested, and it's currently failing, so I'm
|
|
// leaving it commented out until I can sort it out.
|
|
//assert(equal(tzNames, tzNames.uniq()));
|
|
|
|
foreach(tzName; tzNames)
|
|
assertNotThrown!DateTimeException(testPZSuccess(tzName));
|
|
}
|
|
|
|
|
|
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) @safe immutable pure
|
|
{
|
|
_name = name;
|
|
_stdName = stdName;
|
|
_dstName = dstName;
|
|
}
|
|
|
|
|
|
immutable string _name;
|
|
immutable string _stdName;
|
|
immutable string _dstName;
|
|
}
|
|
|
|
|
|
/++
|
|
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
|
|
$(LREF PosixTimeZone) and $(LREF 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:
|
|
|
|
/++
|
|
$(LREF LocalTime) is a singleton class. $(LREF LocalTime) returns its only
|
|
instance.
|
|
+/
|
|
static immutable(LocalTime) opCall() @trusted pure nothrow
|
|
{
|
|
alias @safe pure nothrow immutable(LocalTime) function() FuncType;
|
|
return (cast(FuncType)&singleton)();
|
|
}
|
|
|
|
|
|
version(StdDdoc)
|
|
{
|
|
/++
|
|
The name of the time zone per the TZ Database. This is the name used to
|
|
get a $(LREF2 .TimeZone, 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 $(D stdName) and $(D 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:
|
|
$(WEB en.wikipedia.org/wiki/Tz_database, Wikipedia entry on TZ
|
|
Database)<br>
|
|
$(WEB en.wikipedia.org/wiki/List_of_tz_database_time_zones, List
|
|
of Time Zones)
|
|
+/
|
|
@property override string name() @safe const nothrow;
|
|
}
|
|
|
|
|
|
/++
|
|
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() @trusted const nothrow
|
|
{
|
|
version(Posix)
|
|
{
|
|
import std.conv : to;
|
|
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");
|
|
assert(LocalTime().stdName == "PST");
|
|
|
|
setTZEnvVar("America/New_York");
|
|
assert(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() @trusted const nothrow
|
|
{
|
|
version(Posix)
|
|
{
|
|
import std.conv : to;
|
|
try
|
|
return to!string(tzname[1]);
|
|
catch(Exception e)
|
|
assert(0, "to!string(tzname[1]) 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();
|
|
|
|
version(FreeBSD)
|
|
{
|
|
// A bug on FreeBSD 9+ makes it so that this test fails.
|
|
// https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=168862
|
|
}
|
|
else
|
|
{
|
|
setTZEnvVar("America/Los_Angeles");
|
|
assert(LocalTime().dstName == "PDT");
|
|
}
|
|
|
|
setTZEnvVar("America/New_York");
|
|
assert(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 $(D hasDST) because the time zone
|
|
did at some point have DST.
|
|
+/
|
|
@property override bool hasDST() @trusted const nothrow
|
|
{
|
|
version(Posix)
|
|
{
|
|
static if(is(typeof(daylight)))
|
|
return cast(bool)(daylight);
|
|
else
|
|
{
|
|
try
|
|
{
|
|
auto currYear = (cast(Date)Clock.currTime()).year;
|
|
auto janOffset = SysTime(Date(currYear, 1, 4), cast(immutable)this).stdTime -
|
|
SysTime(Date(currYear, 1, 4), UTC()).stdTime;
|
|
auto julyOffset = SysTime(Date(currYear, 7, 4), cast(immutable)this).stdTime -
|
|
SysTime(Date(currYear, 7, 4), UTC()).stdTime;
|
|
|
|
return janOffset != julyOffset;
|
|
}
|
|
catch(Exception e)
|
|
assert(0, "Clock.currTime() threw.");
|
|
}
|
|
}
|
|
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);
|
|
|
|
setTZEnvVar("UTC");
|
|
assert(!LocalTime().hasDST);
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
Takes the number of hnsecs (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) @trusted 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);
|
|
}
|
|
|
|
|
|
/++
|
|
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:
|
|
$(D TimeZone.utcToTZ)
|
|
+/
|
|
override long utcToTZ(long stdTime) @trusted 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);
|
|
}
|
|
|
|
|
|
/++
|
|
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:
|
|
$(D TimeZone.tzToUTC)
|
|
|
|
Params:
|
|
adjTime = The time in this time zone that needs to be adjusted to
|
|
UTC time.
|
|
+/
|
|
override long tzToUTC(long adjTime) @trusted const nothrow
|
|
{
|
|
version(Posix)
|
|
{
|
|
time_t unixTime = stdTimeToUnixTime(adjTime);
|
|
|
|
immutable past = unixTime - cast(time_t)convert!("days", "seconds")(1);
|
|
tm* timeInfo = localtime(past < unixTime ? &past : &unixTime);
|
|
immutable pastOffset = timeInfo.tm_gmtoff;
|
|
|
|
immutable future = unixTime + cast(time_t)convert!("days", "seconds")(1);
|
|
timeInfo = localtime(future > unixTime ? &future : &unixTime);
|
|
immutable futureOffset = timeInfo.tm_gmtoff;
|
|
|
|
if(pastOffset == futureOffset)
|
|
return adjTime - convert!("seconds", "hnsecs")(pastOffset);
|
|
|
|
if(pastOffset < futureOffset)
|
|
unixTime -= cast(time_t)convert!("hours", "seconds")(1);
|
|
|
|
unixTime -= pastOffset;
|
|
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
|
|
{
|
|
import std.format : format;
|
|
|
|
assert(LocalTime().tzToUTC(LocalTime().utcToTZ(0)) == 0);
|
|
assert(LocalTime().utcToTZ(LocalTime().tzToUTC(0)) == 0);
|
|
|
|
assert(LocalTime().tzToUTC(LocalTime().utcToTZ(0)) == 0);
|
|
assert(LocalTime().utcToTZ(LocalTime().tzToUTC(0)) == 0);
|
|
|
|
version(Posix)
|
|
{
|
|
scope(exit) clearTZEnvVar();
|
|
|
|
auto tzInfos = [tuple("America/Los_Angeles", DateTime(2012, 3, 11), DateTime(2012, 11, 4), 2, 2),
|
|
tuple("America/New_York", DateTime(2012, 3, 11), DateTime(2012, 11, 4), 2, 2),
|
|
//tuple("America/Santiago", DateTime(2011, 8, 21), DateTime(2011, 5, 8), 0, 0),
|
|
tuple("Atlantic/Azores", DateTime(2011, 3, 27), DateTime(2011, 10, 30), 0, 1),
|
|
tuple("Europe/London", DateTime(2012, 3, 25), DateTime(2012, 10, 28), 1, 2),
|
|
tuple("Europe/Paris", DateTime(2012, 3, 25), DateTime(2012, 10, 28), 2, 3),
|
|
tuple("Australia/Adelaide", DateTime(2012, 10, 7), DateTime(2012, 4, 1), 2, 3)];
|
|
|
|
foreach(i; 0 .. tzInfos.length)
|
|
{
|
|
auto tzName = tzInfos[i][0];
|
|
setTZEnvVar(tzName);
|
|
immutable spring = tzInfos[i][3];
|
|
immutable fall = tzInfos[i][4];
|
|
auto stdOffset = SysTime(tzInfos[i][1] + dur!"hours"(-12)).utcOffset;
|
|
auto dstOffset = stdOffset + dur!"hours"(1);
|
|
|
|
//Verify that creating a SysTime in the given time zone results
|
|
//in a SysTime with the correct std time during and surrounding
|
|
//a DST switch.
|
|
foreach(hour; -12 .. 13)
|
|
{
|
|
auto st = SysTime(tzInfos[i][1] + dur!"hours"(hour));
|
|
immutable targetHour = hour < 0 ? hour + 24 : hour;
|
|
|
|
static void testHour(SysTime st, int hour, string tzName, size_t line = __LINE__)
|
|
{
|
|
enforce(st.hour == hour,
|
|
new AssertError(format("[%s] [%s]: [%s] [%s]", st, tzName, st.hour, hour),
|
|
__FILE__, line));
|
|
}
|
|
|
|
void testOffset1(Duration offset, bool dstInEffect, size_t line = __LINE__)
|
|
{
|
|
AssertError msg(string tag)
|
|
{
|
|
return new AssertError(format("%s [%s] [%s]: [%s] [%s] [%s]",
|
|
tag, st, tzName, st.utcOffset, stdOffset, dstOffset),
|
|
__FILE__, line);
|
|
}
|
|
|
|
enforce(st.dstInEffect == dstInEffect, msg("1"));
|
|
enforce(st.utcOffset == offset, msg("2"));
|
|
enforce((st + dur!"minutes"(1)).utcOffset == offset, msg("3"));
|
|
}
|
|
|
|
if(hour == spring)
|
|
{
|
|
testHour(st, spring + 1, tzName);
|
|
testHour(st + dur!"minutes"(1), spring + 1, tzName);
|
|
}
|
|
else
|
|
{
|
|
testHour(st, targetHour, tzName);
|
|
testHour(st + dur!"minutes"(1), targetHour, tzName);
|
|
}
|
|
|
|
if(hour < spring)
|
|
testOffset1(stdOffset, false);
|
|
else
|
|
testOffset1(dstOffset, true);
|
|
|
|
st = SysTime(tzInfos[i][2] + dur!"hours"(hour));
|
|
testHour(st, targetHour, tzName);
|
|
|
|
//Verify that 01:00 is the first 01:00 (or whatever hour before the switch is).
|
|
if(hour == fall - 1)
|
|
testHour(st + dur!"hours"(1), targetHour, tzName);
|
|
|
|
if(hour < fall)
|
|
testOffset1(dstOffset, true);
|
|
else
|
|
testOffset1(stdOffset, false);
|
|
}
|
|
|
|
//Verify that converting a time in UTC to a time in another
|
|
//time zone results in the correct time during and surrounding
|
|
//a DST switch.
|
|
bool first = true;
|
|
auto springSwitch = SysTime(tzInfos[i][1] + dur!"hours"(spring), UTC()) - stdOffset;
|
|
auto fallSwitch = SysTime(tzInfos[i][2] + dur!"hours"(fall), UTC()) - dstOffset;
|
|
//@@@BUG@@@ 3659 makes this necessary.
|
|
auto fallSwitchMinus1 = fallSwitch - dur!"hours"(1);
|
|
|
|
foreach(hour; -24 .. 25)
|
|
{
|
|
auto utc = SysTime(tzInfos[i][1] + dur!"hours"(hour), UTC());
|
|
auto local = utc.toLocalTime();
|
|
|
|
void testOffset2(Duration offset, size_t line = __LINE__)
|
|
{
|
|
AssertError msg(string tag)
|
|
{
|
|
return new AssertError(format("%s [%s] [%s]: [%s] [%s]", tag, hour, tzName, utc, local),
|
|
__FILE__, line);
|
|
}
|
|
|
|
enforce((utc + offset).hour == local.hour, msg("1"));
|
|
enforce((utc + offset + dur!"minutes"(1)).hour == local.hour, msg("2"));
|
|
}
|
|
|
|
if(utc < springSwitch)
|
|
testOffset2(stdOffset);
|
|
else
|
|
testOffset2(dstOffset);
|
|
|
|
utc = SysTime(tzInfos[i][2] + dur!"hours"(hour), UTC());
|
|
local = utc.toLocalTime();
|
|
|
|
if(utc == fallSwitch || utc == fallSwitchMinus1)
|
|
{
|
|
if(first)
|
|
{
|
|
testOffset2(dstOffset);
|
|
first = false;
|
|
}
|
|
else
|
|
testOffset2(stdOffset);
|
|
}
|
|
else if(utc > fallSwitch)
|
|
testOffset2(stdOffset);
|
|
else
|
|
testOffset2(dstOffset);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private:
|
|
|
|
this() @safe immutable pure
|
|
{
|
|
super("", "", "");
|
|
}
|
|
|
|
|
|
static immutable LocalTime _localTime = new immutable(LocalTime)();
|
|
// Use low-lock singleton pattern with _tzsetWasCalled (see http://dconf.org/talks/simcha.html)
|
|
static bool _lowLock;
|
|
static shared bool _tzsetWasCalled;
|
|
|
|
|
|
// This is done so that we can maintain purity in spite of doing an impure
|
|
// operation the first time that LocalTime() is called.
|
|
static immutable(LocalTime) singleton() @trusted
|
|
{
|
|
if(!_lowLock)
|
|
{
|
|
synchronized
|
|
{
|
|
if(!_tzsetWasCalled)
|
|
{
|
|
tzset();
|
|
_tzsetWasCalled = true;
|
|
}
|
|
}
|
|
|
|
_lowLock = true;
|
|
}
|
|
|
|
return _localTime;
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
A $(LREF2 .TimeZone, TimeZone) which represents UTC.
|
|
+/
|
|
final class UTC : TimeZone
|
|
{
|
|
public:
|
|
|
|
/++
|
|
$(D UTC) is a singleton class. $(D UTC) returns its only instance.
|
|
+/
|
|
static immutable(UTC) opCall() @safe pure nothrow
|
|
{
|
|
return _utc;
|
|
}
|
|
|
|
|
|
/++
|
|
Always returns false.
|
|
+/
|
|
@property override bool hasDST() @safe const nothrow
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
/++
|
|
Always returns false.
|
|
+/
|
|
override bool dstInEffect(long stdTime) @safe 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:
|
|
$(D TimeZone.utcToTZ)
|
|
+/
|
|
override long utcToTZ(long stdTime) @safe const nothrow
|
|
{
|
|
return stdTime;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(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));
|
|
assert(UTC().utcToTZ(std.stdTime) == std.stdTime);
|
|
assert(UTC().utcToTZ(dst.stdTime) == dst.stdTime);
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
Returns the given hnsecs without changing them at all.
|
|
|
|
See_Also:
|
|
$(D TimeZone.tzToUTC)
|
|
|
|
Params:
|
|
adjTime = The time in this time zone that needs to be adjusted to
|
|
UTC time.
|
|
+/
|
|
override long tzToUTC(long adjTime) @safe const nothrow
|
|
{
|
|
return adjTime;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(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));
|
|
assert(UTC().tzToUTC(std.stdTime) == std.stdTime);
|
|
assert(UTC().tzToUTC(dst.stdTime) == dst.stdTime);
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
Returns a $(CXREF time, Duration) of 0.
|
|
|
|
Params:
|
|
stdTime = The UTC time for which to get the offset from UTC for this
|
|
time zone.
|
|
+/
|
|
override Duration utcOffsetAt(long stdTime) @safe const nothrow
|
|
{
|
|
return dur!"hnsecs"(0);
|
|
}
|
|
|
|
|
|
private:
|
|
|
|
this() @safe immutable pure
|
|
{
|
|
super("UTC", "UTC", "UTC");
|
|
}
|
|
|
|
|
|
static immutable UTC _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 $(LREF SysTime)'s
|
|
$(D fromISOString), $(D fromISOExtString), 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() @safe const nothrow
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
/++
|
|
Always returns false.
|
|
+/
|
|
override bool dstInEffect(long stdTime) @safe const nothrow
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
/++
|
|
Takes the number of hnsecs (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) @safe const nothrow
|
|
{
|
|
return stdTime + _utcOffset.total!"hnsecs";
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto west = new immutable SimpleTimeZone(dur!"hours"(-8));
|
|
auto east = new immutable SimpleTimeZone(dur!"hours"(8));
|
|
|
|
assert(west.utcToTZ(0) == -288_000_000_000L);
|
|
assert(east.utcToTZ(0) == 288_000_000_000L);
|
|
assert(west.utcToTZ(54_321_234_567_890L) == 54_033_234_567_890L);
|
|
|
|
const cstz = west;
|
|
static assert(__traits(compiles, west.utcToTZ(50002)));
|
|
static assert(__traits(compiles, cstz.utcToTZ(50002)));
|
|
}
|
|
|
|
|
|
/++
|
|
Takes the number of hnsecs (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) @safe const nothrow
|
|
{
|
|
return adjTime - _utcOffset.total!"hnsecs";
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto west = new immutable SimpleTimeZone(dur!"hours"(-8));
|
|
auto east = new immutable SimpleTimeZone(dur!"hours"(8));
|
|
|
|
assert(west.tzToUTC(-288_000_000_000L) == 0);
|
|
assert(east.tzToUTC(288_000_000_000L) == 0);
|
|
assert(west.tzToUTC(54_033_234_567_890L) == 54_321_234_567_890L);
|
|
|
|
const cstz = west;
|
|
static assert(__traits(compiles, west.tzToUTC(20005)));
|
|
static assert(__traits(compiles, cstz.tzToUTC(20005)));
|
|
}
|
|
|
|
|
|
/++
|
|
Returns utcOffset as a $(CXREF time, Duration).
|
|
|
|
Params:
|
|
stdTime = The UTC time for which to get the offset from UTC for this
|
|
time zone.
|
|
+/
|
|
override Duration utcOffsetAt(long stdTime) @safe const nothrow
|
|
{
|
|
return _utcOffset;
|
|
}
|
|
|
|
|
|
/++
|
|
Params:
|
|
utcOffset = This time zone's offset from UTC with west of UTC being
|
|
negative (it is added to UTC to get the adjusted time).
|
|
stdName = The $(D stdName) for this time zone.
|
|
+/
|
|
this(Duration utcOffset, string stdName = "") @safe immutable pure
|
|
{
|
|
//FIXME This probably needs to be changed to something like (-12 - 13).
|
|
enforce!DateTimeException(abs(utcOffset) < dur!"minutes"(1440),
|
|
"Offset from UTC must be within range (-24:00 - 24:00).");
|
|
|
|
super("", stdName, "");
|
|
this._utcOffset = utcOffset;
|
|
}
|
|
|
|
/++
|
|
$(RED Deprecated. Please use the overload which takes a Duration. This
|
|
overload will be removed in December 2014).
|
|
|
|
Params:
|
|
utcOffset = This time zone's offset from UTC in minutes with west of
|
|
negative (it is added to UTC to get the adjusted time).
|
|
stdName = The $(D stdName) for this time zone.
|
|
+/
|
|
deprecated("Please use the overload which takes a Duration.")
|
|
this(int utcOffset, string stdName = "") @safe immutable pure
|
|
{
|
|
this(dur!"minutes"(utcOffset), stdName);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto stz = new immutable SimpleTimeZone(dur!"hours"(-8), "PST");
|
|
assert(stz.name == "");
|
|
assert(stz.stdName == "PST");
|
|
assert(stz.dstName == "");
|
|
assert(stz.utcOffset == dur!"hours"(-8));
|
|
}
|
|
|
|
|
|
/++
|
|
The amount of time the offset from UTC is (negative is west of UTC,
|
|
positive is east).
|
|
+/
|
|
@property Duration utcOffset() @safe const pure nothrow
|
|
{
|
|
return _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(Duration utcOffset) @safe pure
|
|
{
|
|
import std.format : format;
|
|
|
|
immutable absOffset = abs(utcOffset);
|
|
enforce!DateTimeException(absOffset < dur!"minutes"(1440),
|
|
"Offset from UTC must be within range (-24:00 - 24:00).");
|
|
int hours;
|
|
int minutes;
|
|
absOffset.split!("hours", "minutes")(hours, minutes);
|
|
return format(utcOffset < Duration.zero ? "-%02d:%02d" : "+%02d:%02d", hours, minutes);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
static string testSTZInvalid(Duration offset)
|
|
{
|
|
return SimpleTimeZone.toISOString(offset);
|
|
}
|
|
|
|
assertThrown!DateTimeException(testSTZInvalid(dur!"minutes"(1440)));
|
|
assertThrown!DateTimeException(testSTZInvalid(dur!"minutes"(-1440)));
|
|
|
|
assert(toISOString(dur!"minutes"(0)) == "+00:00");
|
|
assert(toISOString(dur!"minutes"(1)) == "+00:01");
|
|
assert(toISOString(dur!"minutes"(10)) == "+00:10");
|
|
assert(toISOString(dur!"minutes"(59)) == "+00:59");
|
|
assert(toISOString(dur!"minutes"(60)) == "+01:00");
|
|
assert(toISOString(dur!"minutes"(90)) == "+01:30");
|
|
assert(toISOString(dur!"minutes"(120)) == "+02:00");
|
|
assert(toISOString(dur!"minutes"(480)) == "+08:00");
|
|
assert(toISOString(dur!"minutes"(1439)) == "+23:59");
|
|
|
|
assert(toISOString(dur!"minutes"(-1)) == "-00:01");
|
|
assert(toISOString(dur!"minutes"(-10)) == "-00:10");
|
|
assert(toISOString(dur!"minutes"(-59)) == "-00:59");
|
|
assert(toISOString(dur!"minutes"(-60)) == "-01:00");
|
|
assert(toISOString(dur!"minutes"(-90)) == "-01:30");
|
|
assert(toISOString(dur!"minutes"(-120)) == "-02:00");
|
|
assert(toISOString(dur!"minutes"(-480)) == "-08:00");
|
|
assert(toISOString(dur!"minutes"(-1439)) == "-23:59");
|
|
}
|
|
|
|
|
|
/+
|
|
Takes a time zone as a string with an offset from UTC and returns a
|
|
$(LREF 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) @safe pure
|
|
if(isSomeString!S)
|
|
{
|
|
import std.ascii : isDigit;
|
|
import std.string : strip;
|
|
import std.conv : to;
|
|
import std.algorithm : startsWith, countUntil, all;
|
|
import std.format : format;
|
|
|
|
auto dstr = to!dstring(strip(isoString));
|
|
|
|
enforce(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.countUntil(':');
|
|
|
|
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(all!isDigit(hoursStr), new DateTimeException(format("Invalid ISO String: %s", dstr)));
|
|
enforce(all!isDigit(minutesStr), new DateTimeException(format("Invalid ISO String: %s", dstr)));
|
|
|
|
immutable hours = to!int(hoursStr);
|
|
immutable minutes = minutesStr.empty ? 0 : to!int(minutesStr);
|
|
|
|
return new immutable SimpleTimeZone(sign * (dur!"hours"(hours) + dur!"minutes"(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"));
|
|
|
|
assert(SimpleTimeZone.fromISOString("+00:00").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(0))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("+00:01").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(1))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("+00:10").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(10))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("+00:59").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(59))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("+01:00").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(60))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("+01:30").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(90))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("+02:00").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(120))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("+08:00").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(480))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("+23:59").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(1439))).utcOffset);
|
|
|
|
assert(SimpleTimeZone.fromISOString("-00:01").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(-1))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("-00:10").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(-10))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("-00:59").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(-59))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("-01:00").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(-60))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("-01:30").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(-90))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("-02:00").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(-120))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("-08:00").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(-480))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("-23:59").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(-1439))).utcOffset);
|
|
|
|
assert(SimpleTimeZone.fromISOString("+0").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(0))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("+1").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(60))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("+2").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(120))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("+23").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(1380))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("+2").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(120))).utcOffset);
|
|
|
|
assert(SimpleTimeZone.fromISOString("+0").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(0))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("+1").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(60))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("+2").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(120))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("+23").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(1380))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("+1:00").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(60))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("+1:01").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(61))).utcOffset);
|
|
|
|
assert(SimpleTimeZone.fromISOString("-0").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(0))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("-1").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(-60))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("-2").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(-120))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("-23").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(-1380))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("-1:00").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(-60))).utcOffset);
|
|
assert(SimpleTimeZone.fromISOString("-1:01").utcOffset ==
|
|
(new immutable SimpleTimeZone(dur!"minutes"(-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);
|
|
assert(stz.utcOffset == dur!"minutes"(expectedOffset));
|
|
|
|
auto result = SimpleTimeZone.toISOString(stz.utcOffset);
|
|
assert(result == isoString);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
immutable Duration _utcOffset;
|
|
}
|
|
|
|
|
|
/++
|
|
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. To use the TZ Database,
|
|
use $(D PosixTimeZone) (which reads its information from the TZ Database
|
|
files on disk) on Windows by providing the TZ Database files and telling
|
|
$(D PosixTimeZone.getTimeZone) where the directory holding them is.
|
|
|
|
To get a $(D PosixTimeZone), either call $(D PosixTimeZone.getTimeZone)
|
|
(which allows specifying the location the time zone files) or call
|
|
$(D TimeZone.getTimeZone) (which will give a $(D PosixTimeZone) on Posix
|
|
systems and a $(LREF WindowsTimeZone) on Windows systems).
|
|
|
|
Note:
|
|
Unless your system's local time zone deals with leap seconds (which is
|
|
highly unlikely), then the only way to get a time zone which
|
|
takes leap seconds into account is to use $(LREF PosixTimeZone) with a
|
|
time zone whose name starts with "right/". Those time zone files do
|
|
include leap seconds, and $(LREF PosixTimeZone) will take them into account
|
|
(though posix systems which use a "right/" time zone as their local time
|
|
zone will $(I not) take leap seconds into account even though they're
|
|
in the file).
|
|
|
|
See_Also:
|
|
$(WEB www.iana.org/time-zones, Home of the TZ Database files)<br>
|
|
$(WEB en.wikipedia.org/wiki/Tz_database, Wikipedia entry on TZ Database)<br>
|
|
$(WEB en.wikipedia.org/wiki/List_of_tz_database_time_zones, List of Time
|
|
Zones)
|
|
+/
|
|
final class PosixTimeZone : TimeZone
|
|
{
|
|
import std.stdio : File;
|
|
import std.path : buildNormalizedPath, extension;
|
|
import std.file : isDir, isFile, exists, dirEntries, SpanMode, DirEntry;
|
|
import std.string : strip, representation;
|
|
import std.algorithm : countUntil, canFind, startsWith;
|
|
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 $(D hasDST) because the time zone
|
|
did at some point have DST.
|
|
+/
|
|
@property override bool hasDST() @safe const nothrow
|
|
{
|
|
return _hasDST;
|
|
}
|
|
|
|
|
|
/++
|
|
Takes the number of hnsecs (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) @safe const nothrow
|
|
{
|
|
assert(!_transitions.empty);
|
|
|
|
immutable unixTime = stdTimeToUnixTime(stdTime);
|
|
immutable found = countUntil!"b < a.timeT"(_transitions, unixTime);
|
|
|
|
if(found == -1)
|
|
return _transitions.back.ttInfo.isDST;
|
|
|
|
immutable transition = found == 0 ? _transitions[0] : _transitions[found - 1];
|
|
|
|
return transition.ttInfo.isDST;
|
|
}
|
|
|
|
|
|
/++
|
|
Takes the number of hnsecs (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) @safe const nothrow
|
|
{
|
|
assert(!_transitions.empty);
|
|
|
|
immutable leapSecs = calculateLeapSeconds(stdTime);
|
|
immutable unixTime = stdTimeToUnixTime(stdTime);
|
|
immutable found = countUntil!"b < a.timeT"(_transitions, unixTime);
|
|
|
|
if(found == -1)
|
|
return stdTime + convert!("seconds", "hnsecs")(_transitions.back.ttInfo.utcOffset + leapSecs);
|
|
|
|
immutable transition = found == 0 ? _transitions[0] : _transitions[found - 1];
|
|
|
|
return stdTime + convert!("seconds", "hnsecs")(transition.ttInfo.utcOffset + leapSecs);
|
|
}
|
|
|
|
|
|
/++
|
|
Takes the number of hnsecs (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) @safe const nothrow
|
|
{
|
|
assert(!_transitions.empty);
|
|
|
|
immutable leapSecs = calculateLeapSeconds(adjTime);
|
|
time_t unixTime = stdTimeToUnixTime(adjTime);
|
|
immutable past = unixTime - convert!("days", "seconds")(1);
|
|
immutable future = unixTime + convert!("days", "seconds")(1);
|
|
|
|
immutable pastFound = countUntil!"b < a.timeT"(_transitions, past);
|
|
|
|
if(pastFound == -1)
|
|
return adjTime - convert!("seconds", "hnsecs")(_transitions.back.ttInfo.utcOffset + leapSecs);
|
|
|
|
immutable futureFound = countUntil!"b < a.timeT"(_transitions[pastFound .. $], future);
|
|
immutable pastTrans = pastFound == 0 ? _transitions[0] : _transitions[pastFound - 1];
|
|
|
|
if(futureFound == 0)
|
|
return adjTime - convert!("seconds", "hnsecs")(pastTrans.ttInfo.utcOffset + leapSecs);
|
|
|
|
immutable futureTrans = futureFound == -1 ? _transitions.back
|
|
: _transitions[pastFound + futureFound - 1];
|
|
immutable pastOffset = pastTrans.ttInfo.utcOffset;
|
|
|
|
if(pastOffset < futureTrans.ttInfo.utcOffset)
|
|
unixTime -= convert!("hours", "seconds")(1);
|
|
|
|
immutable found = countUntil!"b < a.timeT"(_transitions[pastFound .. $], unixTime - pastOffset);
|
|
|
|
if(found == -1)
|
|
return adjTime - convert!("seconds", "hnsecs")(_transitions.back.ttInfo.utcOffset + leapSecs);
|
|
|
|
immutable transition = found == 0 ? pastTrans : _transitions[pastFound + found - 1];
|
|
|
|
return adjTime - convert!("seconds", "hnsecs")(transition.ttInfo.utcOffset + leapSecs);
|
|
}
|
|
|
|
|
|
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 $(LREF2 .TimeZone, 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:
|
|
$(WEB en.wikipedia.org/wiki/Tz_database, Wikipedia entry on TZ
|
|
Database)<br>
|
|
$(WEB en.wikipedia.org/wiki/List_of_tz_database_time_zones, List of
|
|
Time Zones)
|
|
|
|
Params:
|
|
name = The TZ Database name of the desired time zone
|
|
tzDatabaseDir = The directory where the TZ Database files are
|
|
located. Because these files are not located on
|
|
Windows systems, provide them
|
|
and give their location here to
|
|
use $(LREF PosixTimeZone)s.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given time zone could not be found or
|
|
$(D 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) @trusted
|
|
{
|
|
import std.algorithm : sort;
|
|
import std.range : retro;
|
|
import std.format : format;
|
|
|
|
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)));
|
|
|
|
immutable file = buildNormalizedPath(tzDatabaseDir, name);
|
|
|
|
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.representation().canFind("GMT");
|
|
|
|
try
|
|
{
|
|
_enforceValidTZFile(readVal!(char[])(tzFile, 4) == "TZif");
|
|
|
|
immutable char tzFileVersion = readVal!char(tzFile);
|
|
_enforceValidTZFile(tzFileVersion == '\0' || tzFileVersion == '2' || tzFileVersion == '3');
|
|
|
|
{
|
|
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 or 3, the information is duplicated in 64-bit.
|
|
if(tzFileVersion == '2' || tzFileVersion == '3')
|
|
{
|
|
_enforceValidTZFile(readVal!(char[])(tzFile, 4) == "TZif");
|
|
|
|
immutable char tzFileVersion2 = readVal!(char)(tzFile);
|
|
_enforceValidTZFile(tzFileVersion2 == '2' || tzFileVersion2 == '3');
|
|
|
|
{
|
|
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 .. abbrevChars.countUntil('\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 immutable 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);
|
|
}
|
|
|
|
/++
|
|
Returns a list of the names of the time zones installed on the system.
|
|
|
|
Providing a sub-name narrows down the list of time zones (which
|
|
can number in the thousands). For example,
|
|
passing in "America" as the sub-name returns only the time zones which
|
|
begin with "America".
|
|
|
|
Params:
|
|
subName = The first part of the desired time zones.
|
|
tzDatabaseDir = The directory where the TZ Database files are
|
|
located.
|
|
|
|
Throws:
|
|
$(D FileException) if it fails to read from disk.
|
|
+/
|
|
static string[] getInstalledTZNames(string subName = "", string tzDatabaseDir = defaultTZDatabaseDir) @trusted
|
|
{
|
|
import std.array : appender;
|
|
import std.algorithm : sort;
|
|
import std.format : format;
|
|
|
|
version(Posix)
|
|
subName = strip(subName);
|
|
else version(Windows)
|
|
{
|
|
import std.array : replace;
|
|
import std.path : dirSeparator;
|
|
subName = replace(strip(subName), "/", dirSeparator);
|
|
}
|
|
|
|
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.extension().empty ||
|
|
!tzName.startsWith(subName) ||
|
|
tzName == "+VERSION")
|
|
{
|
|
continue;
|
|
}
|
|
|
|
timezones.put(tzName);
|
|
}
|
|
}
|
|
|
|
sort(timezones.data);
|
|
|
|
return timezones.data;
|
|
}
|
|
|
|
version(Posix) unittest
|
|
{
|
|
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 $(D TTInfo) which
|
|
holds information on the utc offset past the transition.
|
|
+/
|
|
struct Transition
|
|
{
|
|
this(long timeT, immutable (TTInfo)* ttInfo) @safe pure
|
|
{
|
|
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) @safe pure
|
|
{
|
|
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) @safe immutable pure
|
|
{
|
|
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 $(D TTInfo) while organizing
|
|
the time zone information prior to putting it in its final form.
|
|
+/
|
|
struct TempTTInfo
|
|
{
|
|
this(int gmtOff, bool isDST, ubyte abbrInd) @safe pure
|
|
{
|
|
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 $(D 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) @safe pure
|
|
{
|
|
this.timeT = timeT;
|
|
this.ttInfo = ttInfo;
|
|
this.ttype = ttype;
|
|
}
|
|
|
|
long timeT;
|
|
immutable (TTInfo)* ttInfo;
|
|
TransitionType* ttype;
|
|
}
|
|
|
|
|
|
/+
|
|
Struct used to hold information relating to $(D Transition) and
|
|
$(D TTInfo) while organizing the time zone information prior to putting
|
|
it in its final form.
|
|
+/
|
|
struct TransitionType
|
|
{
|
|
this(bool isStd, bool inUTC) @safe pure
|
|
{
|
|
this.isStd = isStd;
|
|
this.inUTC = inUTC;
|
|
}
|
|
|
|
/// Whether the transition is in std time (as opposed to wall clock time).
|
|
bool isStd;
|
|
|
|
/// Whether the transition is in UTC (as opposed to local time).
|
|
bool inUTC;
|
|
}
|
|
|
|
|
|
/+
|
|
Reads an int from a TZ file.
|
|
+/
|
|
static T readVal(T)(ref File tzFile) @trusted
|
|
if((isIntegral!T || isSomeChar!T) || is(Unqual!T == bool))
|
|
{
|
|
import std.bitmanip;
|
|
T[1] buff;
|
|
|
|
_enforceValidTZFile(!tzFile.eof);
|
|
tzFile.rawRead(buff);
|
|
|
|
return bigEndianToNative!T(cast(ubyte[T.sizeof])buff);
|
|
}
|
|
|
|
/+
|
|
Reads an array of values from a TZ file.
|
|
+/
|
|
static T readVal(T)(ref File tzFile, size_t length) @trusted
|
|
if(isArray!T)
|
|
{
|
|
auto buff = new T(length);
|
|
|
|
_enforceValidTZFile(!tzFile.eof);
|
|
tzFile.rawRead(buff);
|
|
|
|
return buff;
|
|
}
|
|
|
|
|
|
/+
|
|
Reads a $(D TempTTInfo) from a TZ file.
|
|
+/
|
|
static T readVal(T)(ref File tzFile) @safe
|
|
if(is(T == TempTTInfo))
|
|
{
|
|
return TempTTInfo(readVal!int(tzFile),
|
|
readVal!bool(tzFile),
|
|
readVal!ubyte(tzFile));
|
|
}
|
|
|
|
|
|
/+
|
|
Throws:
|
|
$(LREF DateTimeException) if $(D result) is false.
|
|
+/
|
|
static void _enforceValidTZFile(bool result, size_t line = __LINE__) @safe pure
|
|
{
|
|
if(!result)
|
|
throw new DateTimeException("Not a valid tzdata file.", __FILE__, line);
|
|
}
|
|
|
|
|
|
int calculateLeapSeconds(long stdTime) @safe const pure nothrow
|
|
{
|
|
if(_leapSeconds.empty)
|
|
return 0;
|
|
|
|
immutable unixTime = stdTimeToUnixTime(stdTime);
|
|
|
|
if(_leapSeconds.front.timeT >= unixTime)
|
|
return 0;
|
|
|
|
immutable found = countUntil!"b < a.timeT"(_leapSeconds, unixTime);
|
|
|
|
if(found == -1)
|
|
return _leapSeconds.back.total;
|
|
|
|
immutable leapSecond = found == 0 ? _leapSeconds[0] : _leapSeconds[found - 1];
|
|
|
|
return leapSecond.total;
|
|
}
|
|
|
|
|
|
this(immutable Transition[] transitions,
|
|
immutable LeapSecond[] leapSeconds,
|
|
string name,
|
|
string stdName,
|
|
string dstName,
|
|
bool hasDST) @safe immutable pure
|
|
{
|
|
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;
|
|
}
|
|
|
|
/// List of times when the utc offset changes.
|
|
immutable Transition[] _transitions;
|
|
|
|
/// List of leap second occurrences.
|
|
immutable LeapSecond[] _leapSeconds;
|
|
|
|
/// Whether DST is in effect for this time zone at any point in time.
|
|
immutable bool _hasDST;
|
|
}
|
|
|
|
|
|
|
|
version(StdDdoc)
|
|
{
|
|
/++
|
|
$(BLUE This class is Windows-Only.)
|
|
|
|
Represents a time zone from the Windows registry. Unfortunately, Windows
|
|
does not use the TZ Database. To use the TZ Database, use
|
|
$(LREF PosixTimeZone) (which reads its information from the TZ Database
|
|
files on disk) on Windows by providing the TZ Database files and telling
|
|
$(D PosixTimeZone.getTimeZone) where the directory holding them is.
|
|
|
|
The TZ Database files and Windows' time zone information frequently
|
|
do not match. Windows has many errors with regards to when DST switches
|
|
occur (especially for historical dates). Also, the TZ Database files
|
|
include far more time zones than Windows does. So, for accurate
|
|
time zone information, use the TZ Database files with
|
|
$(LREF PosixTimeZone) rather than $(LREF WindowsTimeZone). However, because
|
|
$(LREF WindowsTimeZone) uses Windows system calls to deal with the time,
|
|
it's far more likely to match the behavior of other Windows programs.
|
|
Be aware of the differences when selecting a method.
|
|
|
|
$(LREF WindowsTimeZone) does not exist on Posix systems.
|
|
|
|
To get a $(LREF WindowsTimeZone), either call
|
|
$(D WindowsTimeZone.getTimeZone) or call $(D TimeZone.getTimeZone)
|
|
(which will give a $(LREF PosixTimeZone) on Posix systems and a
|
|
$(LREF WindowsTimeZone) on Windows systems).
|
|
|
|
See_Also:
|
|
$(WEB www.iana.org/time-zones, Home of the TZ Database files)
|
|
+/
|
|
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 $(D hasDST) because the
|
|
time zone did at some point have DST.
|
|
+/
|
|
@property override bool hasDST() @safe const nothrow;
|
|
|
|
|
|
/++
|
|
Takes the number of hnsecs (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) @safe const nothrow;
|
|
|
|
|
|
/++
|
|
Takes the number of hnsecs (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) @safe const nothrow;
|
|
|
|
|
|
/++
|
|
Takes the number of hnsecs (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) @safe const nothrow;
|
|
|
|
|
|
/++
|
|
Returns a $(LREF2 .TimeZone, TimeZone) with the given name per the Windows time
|
|
zone names. The time zone information is fetched from the Windows
|
|
registry.
|
|
|
|
See_Also:
|
|
$(WEB en.wikipedia.org/wiki/Tz_database, Wikipedia entry on TZ
|
|
Database)<br>
|
|
$(WEB en.wikipedia.org/wiki/List_of_tz_database_time_zones, List
|
|
of Time Zones)
|
|
|
|
Params:
|
|
name = The TZ Database name of the desired time zone.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given time zone could not be
|
|
found.
|
|
|
|
Examples:
|
|
--------------------
|
|
auto tz = TimeZone.getTimeZone("America/Los_Angeles");
|
|
--------------------
|
|
+/
|
|
static immutable(WindowsTimeZone) getTimeZone(string name) @safe;
|
|
|
|
|
|
/++
|
|
Returns a list of the names of the time zones installed on the
|
|
system. The list returned by WindowsTimeZone contains the Windows
|
|
TZ names, not the TZ Database names. However,
|
|
$(D TimeZone.getinstalledTZNames) will return the TZ Database names
|
|
which are equivalent to the Windows TZ names.
|
|
+/
|
|
static string[] getInstalledTZNames() @safe;
|
|
|
|
private:
|
|
|
|
version(Windows) {}
|
|
else
|
|
alias void* TIME_ZONE_INFORMATION;
|
|
|
|
static bool _dstInEffect(const TIME_ZONE_INFORMATION* tzInfo, long stdTime) nothrow;
|
|
static long _utcToTZ(const TIME_ZONE_INFORMATION* tzInfo, long stdTime, bool hasDST) nothrow;
|
|
static long _tzToUTC(const TIME_ZONE_INFORMATION* tzInfo, long adjTime, bool hasDST) nothrow;
|
|
|
|
this() immutable pure
|
|
{
|
|
super("", "", "");
|
|
}
|
|
}
|
|
|
|
}
|
|
else version(Windows)
|
|
{
|
|
final class WindowsTimeZone : TimeZone
|
|
{
|
|
import std.format : format;
|
|
import std.conv : to;
|
|
import std.algorithm : sort;
|
|
import std.array : appender;
|
|
|
|
public:
|
|
|
|
@property override bool hasDST() @safe const nothrow
|
|
{
|
|
return _tzInfo.DaylightDate.wMonth != 0;
|
|
}
|
|
|
|
|
|
override bool dstInEffect(long stdTime) @safe const nothrow
|
|
{
|
|
return _dstInEffect(&_tzInfo, stdTime);
|
|
}
|
|
|
|
|
|
override long utcToTZ(long stdTime) @safe const nothrow
|
|
{
|
|
return _utcToTZ(&_tzInfo, stdTime, hasDST);
|
|
}
|
|
|
|
|
|
override long tzToUTC(long adjTime) @safe const nothrow
|
|
{
|
|
return _tzToUTC(&_tzInfo, adjTime, hasDST);
|
|
}
|
|
|
|
|
|
static immutable(WindowsTimeZone) getTimeZone(string name) @trusted
|
|
{
|
|
import std.utf : toUTF16;
|
|
|
|
scope baseKey = Registry.localMachine.getKey(`Software\Microsoft\Windows NT\CurrentVersion\Time Zones`);
|
|
|
|
foreach (tzKeyName; baseKey.keyNames)
|
|
{
|
|
if (tzKeyName != name)
|
|
continue;
|
|
|
|
scope tzKey = baseKey.getKey(tzKeyName);
|
|
|
|
scope stdVal = tzKey.getValue("Std");
|
|
auto stdName = stdVal.value_SZ;
|
|
|
|
scope dstVal = tzKey.getValue("Dlt");
|
|
auto dstName = dstVal.value_SZ;
|
|
|
|
scope tziVal = tzKey.getValue("TZI");
|
|
auto binVal = tziVal.value_BINARY;
|
|
assert(binVal.length == REG_TZI_FORMAT.sizeof);
|
|
auto tziFmt = cast(REG_TZI_FORMAT*)binVal.ptr;
|
|
|
|
TIME_ZONE_INFORMATION tzInfo;
|
|
|
|
auto wstdName = toUTF16(stdName);
|
|
auto wdstName = toUTF16(dstName);
|
|
auto wstdNameLen = wstdName.length > 32 ? 32 : wstdName.length;
|
|
auto wdstNameLen = wdstName.length > 32 ? 32 : wdstName.length;
|
|
|
|
tzInfo.Bias = tziFmt.Bias;
|
|
tzInfo.StandardName[0 .. wstdNameLen] = wstdName[0 .. wstdNameLen];
|
|
tzInfo.StandardName[wstdNameLen .. $] = '\0';
|
|
tzInfo.StandardDate = tziFmt.StandardDate;
|
|
tzInfo.StandardBias = tziFmt.StandardBias;
|
|
tzInfo.DaylightName[0 .. wdstNameLen] = wdstName[0 .. wdstNameLen];
|
|
tzInfo.DaylightName[wdstNameLen .. $] = '\0';
|
|
tzInfo.DaylightDate = tziFmt.DaylightDate;
|
|
tzInfo.DaylightBias = tziFmt.DaylightBias;
|
|
|
|
return new immutable WindowsTimeZone(name, tzInfo);
|
|
}
|
|
throw new DateTimeException(format("Failed to find time zone: %s", name));
|
|
}
|
|
|
|
static string[] getInstalledTZNames() @trusted
|
|
{
|
|
auto timezones = appender!(string[])();
|
|
|
|
scope baseKey = Registry.localMachine.getKey(`Software\Microsoft\Windows NT\CurrentVersion\Time Zones`);
|
|
|
|
foreach (tzKeyName; baseKey.keyNames)
|
|
{
|
|
timezones.put(tzKeyName);
|
|
}
|
|
sort(timezones.data);
|
|
|
|
return timezones.data;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
static void testWTZSuccess(string tzName)
|
|
{
|
|
scope(failure) writefln("TZName which threw: %s", tzName);
|
|
|
|
WindowsTimeZone.getTimeZone(tzName);
|
|
}
|
|
|
|
auto tzNames = getInstalledTZNames();
|
|
|
|
foreach(tzName; tzNames)
|
|
assertNotThrown!DateTimeException(testWTZSuccess(tzName));
|
|
}
|
|
|
|
|
|
private:
|
|
|
|
static bool _dstInEffect(const TIME_ZONE_INFORMATION* tzInfo, long stdTime) @trusted 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;
|
|
utcTime.wMilliseconds = 0;
|
|
|
|
immutable result = SystemTimeToTzSpecificLocalTime(cast(TIME_ZONE_INFORMATION*)tzInfo,
|
|
&utcTime,
|
|
&otherTime);
|
|
assert(result);
|
|
|
|
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, "DateTime's constructor threw.");
|
|
}
|
|
|
|
unittest
|
|
{
|
|
TIME_ZONE_INFORMATION tzInfo;
|
|
GetTimeZoneInformation(&tzInfo);
|
|
|
|
foreach(year; [1600, 1601, 30_827, 30_828])
|
|
WindowsTimeZone._dstInEffect(&tzInfo, SysTime(DateTime(year, 1, 1)).stdTime);
|
|
}
|
|
|
|
|
|
static long _utcToTZ(const TIME_ZONE_INFORMATION* tzInfo, long stdTime, bool hasDST) @safe 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) @trusted nothrow
|
|
{
|
|
if(hasDST)
|
|
{
|
|
try
|
|
{
|
|
bool dstInEffectForLocalDateTime(DateTime localDateTime)
|
|
{
|
|
//The limits of what SystemTimeToTzSpecificLocalTime will accept.
|
|
if(localDateTime.year < 1601)
|
|
{
|
|
if(localDateTime.month == Month.feb && localDateTime.day == 29)
|
|
localDateTime.day = 28;
|
|
|
|
localDateTime.year = 1601;
|
|
}
|
|
else if(localDateTime.year > 30_827)
|
|
{
|
|
if(localDateTime.month == Month.feb && localDateTime.day == 29)
|
|
localDateTime.day = 28;
|
|
|
|
localDateTime.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(localDateTime.month == Month.jan)
|
|
{
|
|
if(localDateTime.day == 1)
|
|
localDateTime.day = 2;
|
|
}
|
|
else if(localDateTime.month == Month.dec && localDateTime.day == 31)
|
|
localDateTime.day = 30;
|
|
|
|
SYSTEMTIME utcTime = void;
|
|
SYSTEMTIME localTime = void;
|
|
|
|
localTime.wYear = localDateTime.year;
|
|
localTime.wMonth = localDateTime.month;
|
|
localTime.wDay = localDateTime.day;
|
|
localTime.wHour = localDateTime.hour;
|
|
localTime.wMinute = localDateTime.minute;
|
|
localTime.wSecond = localDateTime.second;
|
|
localTime.wMilliseconds = 0;
|
|
|
|
immutable result = TzSpecificLocalTimeToSystemTime(cast(TIME_ZONE_INFORMATION*)tzInfo,
|
|
&localTime,
|
|
&utcTime);
|
|
assert(result);
|
|
|
|
immutable utcDateTime = DateTime(utcTime.wYear,
|
|
utcTime.wMonth,
|
|
utcTime.wDay,
|
|
utcTime.wHour,
|
|
utcTime.wMinute,
|
|
utcTime.wSecond);
|
|
|
|
immutable diff = localDateTime - utcDateTime;
|
|
immutable minutes = -tzInfo.Bias - diff.total!"minutes";
|
|
|
|
if(minutes == tzInfo.DaylightBias)
|
|
return true;
|
|
|
|
assert(minutes == tzInfo.StandardBias);
|
|
|
|
return false;
|
|
}
|
|
|
|
auto localDateTime = cast(DateTime)SysTime(adjTime, UTC());
|
|
auto localDateTimeBefore = localDateTime - dur!"hours"(1);
|
|
auto localDateTimeAfter = localDateTime + dur!"hours"(1);
|
|
|
|
auto dstInEffectNow = dstInEffectForLocalDateTime(localDateTime);
|
|
auto dstInEffectBefore = dstInEffectForLocalDateTime(localDateTimeBefore);
|
|
auto dstInEffectAfter = dstInEffectForLocalDateTime(localDateTimeAfter);
|
|
|
|
bool isDST;
|
|
|
|
if(dstInEffectBefore && dstInEffectNow && dstInEffectAfter)
|
|
isDST = true;
|
|
else if(!dstInEffectBefore && !dstInEffectNow && !dstInEffectAfter)
|
|
isDST = false;
|
|
else if(!dstInEffectBefore && dstInEffectAfter)
|
|
isDST = false;
|
|
else if(dstInEffectBefore && !dstInEffectAfter)
|
|
isDST = dstInEffectNow;
|
|
else
|
|
assert(0, "Bad Logic.");
|
|
|
|
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) @safe immutable pure
|
|
{
|
|
super(name, to!string(tzInfo.StandardName.ptr), to!string(tzInfo.DaylightName.ptr));
|
|
_tzInfo = tzInfo;
|
|
}
|
|
|
|
|
|
TIME_ZONE_INFORMATION _tzInfo;
|
|
}
|
|
}
|
|
|
|
|
|
version(StdDdoc)
|
|
{
|
|
/++
|
|
$(BLUE This function is Posix-Only.)
|
|
|
|
Sets 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) @safe nothrow;
|
|
|
|
|
|
/++
|
|
$(BLUE This function is Posix-Only.)
|
|
|
|
Clears the TZ environment variable.
|
|
+/
|
|
void clearTZEnvVar() @safe nothrow;
|
|
}
|
|
else version(Posix)
|
|
{
|
|
void setTZEnvVar(string tzDatabaseName) @trusted nothrow
|
|
{
|
|
import std.internal.cstring : tempCString;
|
|
import std.path : buildNormalizedPath;
|
|
|
|
try
|
|
{
|
|
immutable value = buildNormalizedPath(PosixTimeZone.defaultTZDatabaseDir, tzDatabaseName);
|
|
setenv("TZ", value.tempCString(), 1);
|
|
tzset();
|
|
}
|
|
catch(Exception e)
|
|
assert(0, "The impossible happened. setenv or tzset threw.");
|
|
}
|
|
|
|
|
|
void clearTZEnvVar() @trusted nothrow
|
|
{
|
|
try
|
|
{
|
|
unsetenv("TZ");
|
|
tzset();
|
|
}
|
|
catch(Exception e)
|
|
assert(0, "The impossible happened. unsetenv or tzset threw.");
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
Converts the given TZ Database name to the corresponding Windows time zone
|
|
name.
|
|
|
|
Note that in a few cases, a TZ Dabatase name corresponds to two different
|
|
Windows time zone names. So, while in most cases converting from one to the
|
|
other and back again will result in the same time zone name started
|
|
with, in a few case, it'll get a different name.
|
|
|
|
Also, there are far more TZ Database names than Windows time zones, so some
|
|
of the more exotic TZ Database names don't have corresponding Windows time
|
|
zone names.
|
|
|
|
Returns null if the given time zone name cannot be converted.
|
|
|
|
See_Also:
|
|
$(WEB unicode.org/repos/cldr-tmp/trunk/diff/supplemental/zone_tzid.html,
|
|
Windows <-> TZ Database Name Conversion Table)
|
|
|
|
Params:
|
|
tzName = The TZ Database name to convert.
|
|
+/
|
|
string tzDatabaseNameToWindowsTZName(string tzName) @safe pure nothrow @nogc
|
|
{
|
|
switch(tzName)
|
|
{
|
|
case "Africa/Abidjan": return "Greenwich Standard Time";
|
|
case "Africa/Accra": return "Greenwich Standard Time";
|
|
case "Africa/Addis_Ababa": return "E. Africa Standard Time";
|
|
case "Africa/Algiers": return "W. Central Africa Standard Time";
|
|
case "Africa/Asmera": return "E. Africa Standard Time";
|
|
case "Africa/Bamako": return "Greenwich Standard Time";
|
|
case "Africa/Bangui": return "W. Central Africa Standard Time";
|
|
case "Africa/Banjul": return "Greenwich Standard Time";
|
|
case "Africa/Bissau": return "Greenwich Standard Time";
|
|
case "Africa/Blantyre": return "South Africa Standard Time";
|
|
case "Africa/Brazzaville": return "W. Central Africa Standard Time";
|
|
case "Africa/Bujumbura": return "South Africa Standard Time";
|
|
case "Africa/Cairo": return "Egypt Standard Time";
|
|
case "Africa/Casablanca": return "Morocco Standard Time";
|
|
case "Africa/Ceuta": return "Romance Standard Time";
|
|
case "Africa/Conakry": return "Greenwich Standard Time";
|
|
case "Africa/Dakar": return "Greenwich Standard Time";
|
|
case "Africa/Dar_es_Salaam": return "E. Africa Standard Time";
|
|
case "Africa/Djibouti": return "E. Africa Standard Time";
|
|
case "Africa/Douala": return "W. Central Africa Standard Time";
|
|
case "Africa/El_Aaiun": return "Morocco Standard Time";
|
|
case "Africa/Freetown": return "Greenwich Standard Time";
|
|
case "Africa/Gaborone": return "South Africa Standard Time";
|
|
case "Africa/Harare": return "South Africa Standard Time";
|
|
case "Africa/Johannesburg": return "South Africa Standard Time";
|
|
case "Africa/Juba": return "E. Africa Standard Time";
|
|
case "Africa/Kampala": return "E. Africa Standard Time";
|
|
case "Africa/Khartoum": return "E. Africa Standard Time";
|
|
case "Africa/Kigali": return "South Africa Standard Time";
|
|
case "Africa/Kinshasa": return "W. Central Africa Standard Time";
|
|
case "Africa/Lagos": return "W. Central Africa Standard Time";
|
|
case "Africa/Libreville": return "W. Central Africa Standard Time";
|
|
case "Africa/Lome": return "Greenwich Standard Time";
|
|
case "Africa/Luanda": return "W. Central Africa Standard Time";
|
|
case "Africa/Lubumbashi": return "South Africa Standard Time";
|
|
case "Africa/Lusaka": return "South Africa Standard Time";
|
|
case "Africa/Malabo": return "W. Central Africa Standard Time";
|
|
case "Africa/Maputo": return "South Africa Standard Time";
|
|
case "Africa/Maseru": return "South Africa Standard Time";
|
|
case "Africa/Mbabane": return "South Africa Standard Time";
|
|
case "Africa/Mogadishu": return "E. Africa Standard Time";
|
|
case "Africa/Monrovia": return "Greenwich Standard Time";
|
|
case "Africa/Nairobi": return "E. Africa Standard Time";
|
|
case "Africa/Ndjamena": return "W. Central Africa Standard Time";
|
|
case "Africa/Niamey": return "W. Central Africa Standard Time";
|
|
case "Africa/Nouakchott": return "Greenwich Standard Time";
|
|
case "Africa/Ouagadougou": return "Greenwich Standard Time";
|
|
case "Africa/Porto-Novo": return "W. Central Africa Standard Time";
|
|
case "Africa/Sao_Tome": return "Greenwich Standard Time";
|
|
case "Africa/Tripoli": return "Libya Standard Time";
|
|
case "Africa/Tunis": return "W. Central Africa Standard Time";
|
|
case "Africa/Windhoek": return "Namibia Standard Time";
|
|
case "America/Anchorage": return "Alaskan Standard Time";
|
|
case "America/Anguilla": return "SA Western Standard Time";
|
|
case "America/Antigua": return "SA Western Standard Time";
|
|
case "America/Araguaina": return "SA Eastern Standard Time";
|
|
case "America/Argentina/La_Rioja": return "Argentina Standard Time";
|
|
case "America/Argentina/Rio_Gallegos": return "Argentina Standard Time";
|
|
case "America/Argentina/Salta": return "Argentina Standard Time";
|
|
case "America/Argentina/San_Juan": return "Argentina Standard Time";
|
|
case "America/Argentina/San_Luis": return "Argentina Standard Time";
|
|
case "America/Argentina/Tucuman": return "Argentina Standard Time";
|
|
case "America/Argentina/Ushuaia": return "Argentina Standard Time";
|
|
case "America/Aruba": return "SA Western Standard Time";
|
|
case "America/Asuncion": return "Paraguay Standard Time";
|
|
case "America/Bahia": return "Bahia Standard Time";
|
|
case "America/Bahia_Banderas": return "Central Standard Time (Mexico)";
|
|
case "America/Barbados": return "SA Western Standard Time";
|
|
case "America/Belem": return "SA Eastern Standard Time";
|
|
case "America/Belize": return "Central America Standard Time";
|
|
case "America/Blanc-Sablon": return "SA Western Standard Time";
|
|
case "America/Boa_Vista": return "SA Western Standard Time";
|
|
case "America/Bogota": return "SA Pacific Standard Time";
|
|
case "America/Boise": return "Mountain Standard Time";
|
|
case "America/Buenos_Aires": return "Argentina Standard Time";
|
|
case "America/Cambridge_Bay": return "Mountain Standard Time";
|
|
case "America/Campo_Grande": return "Central Brazilian Standard Time";
|
|
case "America/Cancun": return "Central Standard Time (Mexico)";
|
|
case "America/Caracas": return "Venezuela Standard Time";
|
|
case "America/Catamarca": return "Argentina Standard Time";
|
|
case "America/Cayenne": return "SA Eastern Standard Time";
|
|
case "America/Cayman": return "SA Pacific Standard Time";
|
|
case "America/Chicago": return "Central Standard Time";
|
|
case "America/Chihuahua": return "Mountain Standard Time (Mexico)";
|
|
case "America/Coral_Harbour": return "SA Pacific Standard Time";
|
|
case "America/Cordoba": return "Argentina Standard Time";
|
|
case "America/Costa_Rica": return "Central America Standard Time";
|
|
case "America/Creston": return "US Mountain Standard Time";
|
|
case "America/Cuiaba": return "Central Brazilian Standard Time";
|
|
case "America/Curacao": return "SA Western Standard Time";
|
|
case "America/Danmarkshavn": return "UTC";
|
|
case "America/Dawson": return "Pacific Standard Time";
|
|
case "America/Dawson_Creek": return "US Mountain Standard Time";
|
|
case "America/Denver": return "Mountain Standard Time";
|
|
case "America/Detroit": return "Eastern Standard Time";
|
|
case "America/Dominica": return "SA Western Standard Time";
|
|
case "America/Edmonton": return "Mountain Standard Time";
|
|
case "America/Eirunepe": return "SA Pacific Standard Time";
|
|
case "America/El_Salvador": return "Central America Standard Time";
|
|
case "America/Fortaleza": return "SA Eastern Standard Time";
|
|
case "America/Glace_Bay": return "Atlantic Standard Time";
|
|
case "America/Godthab": return "Greenland Standard Time";
|
|
case "America/Goose_Bay": return "Atlantic Standard Time";
|
|
case "America/Grand_Turk": return "SA Western Standard Time";
|
|
case "America/Grenada": return "SA Western Standard Time";
|
|
case "America/Guadeloupe": return "SA Western Standard Time";
|
|
case "America/Guatemala": return "Central America Standard Time";
|
|
case "America/Guayaquil": return "SA Pacific Standard Time";
|
|
case "America/Guyana": return "SA Western Standard Time";
|
|
case "America/Halifax": return "Atlantic Standard Time";
|
|
case "America/Havana": return "Eastern Standard Time";
|
|
case "America/Hermosillo": return "US Mountain Standard Time";
|
|
case "America/Indiana/Knox": return "Central Standard Time";
|
|
case "America/Indiana/Marengo": return "US Eastern Standard Time";
|
|
case "America/Indiana/Petersburg": return "Eastern Standard Time";
|
|
case "America/Indiana/Tell_City": return "Central Standard Time";
|
|
case "America/Indiana/Vevay": return "US Eastern Standard Time";
|
|
case "America/Indiana/Vincennes": return "Eastern Standard Time";
|
|
case "America/Indiana/Winamac": return "Eastern Standard Time";
|
|
case "America/Indianapolis": return "US Eastern Standard Time";
|
|
case "America/Inuvik": return "Mountain Standard Time";
|
|
case "America/Iqaluit": return "Eastern Standard Time";
|
|
case "America/Jamaica": return "SA Pacific Standard Time";
|
|
case "America/Jujuy": return "Argentina Standard Time";
|
|
case "America/Juneau": return "Alaskan Standard Time";
|
|
case "America/Kentucky/Monticello": return "Eastern Standard Time";
|
|
case "America/Kralendijk": return "SA Western Standard Time";
|
|
case "America/La_Paz": return "SA Western Standard Time";
|
|
case "America/Lima": return "SA Pacific Standard Time";
|
|
case "America/Los_Angeles": return "Pacific Standard Time";
|
|
case "America/Louisville": return "Eastern Standard Time";
|
|
case "America/Lower_Princes": return "SA Western Standard Time";
|
|
case "America/Maceio": return "SA Eastern Standard Time";
|
|
case "America/Managua": return "Central America Standard Time";
|
|
case "America/Manaus": return "SA Western Standard Time";
|
|
case "America/Marigot": return "SA Western Standard Time";
|
|
case "America/Martinique": return "SA Western Standard Time";
|
|
case "America/Matamoros": return "Central Standard Time";
|
|
case "America/Mazatlan": return "Mountain Standard Time (Mexico)";
|
|
case "America/Mendoza": return "Argentina Standard Time";
|
|
case "America/Menominee": return "Central Standard Time";
|
|
case "America/Merida": return "Central Standard Time (Mexico)";
|
|
case "America/Mexico_City": return "Central Standard Time (Mexico)";
|
|
case "America/Moncton": return "Atlantic Standard Time";
|
|
case "America/Monterrey": return "Central Standard Time (Mexico)";
|
|
case "America/Montevideo": return "Montevideo Standard Time";
|
|
case "America/Montreal": return "Eastern Standard Time";
|
|
case "America/Montserrat": return "SA Western Standard Time";
|
|
case "America/Nassau": return "Eastern Standard Time";
|
|
case "America/New_York": return "Eastern Standard Time";
|
|
case "America/Nipigon": return "Eastern Standard Time";
|
|
case "America/Nome": return "Alaskan Standard Time";
|
|
case "America/Noronha": return "UTC-02";
|
|
case "America/North_Dakota/Beulah": return "Central Standard Time";
|
|
case "America/North_Dakota/Center": return "Central Standard Time";
|
|
case "America/North_Dakota/New_Salem": return "Central Standard Time";
|
|
case "America/Ojinaga": return "Mountain Standard Time";
|
|
case "America/Panama": return "SA Pacific Standard Time";
|
|
case "America/Pangnirtung": return "Eastern Standard Time";
|
|
case "America/Paramaribo": return "SA Eastern Standard Time";
|
|
case "America/Phoenix": return "US Mountain Standard Time";
|
|
case "America/Port-au-Prince": return "Eastern Standard Time";
|
|
case "America/Port_of_Spain": return "SA Western Standard Time";
|
|
case "America/Porto_Velho": return "SA Western Standard Time";
|
|
case "America/Puerto_Rico": return "SA Western Standard Time";
|
|
case "America/Rainy_River": return "Central Standard Time";
|
|
case "America/Rankin_Inlet": return "Central Standard Time";
|
|
case "America/Recife": return "SA Eastern Standard Time";
|
|
case "America/Regina": return "Canada Central Standard Time";
|
|
case "America/Resolute": return "Central Standard Time";
|
|
case "America/Rio_Branco": return "SA Pacific Standard Time";
|
|
case "America/Santa_Isabel": return "Pacific Standard Time (Mexico)";
|
|
case "America/Santarem": return "SA Eastern Standard Time";
|
|
case "America/Santiago": return "Pacific SA Standard Time";
|
|
case "America/Santo_Domingo": return "SA Western Standard Time";
|
|
case "America/Sao_Paulo": return "E. South America Standard Time";
|
|
case "America/Scoresbysund": return "Azores Standard Time";
|
|
case "America/Sitka": return "Alaskan Standard Time";
|
|
case "America/St_Barthelemy": return "SA Western Standard Time";
|
|
case "America/St_Johns": return "Newfoundland Standard Time";
|
|
case "America/St_Kitts": return "SA Western Standard Time";
|
|
case "America/St_Lucia": return "SA Western Standard Time";
|
|
case "America/St_Thomas": return "SA Western Standard Time";
|
|
case "America/St_Vincent": return "SA Western Standard Time";
|
|
case "America/Swift_Current": return "Canada Central Standard Time";
|
|
case "America/Tegucigalpa": return "Central America Standard Time";
|
|
case "America/Thule": return "Atlantic Standard Time";
|
|
case "America/Thunder_Bay": return "Eastern Standard Time";
|
|
case "America/Tijuana": return "Pacific Standard Time";
|
|
case "America/Toronto": return "Eastern Standard Time";
|
|
case "America/Tortola": return "SA Western Standard Time";
|
|
case "America/Vancouver": return "Pacific Standard Time";
|
|
case "America/Whitehorse": return "Pacific Standard Time";
|
|
case "America/Winnipeg": return "Central Standard Time";
|
|
case "America/Yakutat": return "Alaskan Standard Time";
|
|
case "America/Yellowknife": return "Mountain Standard Time";
|
|
case "Antarctica/Casey": return "W. Australia Standard Time";
|
|
case "Antarctica/Davis": return "SE Asia Standard Time";
|
|
case "Antarctica/DumontDUrville": return "West Pacific Standard Time";
|
|
case "Antarctica/Macquarie": return "Central Pacific Standard Time";
|
|
case "Antarctica/Mawson": return "West Asia Standard Time";
|
|
case "Antarctica/McMurdo": return "New Zealand Standard Time";
|
|
case "Antarctica/Palmer": return "Pacific SA Standard Time";
|
|
case "Antarctica/Rothera": return "SA Eastern Standard Time";
|
|
case "Antarctica/Syowa": return "E. Africa Standard Time";
|
|
case "Antarctica/Vostok": return "Central Asia Standard Time";
|
|
case "Arctic/Longyearbyen": return "W. Europe Standard Time";
|
|
case "Asia/Aden": return "Arab Standard Time";
|
|
case "Asia/Almaty": return "Central Asia Standard Time";
|
|
case "Asia/Amman": return "Jordan Standard Time";
|
|
case "Asia/Anadyr": return "Russia Time Zone 11";
|
|
case "Asia/Aqtau": return "West Asia Standard Time";
|
|
case "Asia/Aqtobe": return "West Asia Standard Time";
|
|
case "Asia/Ashgabat": return "West Asia Standard Time";
|
|
case "Asia/Baghdad": return "Arabic Standard Time";
|
|
case "Asia/Bahrain": return "Arab Standard Time";
|
|
case "Asia/Baku": return "Azerbaijan Standard Time";
|
|
case "Asia/Bangkok": return "SE Asia Standard Time";
|
|
case "Asia/Beirut": return "Middle East Standard Time";
|
|
case "Asia/Bishkek": return "Central Asia Standard Time";
|
|
case "Asia/Brunei": return "Singapore Standard Time";
|
|
case "Asia/Calcutta": return "India Standard Time";
|
|
case "Asia/Chita": return "North Asia East Standard Time";
|
|
case "Asia/Choibalsan": return "Ulaanbaatar Standard Time";
|
|
case "Asia/Colombo": return "Sri Lanka Standard Time";
|
|
case "Asia/Damascus": return "Syria Standard Time";
|
|
case "Asia/Dhaka": return "Bangladesh Standard Time";
|
|
case "Asia/Dili": return "Tokyo Standard Time";
|
|
case "Asia/Dubai": return "Arabian Standard Time";
|
|
case "Asia/Dushanbe": return "West Asia Standard Time";
|
|
case "Asia/Hong_Kong": return "China Standard Time";
|
|
case "Asia/Hovd": return "SE Asia Standard Time";
|
|
case "Asia/Irkutsk": return "North Asia East Standard Time";
|
|
case "Asia/Jakarta": return "SE Asia Standard Time";
|
|
case "Asia/Jayapura": return "Tokyo Standard Time";
|
|
case "Asia/Jerusalem": return "Israel Standard Time";
|
|
case "Asia/Kabul": return "Afghanistan Standard Time";
|
|
case "Asia/Kamchatka": return "Russia Time Zone 11";
|
|
case "Asia/Karachi": return "Pakistan Standard Time";
|
|
case "Asia/Katmandu": return "Nepal Standard Time";
|
|
case "Asia/Khandyga": return "Yakutsk Standard Time";
|
|
case "Asia/Krasnoyarsk": return "North Asia Standard Time";
|
|
case "Asia/Kuala_Lumpur": return "Singapore Standard Time";
|
|
case "Asia/Kuching": return "Singapore Standard Time";
|
|
case "Asia/Kuwait": return "Arab Standard Time";
|
|
case "Asia/Macau": return "China Standard Time";
|
|
case "Asia/Magadan": return "Magadan Standard Time";
|
|
case "Asia/Makassar": return "Singapore Standard Time";
|
|
case "Asia/Manila": return "Singapore Standard Time";
|
|
case "Asia/Muscat": return "Arabian Standard Time";
|
|
case "Asia/Nicosia": return "GTB Standard Time";
|
|
case "Asia/Novokuznetsk": return "North Asia Standard Time";
|
|
case "Asia/Novosibirsk": return "N. Central Asia Standard Time";
|
|
case "Asia/Omsk": return "N. Central Asia Standard Time";
|
|
case "Asia/Oral": return "West Asia Standard Time";
|
|
case "Asia/Phnom_Penh": return "SE Asia Standard Time";
|
|
case "Asia/Pontianak": return "SE Asia Standard Time";
|
|
case "Asia/Pyongyang": return "Korea Standard Time";
|
|
case "Asia/Qatar": return "Arab Standard Time";
|
|
case "Asia/Qyzylorda": return "Central Asia Standard Time";
|
|
case "Asia/Rangoon": return "Myanmar Standard Time";
|
|
case "Asia/Riyadh": return "Arab Standard Time";
|
|
case "Asia/Saigon": return "SE Asia Standard Time";
|
|
case "Asia/Sakhalin": return "Vladivostok Standard Time";
|
|
case "Asia/Samarkand": return "West Asia Standard Time";
|
|
case "Asia/Seoul": return "Korea Standard Time";
|
|
case "Asia/Shanghai": return "China Standard Time";
|
|
case "Asia/Singapore": return "Singapore Standard Time";
|
|
case "Asia/Srednekolymsk": return "Russia Time Zone 10";
|
|
case "Asia/Taipei": return "Taipei Standard Time";
|
|
case "Asia/Tashkent": return "West Asia Standard Time";
|
|
case "Asia/Tbilisi": return "Georgian Standard Time";
|
|
case "Asia/Tehran": return "Iran Standard Time";
|
|
case "Asia/Thimphu": return "Bangladesh Standard Time";
|
|
case "Asia/Tokyo": return "Tokyo Standard Time";
|
|
case "Asia/Ulaanbaatar": return "Ulaanbaatar Standard Time";
|
|
case "Asia/Urumqi": return "Central Asia Standard Time";
|
|
case "Asia/Ust-Nera": return "Vladivostok Standard Time";
|
|
case "Asia/Vientiane": return "SE Asia Standard Time";
|
|
case "Asia/Vladivostok": return "Vladivostok Standard Time";
|
|
case "Asia/Yakutsk": return "Yakutsk Standard Time";
|
|
case "Asia/Yekaterinburg": return "Ekaterinburg Standard Time";
|
|
case "Asia/Yerevan": return "Caucasus Standard Time";
|
|
case "Atlantic/Azores": return "Azores Standard Time";
|
|
case "Atlantic/Bermuda": return "Atlantic Standard Time";
|
|
case "Atlantic/Canary": return "GMT Standard Time";
|
|
case "Atlantic/Cape_Verde": return "Cape Verde Standard Time";
|
|
case "Atlantic/Faeroe": return "GMT Standard Time";
|
|
case "Atlantic/Madeira": return "GMT Standard Time";
|
|
case "Atlantic/Reykjavik": return "Greenwich Standard Time";
|
|
case "Atlantic/South_Georgia": return "UTC-02";
|
|
case "Atlantic/St_Helena": return "Greenwich Standard Time";
|
|
case "Atlantic/Stanley": return "SA Eastern Standard Time";
|
|
case "Australia/Adelaide": return "Cen. Australia Standard Time";
|
|
case "Australia/Brisbane": return "E. Australia Standard Time";
|
|
case "Australia/Broken_Hill": return "Cen. Australia Standard Time";
|
|
case "Australia/Currie": return "Tasmania Standard Time";
|
|
case "Australia/Darwin": return "AUS Central Standard Time";
|
|
case "Australia/Hobart": return "Tasmania Standard Time";
|
|
case "Australia/Lindeman": return "E. Australia Standard Time";
|
|
case "Australia/Melbourne": return "AUS Eastern Standard Time";
|
|
case "Australia/Perth": return "W. Australia Standard Time";
|
|
case "Australia/Sydney": return "AUS Eastern Standard Time";
|
|
case "CST6CDT": return "Central Standard Time";
|
|
case "EST5EDT": return "Eastern Standard Time";
|
|
case "Etc/GMT": return "UTC";
|
|
case "Etc/GMT+1": return "Cape Verde Standard Time";
|
|
case "Etc/GMT+10": return "Hawaiian Standard Time";
|
|
case "Etc/GMT+11": return "UTC-11";
|
|
case "Etc/GMT+12": return "Dateline Standard Time";
|
|
case "Etc/GMT+2": return "UTC-02";
|
|
case "Etc/GMT+3": return "SA Eastern Standard Time";
|
|
case "Etc/GMT+4": return "SA Western Standard Time";
|
|
case "Etc/GMT+5": return "SA Pacific Standard Time";
|
|
case "Etc/GMT+6": return "Central America Standard Time";
|
|
case "Etc/GMT+7": return "US Mountain Standard Time";
|
|
case "Etc/GMT-1": return "W. Central Africa Standard Time";
|
|
case "Etc/GMT-10": return "West Pacific Standard Time";
|
|
case "Etc/GMT-11": return "Central Pacific Standard Time";
|
|
case "Etc/GMT-12": return "UTC+12";
|
|
case "Etc/GMT-13": return "Tonga Standard Time";
|
|
case "Etc/GMT-14": return "Line Islands Standard Time";
|
|
case "Etc/GMT-2": return "South Africa Standard Time";
|
|
case "Etc/GMT-3": return "E. Africa Standard Time";
|
|
case "Etc/GMT-4": return "Arabian Standard Time";
|
|
case "Etc/GMT-5": return "West Asia Standard Time";
|
|
case "Etc/GMT-6": return "Central Asia Standard Time";
|
|
case "Etc/GMT-7": return "SE Asia Standard Time";
|
|
case "Etc/GMT-8": return "Singapore Standard Time";
|
|
case "Etc/GMT-9": return "Tokyo Standard Time";
|
|
case "Europe/Amsterdam": return "W. Europe Standard Time";
|
|
case "Europe/Andorra": return "W. Europe Standard Time";
|
|
case "Europe/Athens": return "GTB Standard Time";
|
|
case "Europe/Belgrade": return "Central Europe Standard Time";
|
|
case "Europe/Berlin": return "W. Europe Standard Time";
|
|
case "Europe/Bratislava": return "Central Europe Standard Time";
|
|
case "Europe/Brussels": return "Romance Standard Time";
|
|
case "Europe/Bucharest": return "GTB Standard Time";
|
|
case "Europe/Budapest": return "Central Europe Standard Time";
|
|
case "Europe/Busingen": return "W. Europe Standard Time";
|
|
case "Europe/Chisinau": return "GTB Standard Time";
|
|
case "Europe/Copenhagen": return "Romance Standard Time";
|
|
case "Europe/Dublin": return "GMT Standard Time";
|
|
case "Europe/Gibraltar": return "W. Europe Standard Time";
|
|
case "Europe/Guernsey": return "GMT Standard Time";
|
|
case "Europe/Helsinki": return "FLE Standard Time";
|
|
case "Europe/Isle_of_Man": return "GMT Standard Time";
|
|
case "Europe/Istanbul": return "Turkey Standard Time";
|
|
case "Europe/Jersey": return "GMT Standard Time";
|
|
case "Europe/Kaliningrad": return "Kaliningrad Standard Time";
|
|
case "Europe/Kiev": return "FLE Standard Time";
|
|
case "Europe/Lisbon": return "GMT Standard Time";
|
|
case "Europe/Ljubljana": return "Central Europe Standard Time";
|
|
case "Europe/London": return "GMT Standard Time";
|
|
case "Europe/Luxembourg": return "W. Europe Standard Time";
|
|
case "Europe/Madrid": return "Romance Standard Time";
|
|
case "Europe/Malta": return "W. Europe Standard Time";
|
|
case "Europe/Mariehamn": return "FLE Standard Time";
|
|
case "Europe/Minsk": return "Belarus Standard Time";
|
|
case "Europe/Monaco": return "W. Europe Standard Time";
|
|
case "Europe/Moscow": return "Russian Standard Time";
|
|
case "Europe/Oslo": return "W. Europe Standard Time";
|
|
case "Europe/Paris": return "Romance Standard Time";
|
|
case "Europe/Podgorica": return "Central Europe Standard Time";
|
|
case "Europe/Prague": return "Central Europe Standard Time";
|
|
case "Europe/Riga": return "FLE Standard Time";
|
|
case "Europe/Rome": return "W. Europe Standard Time";
|
|
case "Europe/Samara": return "Russia Time Zone 3";
|
|
case "Europe/San_Marino": return "W. Europe Standard Time";
|
|
case "Europe/Sarajevo": return "Central European Standard Time";
|
|
case "Europe/Simferopol": return "Russian Standard Time";
|
|
case "Europe/Skopje": return "Central European Standard Time";
|
|
case "Europe/Sofia": return "FLE Standard Time";
|
|
case "Europe/Stockholm": return "W. Europe Standard Time";
|
|
case "Europe/Tallinn": return "FLE Standard Time";
|
|
case "Europe/Tirane": return "Central Europe Standard Time";
|
|
case "Europe/Uzhgorod": return "FLE Standard Time";
|
|
case "Europe/Vaduz": return "W. Europe Standard Time";
|
|
case "Europe/Vatican": return "W. Europe Standard Time";
|
|
case "Europe/Vienna": return "W. Europe Standard Time";
|
|
case "Europe/Vilnius": return "FLE Standard Time";
|
|
case "Europe/Volgograd": return "Russian Standard Time";
|
|
case "Europe/Warsaw": return "Central European Standard Time";
|
|
case "Europe/Zagreb": return "Central European Standard Time";
|
|
case "Europe/Zaporozhye": return "FLE Standard Time";
|
|
case "Europe/Zurich": return "W. Europe Standard Time";
|
|
case "Indian/Antananarivo": return "E. Africa Standard Time";
|
|
case "Indian/Chagos": return "Central Asia Standard Time";
|
|
case "Indian/Christmas": return "SE Asia Standard Time";
|
|
case "Indian/Cocos": return "Myanmar Standard Time";
|
|
case "Indian/Comoro": return "E. Africa Standard Time";
|
|
case "Indian/Kerguelen": return "West Asia Standard Time";
|
|
case "Indian/Mahe": return "Mauritius Standard Time";
|
|
case "Indian/Maldives": return "West Asia Standard Time";
|
|
case "Indian/Mauritius": return "Mauritius Standard Time";
|
|
case "Indian/Mayotte": return "E. Africa Standard Time";
|
|
case "Indian/Reunion": return "Mauritius Standard Time";
|
|
case "MST7MDT": return "Mountain Standard Time";
|
|
case "PST8PDT": return "Pacific Standard Time";
|
|
case "Pacific/Apia": return "Samoa Standard Time";
|
|
case "Pacific/Auckland": return "New Zealand Standard Time";
|
|
case "Pacific/Efate": return "Central Pacific Standard Time";
|
|
case "Pacific/Enderbury": return "Tonga Standard Time";
|
|
case "Pacific/Fakaofo": return "Tonga Standard Time";
|
|
case "Pacific/Fiji": return "Fiji Standard Time";
|
|
case "Pacific/Funafuti": return "UTC+12";
|
|
case "Pacific/Galapagos": return "Central America Standard Time";
|
|
case "Pacific/Guadalcanal": return "Central Pacific Standard Time";
|
|
case "Pacific/Guam": return "West Pacific Standard Time";
|
|
case "Pacific/Honolulu": return "Hawaiian Standard Time";
|
|
case "Pacific/Johnston": return "Hawaiian Standard Time";
|
|
case "Pacific/Kiritimati": return "Line Islands Standard Time";
|
|
case "Pacific/Kosrae": return "Central Pacific Standard Time";
|
|
case "Pacific/Kwajalein": return "UTC+12";
|
|
case "Pacific/Majuro": return "UTC+12";
|
|
case "Pacific/Midway": return "UTC-11";
|
|
case "Pacific/Nauru": return "UTC+12";
|
|
case "Pacific/Niue": return "UTC-11";
|
|
case "Pacific/Noumea": return "Central Pacific Standard Time";
|
|
case "Pacific/Pago_Pago": return "UTC-11";
|
|
case "Pacific/Palau": return "Tokyo Standard Time";
|
|
case "Pacific/Ponape": return "Central Pacific Standard Time";
|
|
case "Pacific/Port_Moresby": return "West Pacific Standard Time";
|
|
case "Pacific/Rarotonga": return "Hawaiian Standard Time";
|
|
case "Pacific/Saipan": return "West Pacific Standard Time";
|
|
case "Pacific/Tahiti": return "Hawaiian Standard Time";
|
|
case "Pacific/Tarawa": return "UTC+12";
|
|
case "Pacific/Tongatapu": return "Tonga Standard Time";
|
|
case "Pacific/Truk": return "West Pacific Standard Time";
|
|
case "Pacific/Wake": return "UTC+12";
|
|
case "Pacific/Wallis": return "UTC+12";
|
|
default: return null;
|
|
}
|
|
}
|
|
|
|
version(Windows) unittest
|
|
{
|
|
import std.format : format;
|
|
foreach(tzName; TimeZone.getInstalledTZNames())
|
|
assert(tzDatabaseNameToWindowsTZName(tzName) !is null, format("TZName which failed: %s", tzName));
|
|
}
|
|
|
|
|
|
/++
|
|
Converts the given Windows time zone name to a corresponding TZ Database
|
|
name.
|
|
|
|
Returns null if the given time zone name cannot be converted.
|
|
|
|
See_Also:
|
|
$(WEB unicode.org/repos/cldr-tmp/trunk/diff/supplemental/zone_tzid.html,
|
|
Windows <-> TZ Database Name Conversion Table)
|
|
|
|
Params:
|
|
tzName = The TZ Database name to convert.
|
|
+/
|
|
string windowsTZNameToTZDatabaseName(string tzName) @safe pure nothrow @nogc
|
|
{
|
|
switch(tzName)
|
|
{
|
|
case "AUS Central Standard Time": return "Australia/Darwin";
|
|
case "AUS Eastern Standard Time": return "Australia/Sydney";
|
|
case "Afghanistan Standard Time": return "Asia/Kabul";
|
|
case "Alaskan Standard Time": return "America/Anchorage";
|
|
case "Arab Standard Time": return "Asia/Riyadh";
|
|
case "Arabian Standard Time": return "Asia/Dubai";
|
|
case "Arabic Standard Time": return "Asia/Baghdad";
|
|
case "Argentina Standard Time": return "America/Buenos_Aires";
|
|
case "Atlantic Standard Time": return "America/Halifax";
|
|
case "Azerbaijan Standard Time": return "Asia/Baku";
|
|
case "Azores Standard Time": return "Atlantic/Azores";
|
|
case "Bahia Standard Time": return "America/Bahia";
|
|
case "Bangladesh Standard Time": return "Asia/Dhaka";
|
|
case "Belarus Standard Time": return "Europe/Minsk";
|
|
case "Canada Central Standard Time": return "America/Regina";
|
|
case "Cape Verde Standard Time": return "Atlantic/Cape_Verde";
|
|
case "Caucasus Standard Time": return "Asia/Yerevan";
|
|
case "Cen. Australia Standard Time": return "Australia/Adelaide";
|
|
case "Central America Standard Time": return "America/Guatemala";
|
|
case "Central Asia Standard Time": return "Asia/Almaty";
|
|
case "Central Brazilian Standard Time": return "America/Cuiaba";
|
|
case "Central Europe Standard Time": return "Europe/Budapest";
|
|
case "Central European Standard Time": return "Europe/Warsaw";
|
|
case "Central Pacific Standard Time": return "Pacific/Guadalcanal";
|
|
case "Central Standard Time": return "America/Chicago";
|
|
case "Central Standard Time (Mexico)": return "America/Mexico_City";
|
|
case "China Standard Time": return "Asia/Shanghai";
|
|
case "Dateline Standard Time": return "Etc/GMT+12";
|
|
case "E. Africa Standard Time": return "Africa/Nairobi";
|
|
case "E. Australia Standard Time": return "Australia/Brisbane";
|
|
// This doesn't appear to be in the current stuff from MS, but the autotester
|
|
// is failing without it (probably because its time zone data hasn't been
|
|
// updated recently enough).
|
|
case "E. Europe Standard Time": return "Europe/Minsk";
|
|
case "E. South America Standard Time": return "America/Sao_Paulo";
|
|
case "Eastern Standard Time": return "America/New_York";
|
|
case "Egypt Standard Time": return "Africa/Cairo";
|
|
case "Ekaterinburg Standard Time": return "Asia/Yekaterinburg";
|
|
case "FLE Standard Time": return "Europe/Kiev";
|
|
case "Fiji Standard Time": return "Pacific/Fiji";
|
|
case "GMT Standard Time": return "Europe/London";
|
|
case "GTB Standard Time": return "Europe/Athens";
|
|
case "Georgian Standard Time": return "Asia/Tbilisi";
|
|
case "Greenland Standard Time": return "America/Godthab";
|
|
case "Greenwich Standard Time": return "Atlantic/Reykjavik";
|
|
case "Hawaiian Standard Time": return "Pacific/Honolulu";
|
|
case "India Standard Time": return "Asia/Calcutta";
|
|
case "Iran Standard Time": return "Asia/Tehran";
|
|
case "Israel Standard Time": return "Asia/Jerusalem";
|
|
case "Jordan Standard Time": return "Asia/Amman";
|
|
case "Kaliningrad Standard Time": return "Europe/Kaliningrad";
|
|
// Same as with E. Europe Standard Time.
|
|
case "Kamchatka Standard Time": return "Asia/Kamchatka";
|
|
case "Korea Standard Time": return "Asia/Seoul";
|
|
case "Libya Standard Time": return "Africa/Tripoli";
|
|
case "Line Islands Standard Time": return "Pacific/Kiritimati";
|
|
case "Magadan Standard Time": return "Asia/Magadan";
|
|
case "Mauritius Standard Time": return "Indian/Mauritius";
|
|
// Same as with E. Europe Standard Time.
|
|
case "Mexico Standard Time": return "America/Mexico_City";
|
|
// Same as with E. Europe Standard Time.
|
|
case "Mexico Standard Time 2": return "America/Chihuahua";
|
|
// Same as with E. Europe Standard Time.
|
|
case "Mid-Atlantic Standard Time": return "Etc/GMT+2";
|
|
case "Middle East Standard Time": return "Asia/Beirut";
|
|
case "Montevideo Standard Time": return "America/Montevideo";
|
|
case "Morocco Standard Time": return "Africa/Casablanca";
|
|
case "Mountain Standard Time": return "America/Denver";
|
|
case "Mountain Standard Time (Mexico)": return "America/Chihuahua";
|
|
case "Myanmar Standard Time": return "Asia/Rangoon";
|
|
case "N. Central Asia Standard Time": return "Asia/Novosibirsk";
|
|
case "Namibia Standard Time": return "Africa/Windhoek";
|
|
case "Nepal Standard Time": return "Asia/Katmandu";
|
|
case "New Zealand Standard Time": return "Pacific/Auckland";
|
|
case "Newfoundland Standard Time": return "America/St_Johns";
|
|
case "North Asia East Standard Time": return "Asia/Irkutsk";
|
|
case "North Asia Standard Time": return "Asia/Krasnoyarsk";
|
|
case "Pacific SA Standard Time": return "America/Santiago";
|
|
case "Pacific Standard Time": return "America/Los_Angeles";
|
|
case "Pacific Standard Time (Mexico)": return "America/Santa_Isabel";
|
|
case "Pakistan Standard Time": return "Asia/Karachi";
|
|
case "Paraguay Standard Time": return "America/Asuncion";
|
|
case "Romance Standard Time": return "Europe/Paris";
|
|
case "Russia Time Zone 10": return "Asia/Srednekolymsk";
|
|
case "Russia Time Zone 11": return "Asia/Anadyr";
|
|
case "Russia Time Zone 3": return "Europe/Samara";
|
|
case "Russian Standard Time": return "Europe/Moscow";
|
|
case "SA Eastern Standard Time": return "America/Cayenne";
|
|
case "SA Pacific Standard Time": return "America/Bogota";
|
|
case "SA Western Standard Time": return "America/La_Paz";
|
|
case "SE Asia Standard Time": return "Asia/Bangkok";
|
|
case "Samoa Standard Time": return "Pacific/Apia";
|
|
case "Singapore Standard Time": return "Asia/Singapore";
|
|
case "South Africa Standard Time": return "Africa/Johannesburg";
|
|
case "Sri Lanka Standard Time": return "Asia/Colombo";
|
|
case "Syria Standard Time": return "Asia/Damascus";
|
|
case "Taipei Standard Time": return "Asia/Taipei";
|
|
case "Tasmania Standard Time": return "Australia/Hobart";
|
|
case "Tokyo Standard Time": return "Asia/Tokyo";
|
|
case "Tonga Standard Time": return "Pacific/Tongatapu";
|
|
case "Turkey Standard Time": return "Europe/Istanbul";
|
|
case "US Eastern Standard Time": return "America/Indianapolis";
|
|
case "US Mountain Standard Time": return "America/Phoenix";
|
|
case "UTC": return "Etc/GMT";
|
|
case "UTC+12": return "Etc/GMT-12";
|
|
case "UTC-02": return "Etc/GMT+2";
|
|
case "UTC-11": return "Etc/GMT+11";
|
|
case "Ulaanbaatar Standard Time": return "Asia/Ulaanbaatar";
|
|
case "Venezuela Standard Time": return "America/Caracas";
|
|
case "Vladivostok Standard Time": return "Asia/Vladivostok";
|
|
case "W. Australia Standard Time": return "Australia/Perth";
|
|
case "W. Central Africa Standard Time": return "Africa/Lagos";
|
|
case "W. Europe Standard Time": return "Europe/Berlin";
|
|
case "West Asia Standard Time": return "Asia/Tashkent";
|
|
case "West Pacific Standard Time": return "Pacific/Port_Moresby";
|
|
case "Yakutsk Standard Time": return "Asia/Yakutsk";
|
|
default: return null;
|
|
}
|
|
}
|
|
|
|
version(Windows) unittest
|
|
{
|
|
import std.format : format;
|
|
foreach(tzName; WindowsTimeZone.getInstalledTZNames())
|
|
assert(windowsTZNameToTZDatabaseName(tzName) !is null, format("TZName which failed: %s", tzName));
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
// Section with StopWatch and Benchmark Code.
|
|
//==============================================================================
|
|
|
|
/++
|
|
$(D 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 precision of $(D 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 switch
|
|
between threads) can also affect $(D StopWatch)'s accuracy.
|
|
|
|
Examples:
|
|
--------------------
|
|
void foo()
|
|
{
|
|
StopWatch sw;
|
|
enum n = 100;
|
|
TickDuration[n] times;
|
|
TickDuration last = TickDuration.from!"seconds"(0);
|
|
foreach(i; 0..n)
|
|
{
|
|
sw.start(); //start/resume mesuring.
|
|
foreach(unused; 0..1_000_000)
|
|
bar();
|
|
sw.stop(); //stop/pause measuring.
|
|
//Return value of peek() after having stopped are the always same.
|
|
writeln((i + 1) * 1_000_000, " times done, lap time: ",
|
|
sw.peek().msecs, "[ms]");
|
|
times[i] = sw.peek() - last;
|
|
last = sw.peek();
|
|
}
|
|
real sum = 0;
|
|
// To know the number of seconds,
|
|
// use properties of TickDuration.
|
|
// (seconds, msecs, usecs, hnsecs)
|
|
foreach(t; times)
|
|
sum += t.hnsecs;
|
|
writeln("Average time: ", sum/n, " hnsecs");
|
|
}
|
|
--------------------
|
|
+/
|
|
@safe struct StopWatch
|
|
{
|
|
public:
|
|
//Verify Example
|
|
@safe unittest
|
|
{
|
|
void writeln(S...)(S args){}
|
|
static void bar() {}
|
|
|
|
StopWatch sw;
|
|
enum n = 100;
|
|
TickDuration[n] times;
|
|
TickDuration last = TickDuration.from!"seconds"(0);
|
|
foreach(i; 0..n)
|
|
{
|
|
sw.start(); //start/resume mesuring.
|
|
foreach(unused; 0..1_000_000)
|
|
bar();
|
|
sw.stop(); //stop/pause measuring.
|
|
//Return value of peek() after having stopped are the always same.
|
|
writeln((i + 1) * 1_000_000, " times done, lap time: ",
|
|
sw.peek().msecs, "[ms]");
|
|
times[i] = sw.peek() - last;
|
|
last = sw.peek();
|
|
}
|
|
real sum = 0;
|
|
// To get the number of seconds,
|
|
// use properties of TickDuration.
|
|
// (seconds, msecs, usecs, hnsecs)
|
|
foreach(t; times)
|
|
sum += t.hnsecs;
|
|
writeln("Average time: ", sum/n, " hnsecs");
|
|
}
|
|
|
|
/++
|
|
Auto start with constructor.
|
|
+/
|
|
this(AutoStart autostart)
|
|
{
|
|
if(autostart)
|
|
start();
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
auto sw = StopWatch(AutoStart.yes);
|
|
sw.stop();
|
|
}
|
|
|
|
|
|
///
|
|
bool opEquals(const StopWatch rhs) const pure nothrow
|
|
{
|
|
return opEquals(rhs);
|
|
}
|
|
|
|
/// ditto
|
|
bool opEquals(const ref StopWatch rhs) const pure nothrow
|
|
{
|
|
return _timeStart == rhs._timeStart &&
|
|
_timeMeasured == rhs._timeMeasured;
|
|
}
|
|
|
|
|
|
/++
|
|
Resets the stop watch.
|
|
+/
|
|
void reset()
|
|
{
|
|
if(_flagStarted)
|
|
{
|
|
// Set current system time if StopWatch is measuring.
|
|
_timeStart = Clock.currSystemTick;
|
|
}
|
|
else
|
|
{
|
|
// Set zero if StopWatch is not measuring.
|
|
_timeStart.length = 0;
|
|
}
|
|
|
|
_timeMeasured.length = 0;
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
StopWatch sw;
|
|
sw.start();
|
|
sw.stop();
|
|
sw.reset();
|
|
assert(sw.peek().to!("seconds", real)() == 0);
|
|
}
|
|
|
|
|
|
/++
|
|
Starts the stop watch.
|
|
+/
|
|
void start()
|
|
{
|
|
assert(!_flagStarted);
|
|
_flagStarted = true;
|
|
_timeStart = Clock.currSystemTick;
|
|
}
|
|
|
|
@trusted unittest
|
|
{
|
|
StopWatch sw;
|
|
sw.start();
|
|
auto t1 = sw.peek();
|
|
bool doublestart = true;
|
|
try
|
|
sw.start();
|
|
catch(AssertError e)
|
|
doublestart = false;
|
|
assert(!doublestart);
|
|
sw.stop();
|
|
assert((t1 - sw.peek()).to!("seconds", real)() <= 0);
|
|
}
|
|
|
|
|
|
/++
|
|
Stops the stop watch.
|
|
+/
|
|
void stop()
|
|
{
|
|
assert(_flagStarted);
|
|
_flagStarted = false;
|
|
_timeMeasured += Clock.currSystemTick - _timeStart;
|
|
}
|
|
|
|
@trusted unittest
|
|
{
|
|
StopWatch sw;
|
|
sw.start();
|
|
sw.stop();
|
|
auto t1 = sw.peek();
|
|
bool doublestop = true;
|
|
try
|
|
sw.stop();
|
|
catch(AssertError e)
|
|
doublestop = false;
|
|
assert(!doublestop);
|
|
assert((t1 - sw.peek()).to!("seconds", real)() == 0);
|
|
}
|
|
|
|
|
|
/++
|
|
Peek at the amount of time which has passed since the stop watch was
|
|
started.
|
|
+/
|
|
TickDuration peek() const
|
|
{
|
|
if(_flagStarted)
|
|
return Clock.currSystemTick - _timeStart + _timeMeasured;
|
|
|
|
return _timeMeasured;
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
StopWatch sw;
|
|
sw.start();
|
|
auto t1 = sw.peek();
|
|
sw.stop();
|
|
auto t2 = sw.peek();
|
|
auto t3 = sw.peek();
|
|
assert(t1 <= t2);
|
|
assert(t2 == t3);
|
|
}
|
|
|
|
|
|
/++
|
|
Set the amount of time which has been measured since the stop watch was
|
|
started.
|
|
+/
|
|
void setMeasured(TickDuration d)
|
|
{
|
|
reset();
|
|
_timeMeasured = d;
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
StopWatch sw;
|
|
TickDuration t0;
|
|
t0.length = 100;
|
|
sw.setMeasured(t0);
|
|
auto t1 = sw.peek();
|
|
assert(t0 == t1);
|
|
}
|
|
|
|
|
|
/++
|
|
Confirm whether this stopwatch is measuring time.
|
|
+/
|
|
bool running() @property const pure nothrow
|
|
{
|
|
return _flagStarted;
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
StopWatch sw1;
|
|
assert(!sw1.running);
|
|
sw1.start();
|
|
assert(sw1.running);
|
|
sw1.stop();
|
|
assert(!sw1.running);
|
|
StopWatch sw2 = AutoStart.yes;
|
|
assert(sw2.running);
|
|
sw2.stop();
|
|
assert(!sw2.running);
|
|
sw2.start();
|
|
assert(sw2.running);
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
// true if observing.
|
|
bool _flagStarted = false;
|
|
|
|
// TickDuration at the time of StopWatch starting measurement.
|
|
TickDuration _timeStart;
|
|
|
|
// Total time that StopWatch ran.
|
|
TickDuration _timeMeasured;
|
|
}
|
|
|
|
|
|
/++
|
|
Benchmarks code for speed assessment and comparison.
|
|
|
|
Params:
|
|
fun = aliases of callable objects (e.g. function names). Each should
|
|
take no arguments.
|
|
n = The number of times each function is to be executed.
|
|
|
|
Returns:
|
|
The amount of time (as a $(CXREF time, TickDuration)) that it took to
|
|
call each function $(D n) times. The first value is the length of time
|
|
that it took to call $(D fun[0]) $(D n) times. The second value is the
|
|
length of time it took to call $(D fun[1]) $(D n) times. Etc.
|
|
|
|
Note that casting the TickDurations to $(CXREF time, Duration)s will make
|
|
the results easier to deal with (and it may change in the future that
|
|
benchmark will return an array of Durations rather than TickDurations).
|
|
|
|
See_Also:
|
|
$(LREF measureTime)
|
|
+/
|
|
TickDuration[fun.length] benchmark(fun...)(uint n)
|
|
{
|
|
TickDuration[fun.length] result;
|
|
StopWatch sw;
|
|
sw.start();
|
|
|
|
foreach(i, unused; fun)
|
|
{
|
|
sw.reset();
|
|
foreach(j; 0 .. n)
|
|
fun[i]();
|
|
result[i] = sw.peek();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
import std.conv : to;
|
|
int a;
|
|
void f0() {}
|
|
void f1() {auto b = a;}
|
|
void f2() {auto b = to!string(a);}
|
|
auto r = benchmark!(f0, f1, f2)(10_000);
|
|
auto f0Result = to!Duration(r[0]); // time f0 took to run 10,000 times
|
|
auto f1Result = to!Duration(r[1]); // time f1 took to run 10,000 times
|
|
auto f2Result = to!Duration(r[2]); // time f2 took to run 10,000 times
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
int a;
|
|
void f0() {}
|
|
//void f1() {auto b = to!(string)(a);}
|
|
void f2() {auto b = (a);}
|
|
auto r = benchmark!(f0, f2)(100);
|
|
}
|
|
|
|
|
|
/++
|
|
Return value of benchmark with two functions comparing.
|
|
+/
|
|
@safe struct ComparingBenchmarkResult
|
|
{
|
|
/++
|
|
Evaluation value
|
|
|
|
This returns the evaluation value of performance as the ratio of
|
|
baseFunc's time over targetFunc's time. If performance is high, this
|
|
returns a high value.
|
|
+/
|
|
@property real point() const pure nothrow
|
|
{
|
|
return _baseTime.length / cast(const real)_targetTime.length;
|
|
}
|
|
|
|
|
|
/++
|
|
The time required of the base function
|
|
+/
|
|
@property public TickDuration baseTime() const pure nothrow
|
|
{
|
|
return _baseTime;
|
|
}
|
|
|
|
|
|
/++
|
|
The time required of the target function
|
|
+/
|
|
@property public TickDuration targetTime() const pure nothrow
|
|
{
|
|
return _targetTime;
|
|
}
|
|
|
|
private:
|
|
|
|
this(TickDuration baseTime, TickDuration targetTime) pure nothrow
|
|
{
|
|
_baseTime = baseTime;
|
|
_targetTime = targetTime;
|
|
}
|
|
|
|
TickDuration _baseTime;
|
|
TickDuration _targetTime;
|
|
}
|
|
|
|
|
|
/++
|
|
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);
|
|
}
|
|
--------------------
|
|
+/
|
|
ComparingBenchmarkResult comparingBenchmark(alias baseFunc,
|
|
alias targetFunc,
|
|
int times = 0xfff)()
|
|
{
|
|
auto t = benchmark!(baseFunc, targetFunc)(times);
|
|
return ComparingBenchmarkResult(t[0], t[1]);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
void f1x() {}
|
|
void f2x() {}
|
|
@safe void f1o() {}
|
|
@safe void f2o() {}
|
|
auto b1 = comparingBenchmark!(f1o, f2o, 1)(); // OK
|
|
//static auto b2 = comparingBenchmark!(f1x, f2x, 1); // NG
|
|
}
|
|
|
|
unittest
|
|
{
|
|
void f1x() {}
|
|
void f2x() {}
|
|
@safe void f1o() {}
|
|
@safe void f2o() {}
|
|
auto b1 = comparingBenchmark!(f1o, f2o, 1)(); // OK
|
|
auto b2 = comparingBenchmark!(f1x, f2x, 1)(); // OK
|
|
}
|
|
|
|
//Bug# 8450
|
|
unittest
|
|
{
|
|
@safe void safeFunc() {}
|
|
@trusted void trustFunc() {}
|
|
@system void sysFunc() {}
|
|
auto safeResult = comparingBenchmark!((){safeFunc();}, (){safeFunc();})();
|
|
auto trustResult = comparingBenchmark!((){trustFunc();}, (){trustFunc();})();
|
|
auto sysResult = comparingBenchmark!((){sysFunc();}, (){sysFunc();})();
|
|
auto mixedResult1 = comparingBenchmark!((){safeFunc();}, (){trustFunc();})();
|
|
auto mixedResult2 = comparingBenchmark!((){trustFunc();}, (){sysFunc();})();
|
|
auto mixedResult3 = comparingBenchmark!((){safeFunc();}, (){sysFunc();})();
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
// 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) @safe pure nothrow
|
|
{
|
|
if(year % 400 == 0)
|
|
return true;
|
|
|
|
if(year % 100 == 0)
|
|
return false;
|
|
|
|
return year % 4 == 0;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.format : format;
|
|
foreach(year; [1, 2, 3, 5, 6, 7, 100, 200, 300, 500, 600, 700, 1998, 1999,
|
|
2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010, 2011])
|
|
{
|
|
assert(!yearIsLeapYear(year), format("year: %s.", year));
|
|
assert(!yearIsLeapYear(-year), format("year: %s.", year));
|
|
}
|
|
|
|
foreach(year; [0, 4, 8, 400, 800, 1600, 1996, 2000, 2004, 2008, 2012])
|
|
{
|
|
assert(yearIsLeapYear(year), format("year: %s.", year));
|
|
assert(yearIsLeapYear(-year), format("year: %s.", year));
|
|
}
|
|
}
|
|
|
|
/++
|
|
Converts a $(D 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 $(D time_t) to convert.
|
|
+/
|
|
long unixTimeToStdTime(time_t unixTime) @safe pure nothrow
|
|
{
|
|
return 621_355_968_000_000_000L + convert!("seconds", "hnsecs")(unixTime);
|
|
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(unixTimeToStdTime(0) == 621_355_968_000_000_000L); //Midnight, January 1st, 1970
|
|
assert(unixTimeToStdTime(86_400) == 621_355_968_000_000_000L + 864_000_000_000L); //Midnight, January 2nd, 1970
|
|
assert(unixTimeToStdTime(-86_400) == 621_355_968_000_000_000L - 864_000_000_000L); //Midnight, December 31st, 1969
|
|
|
|
assert(unixTimeToStdTime(0) == (Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs");
|
|
assert(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 $(D time_t) (which uses midnight, January 1st,
|
|
1970 UTC as its epoch and seconds as its units). If $(D 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 $(D time_t.max) if it
|
|
goes over and $(D time_t.min) if it goes under).
|
|
|
|
Note:
|
|
While Windows systems require that $(D time_t) be non-negative (in spite
|
|
of $(D 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. If on Windows and using the
|
|
standard C functions or Win32 API functions which take a $(D time_t),
|
|
check whether the return value of
|
|
$(D stdTimeToUnixTime) is non-negative.
|
|
|
|
Params:
|
|
stdTime = The std time to convert.
|
|
+/
|
|
time_t stdTimeToUnixTime(long stdTime) @safe pure nothrow
|
|
{
|
|
immutable unixTime = convert!("hnsecs", "seconds")(stdTime - 621_355_968_000_000_000L);
|
|
|
|
static if(time_t.sizeof >= long.sizeof)
|
|
return cast(time_t)unixTime;
|
|
else
|
|
{
|
|
if(unixTime > 0)
|
|
{
|
|
if(unixTime > time_t.max)
|
|
return time_t.max;
|
|
return cast(time_t)unixTime;
|
|
}
|
|
|
|
if(unixTime < time_t.min)
|
|
return time_t.min;
|
|
|
|
return cast(time_t)unixTime;
|
|
}
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(stdTimeToUnixTime(621_355_968_000_000_000L) == 0); //Midnight, January 1st, 1970
|
|
assert(stdTimeToUnixTime(621_355_968_000_000_000L + 864_000_000_000L) == 86_400); //Midnight, January 2nd, 1970
|
|
assert(stdTimeToUnixTime(621_355_968_000_000_000L - 864_000_000_000L) == -86_400); //Midnight, December 31st, 1969
|
|
|
|
assert(stdTimeToUnixTime((Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs") == 0);
|
|
assert(stdTimeToUnixTime((DateTime(1970, 1, 1) - DateTime(1, 1, 1)).total!"hnsecs") == 0);
|
|
}
|
|
|
|
|
|
version(StdDdoc)
|
|
{
|
|
version(Windows) {}
|
|
else
|
|
{
|
|
alias void* SYSTEMTIME;
|
|
alias void* FILETIME;
|
|
}
|
|
|
|
/++
|
|
$(BLUE This function is Windows-Only.)
|
|
|
|
Converts a $(D SYSTEMTIME) struct to a $(LREF SysTime).
|
|
|
|
Params:
|
|
st = The $(D SYSTEMTIME) struct to convert.
|
|
tz = The time zone that the time in the $(D SYSTEMTIME) struct is
|
|
assumed to be (if the $(D SYSTEMTIME) was supplied by a Windows
|
|
system call, the $(D SYSTEMTIME) will either be in local time
|
|
or UTC, depending on the call).
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given $(D SYSTEMTIME) will not fit in
|
|
a $(LREF SysTime), which is highly unlikely to happen given that
|
|
$(D SysTime.max) is in 29,228 A.D. and the maximum $(D SYSTEMTIME)
|
|
is in 30,827 A.D.
|
|
+/
|
|
SysTime SYSTEMTIMEToSysTime(const SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) @safe;
|
|
|
|
|
|
/++
|
|
$(BLUE This function is Windows-Only.)
|
|
|
|
Converts a $(LREF SysTime) to a $(D SYSTEMTIME) struct.
|
|
|
|
The $(D SYSTEMTIME) which is returned will be set using the given
|
|
$(LREF SysTime)'s time zone, so to get the $(D SYSTEMTIME) in
|
|
UTC, set the $(LREF SysTime)'s time zone to UTC.
|
|
|
|
Params:
|
|
sysTime = The $(LREF SysTime) to convert.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given $(LREF SysTime) will not fit in a
|
|
$(D SYSTEMTIME). This will only happen if the $(LREF SysTime)'s date is
|
|
prior to 1601 A.D.
|
|
+/
|
|
SYSTEMTIME SysTimeToSYSTEMTIME(in SysTime sysTime) @safe;
|
|
|
|
|
|
/++
|
|
$(BLUE This function is Windows-Only.)
|
|
|
|
Converts a $(D FILETIME) struct to the number of hnsecs since midnight,
|
|
January 1st, 1 A.D.
|
|
|
|
Params:
|
|
ft = The $(D FILETIME) struct to convert.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given $(D FILETIME) cannot be
|
|
represented as the return value.
|
|
+/
|
|
long FILETIMEToStdTime(const FILETIME* ft) @safe;
|
|
|
|
|
|
/++
|
|
$(BLUE This function is Windows-Only.)
|
|
|
|
Converts a $(D FILETIME) struct to a $(LREF SysTime).
|
|
|
|
Params:
|
|
ft = The $(D FILETIME) struct to convert.
|
|
tz = The time zone that the $(LREF SysTime) will be in ($(D FILETIME)s
|
|
are in UTC).
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given $(D FILETIME) will not fit in a
|
|
$(LREF SysTime).
|
|
+/
|
|
SysTime FILETIMEToSysTime(const FILETIME* ft, immutable TimeZone tz = LocalTime()) @safe;
|
|
|
|
|
|
/++
|
|
$(BLUE This function is Windows-Only.)
|
|
|
|
Converts a number of hnsecs since midnight, January 1st, 1 A.D. to a
|
|
$(D FILETIME) struct.
|
|
|
|
Params:
|
|
stdTime = The number of hnsecs since midnight, January 1st, 1 A.D. UTC.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given value will not fit in a
|
|
$(D FILETIME).
|
|
+/
|
|
FILETIME stdTimeToFILETIME(long stdTime) @safe;
|
|
|
|
|
|
/++
|
|
$(BLUE This function is Windows-Only.)
|
|
|
|
Converts a $(LREF SysTime) to a $(D FILETIME) struct.
|
|
|
|
$(D FILETIME)s are always in UTC.
|
|
|
|
Params:
|
|
sysTime = The $(LREF SysTime) to convert.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given $(LREF SysTime) will not fit in a
|
|
$(D FILETIME).
|
|
+/
|
|
FILETIME SysTimeToFILETIME(SysTime sysTime) @safe;
|
|
}
|
|
else version(Windows)
|
|
{
|
|
SysTime SYSTEMTIMEToSysTime(const SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) @safe
|
|
{
|
|
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.fracSecs.total!"msecs")
|
|
throwLaterThanMax();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
auto dt = DateTime(st.wYear, st.wMonth, st.wDay,
|
|
st.wHour, st.wMinute, st.wSecond);
|
|
|
|
return SysTime(dt, msecs(st.wMilliseconds), tz);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
auto sysTime = Clock.currTime(UTC());
|
|
SYSTEMTIME st = void;
|
|
GetSystemTime(&st);
|
|
auto converted = SYSTEMTIMEToSysTime(&st, UTC());
|
|
|
|
assert(abs((converted - sysTime)) <= dur!"seconds"(2));
|
|
}
|
|
|
|
|
|
SYSTEMTIME SysTimeToSYSTEMTIME(in SysTime sysTime) @safe
|
|
{
|
|
immutable dt = cast(DateTime)sysTime;
|
|
|
|
if(dt.year < 1601)
|
|
throw new DateTimeException("SYSTEMTIME cannot hold dates prior to the year 1601.");
|
|
|
|
SYSTEMTIME st;
|
|
|
|
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 = cast(ushort)sysTime.fracSecs.total!"msecs";
|
|
|
|
return st;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
SYSTEMTIME st = void;
|
|
GetSystemTime(&st);
|
|
auto sysTime = SYSTEMTIMEToSysTime(&st, UTC());
|
|
|
|
SYSTEMTIME result = SysTimeToSYSTEMTIME(sysTime);
|
|
|
|
assert(st.wYear == result.wYear);
|
|
assert(st.wMonth == result.wMonth);
|
|
assert(st.wDayOfWeek == result.wDayOfWeek);
|
|
assert(st.wDay == result.wDay);
|
|
assert(st.wHour == result.wHour);
|
|
assert(st.wMinute == result.wMinute);
|
|
assert(st.wSecond == result.wSecond);
|
|
assert(st.wMilliseconds == result.wMilliseconds);
|
|
}
|
|
|
|
private enum hnsecsFrom1601 = 504_911_232_000_000_000L;
|
|
|
|
long FILETIMEToStdTime(const FILETIME* ft) @safe
|
|
{
|
|
ULARGE_INTEGER ul;
|
|
ul.HighPart = ft.dwHighDateTime;
|
|
ul.LowPart = ft.dwLowDateTime;
|
|
ulong tempHNSecs = ul.QuadPart;
|
|
|
|
if(tempHNSecs > long.max - hnsecsFrom1601)
|
|
throw new DateTimeException("The given FILETIME cannot be represented as a stdTime value.");
|
|
|
|
return cast(long)tempHNSecs + hnsecsFrom1601;
|
|
}
|
|
|
|
SysTime FILETIMEToSysTime(const FILETIME* ft, immutable TimeZone tz = LocalTime()) @safe
|
|
{
|
|
auto sysTime = SysTime(FILETIMEToStdTime(ft), 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);
|
|
|
|
assert(abs((converted - sysTime)) <= dur!"seconds"(2));
|
|
}
|
|
|
|
|
|
FILETIME stdTimeToFILETIME(long stdTime) @safe
|
|
{
|
|
if(stdTime < hnsecsFrom1601)
|
|
throw new DateTimeException("The given stdTime value cannot be represented as a FILETIME.");
|
|
|
|
ULARGE_INTEGER ul;
|
|
ul.QuadPart = cast(ulong)stdTime - hnsecsFrom1601;
|
|
|
|
FILETIME ft;
|
|
ft.dwHighDateTime = ul.HighPart;
|
|
ft.dwLowDateTime = ul.LowPart;
|
|
|
|
return ft;
|
|
}
|
|
|
|
FILETIME SysTimeToFILETIME(SysTime sysTime) @safe
|
|
{
|
|
return stdTimeToFILETIME(sysTime.stdTime);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
SYSTEMTIME st = void;
|
|
GetSystemTime(&st);
|
|
|
|
FILETIME ft = void;
|
|
SystemTimeToFileTime(&st, &ft);
|
|
auto sysTime = FILETIMEToSysTime(&ft, UTC());
|
|
|
|
FILETIME result = SysTimeToFILETIME(sysTime);
|
|
|
|
assert(ft.dwLowDateTime == result.dwLowDateTime);
|
|
assert(ft.dwHighDateTime == result.dwHighDateTime);
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
Type representing the DOS file date/time format.
|
|
+/
|
|
alias uint DosFileTime;
|
|
|
|
/++
|
|
Converts from DOS file date/time to $(LREF SysTime).
|
|
|
|
Params:
|
|
dft = The DOS file time to convert.
|
|
tz = The time zone which the DOS file time is assumed to be in.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the $(D DosFileTime) is invalid.
|
|
+/
|
|
SysTime DosFileTimeToSysTime(DosFileTime dft, immutable TimeZone tz = LocalTime()) @safe
|
|
{
|
|
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..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)
|
|
|
|
try
|
|
return SysTime(DateTime(year, month, dayOfMonth, hour, minute, second), tz);
|
|
catch(DateTimeException dte)
|
|
throw new DateTimeException("Invalid DosFileTime", __FILE__, __LINE__, dte);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(DosFileTimeToSysTime(0b00000000001000010000000000000000) ==
|
|
SysTime(DateTime(1980, 1, 1, 0, 0, 0)));
|
|
|
|
assert(DosFileTimeToSysTime(0b11111111100111111011111101111101) ==
|
|
SysTime(DateTime(2107, 12, 31, 23, 59, 58)));
|
|
|
|
assert(DosFileTimeToSysTime(0x3E3F8456) ==
|
|
SysTime(DateTime(2011, 1, 31, 16, 34, 44)));
|
|
}
|
|
|
|
|
|
/++
|
|
Converts from $(LREF SysTime) to DOS file date/time.
|
|
|
|
Params:
|
|
sysTime = The $(LREF SysTime) to convert.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given $(LREF SysTime) cannot be converted to
|
|
a $(D DosFileTime).
|
|
+/
|
|
DosFileTime SysTimeToDosFileTime(SysTime sysTime) @safe
|
|
{
|
|
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 past 2107.");
|
|
|
|
uint retval = 0;
|
|
retval = (dateTime.year - 1980) << 25;
|
|
retval |= (dateTime.month & 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;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(SysTimeToDosFileTime(SysTime(DateTime(1980, 1, 1, 0, 0, 0))) ==
|
|
0b00000000001000010000000000000000);
|
|
|
|
assert(SysTimeToDosFileTime(SysTime(DateTime(2107, 12, 31, 23, 59, 58))) ==
|
|
0b11111111100111111011111101111101);
|
|
|
|
assert(SysTimeToDosFileTime(SysTime(DateTime(2011, 1, 31, 16, 34, 44))) ==
|
|
0x3E3F8456);
|
|
}
|
|
|
|
|
|
/++
|
|
The given array of $(D char) or random-access range of $(D char) or
|
|
$(D ubyte) is expected to be in the format specified in
|
|
$(WEB tools.ietf.org/html/rfc5322, RFC 5322) section 3.3 with the
|
|
grammar rule $(I date-time). It is the date-time format commonly used in
|
|
internet messages such as e-mail and HTTP. The corresponding
|
|
$(LREF SysTime) will be returned.
|
|
|
|
RFC 822 was the original spec (hence the function's name), whereas RFC 5322
|
|
is the current spec.
|
|
|
|
The day of the week is ignored beyond verifying that it's a valid day of the
|
|
week, as the day of the week can be inferred from the date. It is not
|
|
checked whether the given day of the week matches the actual day of the week
|
|
of the given date (though it is technically invalid per the spec if the
|
|
day of the week doesn't match the actual day of the week of the given date).
|
|
|
|
If the time zone is $(D "-0000") (or considered to be equivalent to
|
|
$(D "-0000") by section 4.3 of the spec), a $(LREF SimpleTimeZone) with a
|
|
utc offset of $(D 0) is used rather than $(LREF UTC), whereas $(D "+0000")
|
|
uses $(LREF UTC).
|
|
|
|
Note that because $(LREF SysTime) does not currently support having a second
|
|
value of 60 (as is sometimes done for leap seconds), if the date-time value
|
|
does have a value of 60 for the seconds, it is treated as 59.
|
|
|
|
The one area in which this function violates RFC 5322 is that it accepts
|
|
$(D "\n") in folding whitespace in the place of $(D "\r\n"), because the
|
|
HTTP spec requires it.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given string doesn't follow the grammar
|
|
for a date-time field or if the resulting $(LREF SysTime) is invalid.
|
|
+/
|
|
SysTime parseRFC822DateTime()(in char[] value) @safe
|
|
{
|
|
import std.string : representation;
|
|
return parseRFC822DateTime(value.representation);
|
|
}
|
|
|
|
/++ Ditto +/
|
|
SysTime parseRFC822DateTime(R)(R value) @safe
|
|
if(isRandomAccessRange!R && hasSlicing!R && hasLength!R &&
|
|
(is(Unqual!(ElementType!R) == char) || is(Unqual!(ElementType!R) == ubyte)))
|
|
{
|
|
import std.functional : not;
|
|
import std.ascii : isDigit;
|
|
import std.typecons : Rebindable;
|
|
import std.string : capitalize, format;
|
|
import std.conv : to;
|
|
import std.algorithm : find, all;
|
|
|
|
void stripAndCheckLen(R valueBefore, size_t minLen, size_t line = __LINE__)
|
|
{
|
|
value = _stripCFWS(valueBefore);
|
|
if(value.length < minLen)
|
|
throw new DateTimeException("date-time value too short", __FILE__, line);
|
|
}
|
|
stripAndCheckLen(value, "7Dec1200:00A".length);
|
|
|
|
static if(isArray!R && (is(ElementEncodingType!R == char) || is(ElementEncodingType!R == ubyte)))
|
|
{
|
|
static string sliceAsString(R str) @trusted
|
|
{
|
|
return cast(string)str;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char[4] temp;
|
|
char[] sliceAsString(R str) @trusted
|
|
{
|
|
size_t i = 0;
|
|
foreach(c; str)
|
|
temp[i++] = cast(char)c;
|
|
return temp[0 .. str.length];
|
|
}
|
|
}
|
|
|
|
// day-of-week
|
|
if(std.ascii.isAlpha(value[0]))
|
|
{
|
|
auto dowStr = sliceAsString(value[0 .. 3]);
|
|
switch(dowStr)
|
|
{
|
|
foreach(dow; EnumMembers!DayOfWeek)
|
|
{
|
|
enum dowC = capitalize(to!string(dow));
|
|
case dowC:
|
|
goto afterDoW;
|
|
}
|
|
default: throw new DateTimeException(format("Invalid day-of-week: %s", dowStr));
|
|
}
|
|
afterDoW: stripAndCheckLen(value[3 .. value.length], ",7Dec1200:00A".length);
|
|
if(value[0] != ',')
|
|
throw new DateTimeException("day-of-week missing comma");
|
|
stripAndCheckLen(value[1 .. value.length], "7Dec1200:00A".length);
|
|
}
|
|
|
|
// day
|
|
immutable digits = std.ascii.isDigit(value[1]) ? 2 : 1;
|
|
immutable day = _convDigits!short(value[0 .. digits]);
|
|
if(day == -1)
|
|
throw new DateTimeException("Invalid day");
|
|
stripAndCheckLen(value[digits .. value.length], "Dec1200:00A".length);
|
|
|
|
// month
|
|
Month month;
|
|
{
|
|
auto monStr = sliceAsString(value[0 .. 3]);
|
|
switch(monStr)
|
|
{
|
|
foreach(mon; EnumMembers!Month)
|
|
{
|
|
enum monC = capitalize(to!string(mon));
|
|
case monC:
|
|
{
|
|
month = mon;
|
|
goto afterMon;
|
|
}
|
|
}
|
|
default: throw new DateTimeException(format("Invalid month: %s", monStr));
|
|
}
|
|
afterMon: stripAndCheckLen(value[3 .. value.length], "1200:00A".length);
|
|
}
|
|
|
|
// year
|
|
auto found = value[2 .. value.length].find!(not!(std.ascii.isDigit))();
|
|
size_t yearLen = value.length - found.length;
|
|
if(found.length == 0)
|
|
throw new DateTimeException("Invalid year");
|
|
if(found[0] == ':')
|
|
yearLen -= 2;
|
|
auto year = _convDigits!short(value[0 .. yearLen]);
|
|
if(year < 1900)
|
|
{
|
|
if(year == -1)
|
|
throw new DateTimeException("Invalid year");
|
|
if(yearLen < 4)
|
|
{
|
|
if(yearLen == 3)
|
|
year += 1900;
|
|
else if(yearLen == 2)
|
|
year += year < 50 ? 2000 : 1900;
|
|
else
|
|
throw new DateTimeException("Invalid year. Too few digits.");
|
|
}
|
|
else
|
|
throw new DateTimeException("Invalid year. Cannot be earlier than 1900.");
|
|
}
|
|
stripAndCheckLen(value[yearLen .. value.length], "00:00A".length);
|
|
|
|
// hour
|
|
immutable hour = _convDigits!short(value[0 .. 2]);
|
|
stripAndCheckLen(value[2 .. value.length], ":00A".length);
|
|
if(value[0] != ':')
|
|
throw new DateTimeException("Invalid hour");
|
|
stripAndCheckLen(value[1 .. value.length], "00A".length);
|
|
|
|
// minute
|
|
immutable minute = _convDigits!short(value[0 .. 2]);
|
|
stripAndCheckLen(value[2 .. value.length], "A".length);
|
|
|
|
// second
|
|
short second;
|
|
if(value[0] == ':')
|
|
{
|
|
stripAndCheckLen(value[1 .. value.length], "00A".length);
|
|
second = _convDigits!short(value[0 .. 2]);
|
|
// this is just if/until SysTime is sorted out to fully support leap seconds
|
|
if(second == 60)
|
|
second = 59;
|
|
stripAndCheckLen(value[2 .. value.length], "A".length);
|
|
}
|
|
|
|
immutable(TimeZone) parseTZ(int sign)
|
|
{
|
|
if(value.length < 5)
|
|
throw new DateTimeException("Invalid timezone");
|
|
immutable zoneHours = _convDigits!short(value[1 .. 3]);
|
|
immutable zoneMinutes = _convDigits!short(value[3 .. 5]);
|
|
if(zoneHours == -1 || zoneMinutes == -1 || zoneMinutes > 59)
|
|
throw new DateTimeException("Invalid timezone");
|
|
value = value[5 .. value.length];
|
|
immutable utcOffset = (dur!"hours"(zoneHours) + dur!"minutes"(zoneMinutes)) * sign;
|
|
if(utcOffset == Duration.zero)
|
|
{
|
|
return sign == 1 ? cast(immutable(TimeZone))UTC()
|
|
: cast(immutable(TimeZone))new immutable SimpleTimeZone(Duration.zero);
|
|
}
|
|
return new immutable(SimpleTimeZone)(utcOffset);
|
|
}
|
|
|
|
// zone
|
|
Rebindable!(immutable TimeZone) tz;
|
|
if(value[0] == '-')
|
|
tz = parseTZ(-1);
|
|
else if(value[0] == '+')
|
|
tz = parseTZ(1);
|
|
else
|
|
{
|
|
// obs-zone
|
|
immutable tzLen = value.length - find(value, ' ', '\t', '(')[0].length;
|
|
switch(sliceAsString(value[0 .. tzLen <= 4 ? tzLen : 4]))
|
|
{
|
|
case "UT": case "GMT": tz = UTC(); break;
|
|
case "EST": tz = new immutable SimpleTimeZone(dur!"hours"(-5)); break;
|
|
case "EDT": tz = new immutable SimpleTimeZone(dur!"hours"(-4)); break;
|
|
case "CST": tz = new immutable SimpleTimeZone(dur!"hours"(-6)); break;
|
|
case "CDT": tz = new immutable SimpleTimeZone(dur!"hours"(-5)); break;
|
|
case "MST": tz = new immutable SimpleTimeZone(dur!"hours"(-7)); break;
|
|
case "MDT": tz = new immutable SimpleTimeZone(dur!"hours"(-6)); break;
|
|
case "PST": tz = new immutable SimpleTimeZone(dur!"hours"(-8)); break;
|
|
case "PDT": tz = new immutable SimpleTimeZone(dur!"hours"(-7)); break;
|
|
case "J": case "j": throw new DateTimeException("Invalid timezone");
|
|
default:
|
|
{
|
|
if(all!(std.ascii.isAlpha)(value[0 .. tzLen]))
|
|
{
|
|
tz = new immutable SimpleTimeZone(Duration.zero);
|
|
break;
|
|
}
|
|
throw new DateTimeException("Invalid timezone");
|
|
}
|
|
}
|
|
value = value[tzLen .. value.length];
|
|
}
|
|
|
|
// This is kind of arbitrary. Technically, nothing but CFWS is legal past
|
|
// the end of the timezone, but we don't want to be picky about that in a
|
|
// function that's just parsing rather than validating. So, the idea here is
|
|
// that if the next character is printable (and not part of CFWS), then it
|
|
// might be part of the timezone and thus affect what the timezone was
|
|
// supposed to be, so we'll throw, but otherwise, we'll just ignore it.
|
|
if(!value.empty && std.ascii.isPrintable(value[0]) && value[0] != ' ' && value[0] != '(')
|
|
throw new DateTimeException("Invalid timezone");
|
|
|
|
try
|
|
return SysTime(DateTime(year, month, day, hour, minute, second), tz);
|
|
catch(DateTimeException dte)
|
|
throw new DateTimeException("date-time format is correct, but the resulting SysTime is invalid.", dte);
|
|
}
|
|
|
|
///
|
|
unittest
|
|
{
|
|
auto tz = new immutable SimpleTimeZone(hours(-8));
|
|
assert(parseRFC822DateTime("Sat, 6 Jan 1990 12:14:19 -0800") ==
|
|
SysTime(DateTime(1990, 1, 6, 12, 14, 19), tz));
|
|
|
|
assert(parseRFC822DateTime("9 Jul 2002 13:11 +0000") ==
|
|
SysTime(DateTime(2002, 7, 9, 13, 11, 0), UTC()));
|
|
|
|
auto badStr = "29 Feb 2001 12:17:16 +0200";
|
|
assertThrown!DateTimeException(parseRFC822DateTime(badStr));
|
|
}
|
|
|
|
version(unittest) void testParse822(alias cr)(string str, SysTime expected, size_t line = __LINE__)
|
|
{
|
|
import std.string;
|
|
import std.format : format;
|
|
auto value = cr(str);
|
|
auto result = parseRFC822DateTime(value);
|
|
if(result != expected)
|
|
throw new AssertError(format("wrong result. expected [%s], actual[%s]", expected, result), __FILE__, line);
|
|
}
|
|
|
|
version(unittest) void testBadParse822(alias cr)(string str, size_t line = __LINE__)
|
|
{
|
|
try
|
|
parseRFC822DateTime(cr(str));
|
|
catch(DateTimeException)
|
|
return;
|
|
throw new AssertError("No DateTimeException was thrown", __FILE__, line);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.algorithm;
|
|
import std.ascii;
|
|
import std.format : format;
|
|
import std.range;
|
|
import std.string;
|
|
import std.typecons;
|
|
import std.meta;
|
|
|
|
static struct Rand3Letters
|
|
{
|
|
enum empty = false;
|
|
@property auto front() { return _mon; }
|
|
void popFront()
|
|
{
|
|
import std.random;
|
|
_mon = rndGen.map!(a => letters[a % letters.length])().take(3).array().assumeUnique();
|
|
}
|
|
string _mon;
|
|
static auto start() { Rand3Letters retval; retval.popFront(); return retval; }
|
|
}
|
|
|
|
foreach(cr; TypeTuple!(function(string a){return cast(char[])a;},
|
|
function(string a){return cast(ubyte[])a;},
|
|
function(string a){return a;},
|
|
function(string a){return map!(b => cast(char)b)(a.representation);}))
|
|
(){ // avoid slow optimizations for large functions @@@BUG@@@ 2396
|
|
scope(failure) writeln(typeof(cr).stringof);
|
|
alias testParse822!cr test;
|
|
alias testBadParse822!cr testBad;
|
|
|
|
immutable std1 = DateTime(2012, 12, 21, 13, 14, 15);
|
|
immutable std2 = DateTime(2012, 12, 21, 13, 14, 0);
|
|
immutable dst1 = DateTime(1976, 7, 4, 5, 4, 22);
|
|
immutable dst2 = DateTime(1976, 7, 4, 5, 4, 0);
|
|
|
|
test("21 Dec 2012 13:14:15 +0000", SysTime(std1, UTC()));
|
|
test("21 Dec 2012 13:14 +0000", SysTime(std2, UTC()));
|
|
test("Fri, 21 Dec 2012 13:14 +0000", SysTime(std2, UTC()));
|
|
test("Fri, 21 Dec 2012 13:14:15 +0000", SysTime(std1, UTC()));
|
|
|
|
test("04 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
|
|
test("04 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
|
|
test("Sun, 04 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
|
|
test("Sun, 04 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
|
|
|
|
test("4 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
|
|
test("4 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
|
|
test("Sun, 4 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
|
|
test("Sun, 4 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
|
|
|
|
auto badTZ = new immutable SimpleTimeZone(Duration.zero);
|
|
test("21 Dec 2012 13:14:15 -0000", SysTime(std1, badTZ));
|
|
test("21 Dec 2012 13:14 -0000", SysTime(std2, badTZ));
|
|
test("Fri, 21 Dec 2012 13:14 -0000", SysTime(std2, badTZ));
|
|
test("Fri, 21 Dec 2012 13:14:15 -0000", SysTime(std1, badTZ));
|
|
|
|
test("04 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
|
|
test("04 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
|
|
test("Sun, 04 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
|
|
test("Sun, 04 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
|
|
|
|
test("4 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
|
|
test("4 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
|
|
test("Sun, 4 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
|
|
test("Sun, 4 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
|
|
|
|
auto pst = new immutable SimpleTimeZone(dur!"hours"(-8));
|
|
auto pdt = new immutable SimpleTimeZone(dur!"hours"(-7));
|
|
test("21 Dec 2012 13:14:15 -0800", SysTime(std1, pst));
|
|
test("21 Dec 2012 13:14 -0800", SysTime(std2, pst));
|
|
test("Fri, 21 Dec 2012 13:14 -0800", SysTime(std2, pst));
|
|
test("Fri, 21 Dec 2012 13:14:15 -0800", SysTime(std1, pst));
|
|
|
|
test("04 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
|
|
test("04 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
|
|
test("Sun, 04 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
|
|
test("Sun, 04 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
|
|
|
|
test("4 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
|
|
test("4 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
|
|
test("Sun, 4 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
|
|
test("Sun, 4 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
|
|
|
|
auto cet = new immutable SimpleTimeZone(dur!"hours"(1));
|
|
auto cest = new immutable SimpleTimeZone(dur!"hours"(2));
|
|
test("21 Dec 2012 13:14:15 +0100", SysTime(std1, cet));
|
|
test("21 Dec 2012 13:14 +0100", SysTime(std2, cet));
|
|
test("Fri, 21 Dec 2012 13:14 +0100", SysTime(std2, cet));
|
|
test("Fri, 21 Dec 2012 13:14:15 +0100", SysTime(std1, cet));
|
|
|
|
test("04 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
|
|
test("04 Jul 1976 05:04 +0200", SysTime(dst2, cest));
|
|
test("Sun, 04 Jul 1976 05:04 +0200", SysTime(dst2, cest));
|
|
test("Sun, 04 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
|
|
|
|
test("4 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
|
|
test("4 Jul 1976 05:04 +0200", SysTime(dst2, cest));
|
|
test("Sun, 4 Jul 1976 05:04 +0200", SysTime(dst2, cest));
|
|
test("Sun, 4 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
|
|
|
|
// dst and std times are switched in the Southern Hemisphere which is why the
|
|
// time zone names and DateTime variables don't match.
|
|
auto cstStd = new immutable SimpleTimeZone(dur!"hours"(9) + dur!"minutes"(30));
|
|
auto cstDST = new immutable SimpleTimeZone(dur!"hours"(10) + dur!"minutes"(30));
|
|
test("21 Dec 2012 13:14:15 +1030", SysTime(std1, cstDST));
|
|
test("21 Dec 2012 13:14 +1030", SysTime(std2, cstDST));
|
|
test("Fri, 21 Dec 2012 13:14 +1030", SysTime(std2, cstDST));
|
|
test("Fri, 21 Dec 2012 13:14:15 +1030", SysTime(std1, cstDST));
|
|
|
|
test("04 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
|
|
test("04 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
|
|
test("Sun, 04 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
|
|
test("Sun, 04 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
|
|
|
|
test("4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
|
|
test("4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
|
|
test("Sun, 4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
|
|
test("Sun, 4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
|
|
|
|
foreach(int i, mon; _monthNames)
|
|
{
|
|
test(format("17 %s 2012 00:05:02 +0000", mon), SysTime(DateTime(2012, i + 1, 17, 0, 5, 2), UTC()));
|
|
test(format("17 %s 2012 00:05 +0000", mon), SysTime(DateTime(2012, i + 1, 17, 0, 5, 0), UTC()));
|
|
}
|
|
|
|
import std.uni;
|
|
foreach(mon; chain(_monthNames[].map!(a => toLower(a))(),
|
|
_monthNames[].map!(a => toUpper(a))(),
|
|
["Jam", "Jen", "Fec", "Fdb", "Mas", "Mbr", "Aps", "Aqr", "Mai", "Miy",
|
|
"Jum", "Jbn", "Jup", "Jal", "Aur", "Apg", "Sem", "Sap", "Ocm", "Odt",
|
|
"Nom", "Nav", "Dem", "Dac"],
|
|
Rand3Letters.start().take(20)))
|
|
{
|
|
scope(failure) writefln("Month: %s", mon);
|
|
testBad(format("17 %s 2012 00:05:02 +0000", mon));
|
|
testBad(format("17 %s 2012 00:05 +0000", mon));
|
|
}
|
|
|
|
immutable string[7] daysOfWeekNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
|
|
{
|
|
auto start = SysTime(DateTime(2012, 11, 11, 9, 42, 0), UTC());
|
|
int day = 11;
|
|
|
|
foreach(int i, dow; daysOfWeekNames)
|
|
{
|
|
auto curr = start + dur!"days"(i);
|
|
test(format("%s, %s Nov 2012 09:42:00 +0000", dow, day), curr);
|
|
test(format("%s, %s Nov 2012 09:42 +0000", dow, day++), curr);
|
|
|
|
// Whether the day of the week matches the date is ignored.
|
|
test(format("%s, 11 Nov 2012 09:42:00 +0000", dow), start);
|
|
test(format("%s, 11 Nov 2012 09:42 +0000", dow), start);
|
|
}
|
|
}
|
|
|
|
foreach(dow; chain(daysOfWeekNames[].map!(a => toLower(a))(),
|
|
daysOfWeekNames[].map!(a => toUpper(a))(),
|
|
["Sum", "Spn", "Mom", "Man", "Tuf", "Tae", "Wem", "Wdd", "The", "Tur",
|
|
"Fro", "Fai", "San", "Sut"],
|
|
Rand3Letters.start().take(20)))
|
|
{
|
|
scope(failure) writefln("Day of Week: %s", dow);
|
|
testBad(format("%s, 11 Nov 2012 09:42:00 +0000", dow));
|
|
testBad(format("%s, 11 Nov 2012 09:42 +0000", dow));
|
|
}
|
|
|
|
testBad("31 Dec 1899 23:59:59 +0000");
|
|
test("01 Jan 1900 00:00:00 +0000", SysTime(Date(1900, 1, 1), UTC()));
|
|
test("01 Jan 1900 00:00:00 -0000", SysTime(Date(1900, 1, 1),
|
|
new immutable SimpleTimeZone(Duration.zero)));
|
|
test("01 Jan 1900 00:00:00 -0700", SysTime(Date(1900, 1, 1),
|
|
new immutable SimpleTimeZone(dur!"hours"(-7))));
|
|
|
|
{
|
|
auto st1 = SysTime(Date(1900, 1, 1), UTC());
|
|
auto st2 = SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-11)));
|
|
foreach(i; 1900 .. 2102)
|
|
{
|
|
test(format("1 Jan %05d 00:00 +0000", i), st1);
|
|
test(format("1 Jan %05d 00:00 -1100", i), st2);
|
|
st1.add!"years"(1);
|
|
st2.add!"years"(1);
|
|
}
|
|
st1.year = 9998;
|
|
st2.year = 9998;
|
|
foreach(i; 9998 .. 11_002)
|
|
{
|
|
test(format("1 Jan %05d 00:00 +0000", i), st1);
|
|
test(format("1 Jan %05d 00:00 -1100", i), st2);
|
|
st1.add!"years"(1);
|
|
st2.add!"years"(1);
|
|
}
|
|
}
|
|
|
|
testBad("12 Feb 1907 23:17:09 0000");
|
|
testBad("12 Feb 1907 23:17:09 +000");
|
|
testBad("12 Feb 1907 23:17:09 -000");
|
|
testBad("12 Feb 1907 23:17:09 +00000");
|
|
testBad("12 Feb 1907 23:17:09 -00000");
|
|
testBad("12 Feb 1907 23:17:09 +A");
|
|
testBad("12 Feb 1907 23:17:09 +PST");
|
|
testBad("12 Feb 1907 23:17:09 -A");
|
|
testBad("12 Feb 1907 23:17:09 -PST");
|
|
|
|
// test trailing stuff that gets ignored
|
|
{
|
|
foreach(c; chain(iota(0, 33), ['('], iota(127, ubyte.max + 1)))
|
|
{
|
|
scope(failure) writefln("c: %d", c);
|
|
test(format("21 Dec 2012 13:14:15 +0000%c", cast(char)c), SysTime(std1, UTC()));
|
|
test(format("21 Dec 2012 13:14:15 +0000%c ", cast(char)c), SysTime(std1, UTC()));
|
|
test(format("21 Dec 2012 13:14:15 +0000%chello", cast(char)c), SysTime(std1, UTC()));
|
|
}
|
|
}
|
|
|
|
// test trailing stuff that doesn't get ignored
|
|
{
|
|
foreach(c; chain(iota(33, '('), iota('(' + 1, 127)))
|
|
{
|
|
scope(failure) writefln("c: %d", c);
|
|
testBad(format("21 Dec 2012 13:14:15 +0000%c", cast(char)c));
|
|
testBad(format("21 Dec 2012 13:14:15 +0000%c ", cast(char)c));
|
|
testBad(format("21 Dec 2012 13:14:15 +0000%chello", cast(char)c));
|
|
}
|
|
}
|
|
|
|
testBad("32 Jan 2012 12:13:14 -0800");
|
|
testBad("31 Jan 2012 24:13:14 -0800");
|
|
testBad("31 Jan 2012 12:60:14 -0800");
|
|
testBad("31 Jan 2012 12:13:61 -0800");
|
|
testBad("31 Jan 2012 12:13:14 -0860");
|
|
test("31 Jan 2012 12:13:14 -0859",
|
|
SysTime(DateTime(2012, 1, 31, 12, 13, 14),
|
|
new immutable SimpleTimeZone(dur!"hours"(-8) + dur!"minutes"(-59))));
|
|
|
|
// leap-seconds
|
|
test("21 Dec 2012 15:59:60 -0800", SysTime(DateTime(2012, 12, 21, 15, 59, 59), pst));
|
|
|
|
// FWS
|
|
test("Sun,4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
|
|
test("Sun,4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
|
|
test("Sun,4 Jul 1976 05:04 +0930 (foo)", SysTime(dst2, cstStd));
|
|
test("Sun,4 Jul 1976 05:04:22 +0930 (foo)", SysTime(dst1, cstStd));
|
|
test("Sun,4 \r\n Jul \r\n 1976 \r\n 05:04 \r\n +0930 \r\n (foo)", SysTime(dst2, cstStd));
|
|
test("Sun,4 \r\n Jul \r\n 1976 \r\n 05:04:22 \r\n +0930 \r\n (foo)", SysTime(dst1, cstStd));
|
|
|
|
auto str = "01 Jan 2012 12:13:14 -0800 ";
|
|
test(str, SysTime(DateTime(2012, 1, 1, 12, 13, 14), new immutable SimpleTimeZone(hours(-8))));
|
|
foreach(i; 0 .. str.length)
|
|
{
|
|
auto currStr = str.dup;
|
|
currStr[i] = 'x';
|
|
scope(failure) writefln("failed: %s", currStr);
|
|
testBad(cast(string)currStr);
|
|
}
|
|
foreach(i; 2 .. str.length)
|
|
{
|
|
auto currStr = str[0 .. $ - i];
|
|
scope(failure) writefln("failed: %s", currStr);
|
|
testBad(cast(string)currStr);
|
|
testBad((cast(string)currStr) ~ " ");
|
|
}
|
|
}();
|
|
}
|
|
|
|
// Obsolete Format per section 4.3 of RFC 5322.
|
|
unittest
|
|
{
|
|
import std.algorithm;
|
|
import std.ascii;
|
|
import std.format : format;
|
|
import std.range;
|
|
import std.string;
|
|
import std.typecons;
|
|
import std.meta;
|
|
|
|
auto std1 = SysTime(DateTime(2012, 12, 21, 13, 14, 15), UTC());
|
|
auto std2 = SysTime(DateTime(2012, 12, 21, 13, 14, 0), UTC());
|
|
auto std3 = SysTime(DateTime(1912, 12, 21, 13, 14, 15), UTC());
|
|
auto std4 = SysTime(DateTime(1912, 12, 21, 13, 14, 0), UTC());
|
|
auto dst1 = SysTime(DateTime(1976, 7, 4, 5, 4, 22), UTC());
|
|
auto dst2 = SysTime(DateTime(1976, 7, 4, 5, 4, 0), UTC());
|
|
auto tooLate1 = SysTime(Date(10_000, 1, 1), UTC());
|
|
auto tooLate2 = SysTime(DateTime(12_007, 12, 31, 12, 22, 19), UTC());
|
|
|
|
foreach(cr; TypeTuple!(function(string a){return cast(char[])a;},
|
|
function(string a){return cast(ubyte[])a;},
|
|
function(string a){return a;},
|
|
function(string a){return map!(b => cast(char)b)(a.representation);}))
|
|
(){ // avoid slow optimizations for large functions @@@BUG@@@ 2396
|
|
scope(failure) writeln(typeof(cr).stringof);
|
|
alias testParse822!cr test;
|
|
{
|
|
auto list = ["", " ", " \r\n\t", "\t\r\n (hello world( frien(dog)) silly \r\n ) \t\t \r\n ()",
|
|
" \n ", "\t\n\t", " \n\t (foo) \n (bar) \r\n (baz) \n "];
|
|
|
|
foreach(i, cfws; list)
|
|
{
|
|
scope(failure) writefln("i: %s", i);
|
|
|
|
test(format("%1$s21%1$sDec%1$s2012%1$s13:14:15%1$s+0000%1$s", cfws), std1);
|
|
test(format("%1$s21%1$sDec%1$s2012%1$s13:14%1$s+0000%1$s", cfws), std2);
|
|
test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s2012%1$s13:14%1$s+0000%1$s", cfws), std2);
|
|
test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s2012%1$s13:14:15%1$s+0000%1$s", cfws), std1);
|
|
|
|
test(format("%1$s04%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
|
|
test(format("%1$s04%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
|
|
test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
|
|
test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s1976%1$s05:04:22 +0000%1$s", cfws), dst1);
|
|
|
|
test(format("%1$s4%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
|
|
test(format("%1$s4%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
|
|
test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
|
|
test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
|
|
|
|
test(format("%1$s21%1$sDec%1$s12%1$s13:14:15%1$s+0000%1$s", cfws), std1);
|
|
test(format("%1$s21%1$sDec%1$s12%1$s13:14%1$s+0000%1$s", cfws), std2);
|
|
test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s12%1$s13:14%1$s+0000%1$s", cfws), std2);
|
|
test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s12%1$s13:14:15%1$s+0000%1$s", cfws), std1);
|
|
|
|
test(format("%1$s04%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
|
|
test(format("%1$s04%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
|
|
test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
|
|
test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
|
|
|
|
test(format("%1$s4%1$sJul%1$s76 05:04:22%1$s+0000%1$s", cfws), dst1);
|
|
test(format("%1$s4%1$sJul%1$s76 05:04%1$s+0000%1$s", cfws), dst2);
|
|
test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
|
|
test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
|
|
|
|
test(format("%1$s21%1$sDec%1$s012%1$s13:14:15%1$s+0000%1$s", cfws), std3);
|
|
test(format("%1$s21%1$sDec%1$s012%1$s13:14%1$s+0000%1$s", cfws), std4);
|
|
test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s012%1$s13:14%1$s+0000%1$s", cfws), std4);
|
|
test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s012%1$s13:14:15%1$s+0000%1$s", cfws), std3);
|
|
|
|
test(format("%1$s04%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
|
|
test(format("%1$s04%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
|
|
test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
|
|
test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
|
|
|
|
test(format("%1$s4%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
|
|
test(format("%1$s4%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
|
|
test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
|
|
test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
|
|
|
|
test(format("%1$s1%1$sJan%1$s10000%1$s00:00:00%1$s+0000%1$s", cfws), tooLate1);
|
|
test(format("%1$s31%1$sDec%1$s12007%1$s12:22:19%1$s+0000%1$s", cfws), tooLate2);
|
|
test(format("%1$sSat%1$s,%1$s1%1$sJan%1$s10000%1$s00:00:00%1$s+0000%1$s", cfws), tooLate1);
|
|
test(format("%1$sSun%1$s,%1$s31%1$sDec%1$s12007%1$s12:22:19%1$s+0000%1$s", cfws), tooLate2);
|
|
}
|
|
}
|
|
|
|
// test years of 1, 2, and 3 digits.
|
|
{
|
|
auto st1 = SysTime(Date(2000, 1, 1), UTC());
|
|
auto st2 = SysTime(Date(2000, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-12)));
|
|
foreach(i; 0 .. 50)
|
|
{
|
|
test(format("1 Jan %02d 00:00 GMT", i), st1);
|
|
test(format("1 Jan %02d 00:00 -1200", i), st2);
|
|
st1.add!"years"(1);
|
|
st2.add!"years"(1);
|
|
}
|
|
}
|
|
|
|
{
|
|
auto st1 = SysTime(Date(1950, 1, 1), UTC());
|
|
auto st2 = SysTime(Date(1950, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-12)));
|
|
foreach(i; 50 .. 100)
|
|
{
|
|
test(format("1 Jan %02d 00:00 GMT", i), st1);
|
|
test(format("1 Jan %02d 00:00 -1200", i), st2);
|
|
st1.add!"years"(1);
|
|
st2.add!"years"(1);
|
|
}
|
|
}
|
|
|
|
{
|
|
auto st1 = SysTime(Date(1900, 1, 1), UTC());
|
|
auto st2 = SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-11)));
|
|
foreach(i; 0 .. 1000)
|
|
{
|
|
test(format("1 Jan %03d 00:00 GMT", i), st1);
|
|
test(format("1 Jan %03d 00:00 -1100", i), st2);
|
|
st1.add!"years"(1);
|
|
st2.add!"years"(1);
|
|
}
|
|
}
|
|
|
|
foreach(i; 0 .. 10)
|
|
{
|
|
auto str1 = cr(format("1 Jan %d 00:00 GMT", i));
|
|
auto str2 = cr(format("1 Jan %d 00:00 -1200", i));
|
|
assertThrown!DateTimeException(parseRFC822DateTime(str1));
|
|
assertThrown!DateTimeException(parseRFC822DateTime(str1));
|
|
}
|
|
|
|
// test time zones
|
|
{
|
|
auto dt = DateTime(1982, 05, 03, 12, 22, 04);
|
|
test("Wed, 03 May 1982 12:22:04 UT", SysTime(dt, UTC()));
|
|
test("Wed, 03 May 1982 12:22:04 GMT", SysTime(dt, UTC()));
|
|
test("Wed, 03 May 1982 12:22:04 EST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-5))));
|
|
test("Wed, 03 May 1982 12:22:04 EDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-4))));
|
|
test("Wed, 03 May 1982 12:22:04 CST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-6))));
|
|
test("Wed, 03 May 1982 12:22:04 CDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-5))));
|
|
test("Wed, 03 May 1982 12:22:04 MST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-7))));
|
|
test("Wed, 03 May 1982 12:22:04 MDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-6))));
|
|
test("Wed, 03 May 1982 12:22:04 PST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-8))));
|
|
test("Wed, 03 May 1982 12:22:04 PDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-7))));
|
|
|
|
auto badTZ = new immutable SimpleTimeZone(Duration.zero);
|
|
foreach(dchar c; filter!(a => a != 'j' && a != 'J')(letters))
|
|
{
|
|
scope(failure) writefln("c: %s", c);
|
|
test(format("Wed, 03 May 1982 12:22:04 %s", c), SysTime(dt, badTZ));
|
|
test(format("Wed, 03 May 1982 12:22:04%s", c), SysTime(dt, badTZ));
|
|
}
|
|
|
|
foreach(dchar c; ['j', 'J'])
|
|
{
|
|
scope(failure) writefln("c: %s", c);
|
|
assertThrown!DateTimeException(parseRFC822DateTime(cr(format("Wed, 03 May 1982 12:22:04 %s", c))));
|
|
assertThrown!DateTimeException(parseRFC822DateTime(cr(format("Wed, 03 May 1982 12:22:04%s", c))));
|
|
}
|
|
|
|
foreach(string s; ["AAA", "GQW", "DDT", "PDA", "GT", "GM"])
|
|
{
|
|
scope(failure) writefln("s: %s", s);
|
|
test(format("Wed, 03 May 1982 12:22:04 %s", s), SysTime(dt, badTZ));
|
|
}
|
|
|
|
// test trailing stuff that gets ignored
|
|
{
|
|
foreach(c; chain(iota(0, 33), ['('], iota(127, ubyte.max + 1)))
|
|
{
|
|
scope(failure) writefln("c: %d", c);
|
|
test(format("21Dec1213:14:15+0000%c", cast(char)c), std1);
|
|
test(format("21Dec1213:14:15+0000%c ", cast(char)c), std1);
|
|
test(format("21Dec1213:14:15+0000%chello", cast(char)c), std1);
|
|
}
|
|
}
|
|
|
|
// test trailing stuff that doesn't get ignored
|
|
{
|
|
foreach(c; chain(iota(33, '('), iota('(' + 1, 127)))
|
|
{
|
|
scope(failure) writefln("c: %d", c);
|
|
assertThrown!DateTimeException(parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%c", cast(char)c))));
|
|
assertThrown!DateTimeException(parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%c ", cast(char)c))));
|
|
assertThrown!DateTimeException(parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%chello", cast(char)c))));
|
|
}
|
|
}
|
|
}
|
|
|
|
// test that the checks for minimum length work correctly and avoid
|
|
// any RangeErrors.
|
|
test("7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
|
|
new immutable SimpleTimeZone(Duration.zero)));
|
|
test("Fri,7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
|
|
new immutable SimpleTimeZone(Duration.zero)));
|
|
test("7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
|
|
new immutable SimpleTimeZone(Duration.zero)));
|
|
test("Fri,7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
|
|
new immutable SimpleTimeZone(Duration.zero)));
|
|
|
|
auto tooShortMsg = collectExceptionMsg!DateTimeException(parseRFC822DateTime(""));
|
|
foreach(str; ["Fri,7Dec1200:00:00", "7Dec1200:00:00"])
|
|
{
|
|
foreach(i; 0 .. str.length)
|
|
{
|
|
auto value = str[0 .. $ - i];
|
|
scope(failure) writeln(value);
|
|
assert(collectExceptionMsg!DateTimeException(parseRFC822DateTime(value)) == tooShortMsg);
|
|
}
|
|
}
|
|
}();
|
|
}
|
|
|
|
|
|
/++
|
|
Whether all of the given strings are valid units of time.
|
|
|
|
$(D "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...) @safe pure nothrow
|
|
{
|
|
import std.algorithm : canFind;
|
|
foreach(str; units)
|
|
{
|
|
if(!canFind(timeStrings[], str))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/++
|
|
Compares two time unit strings. $(D "years") are the largest units and
|
|
$(D "hnsecs") are the smallest.
|
|
|
|
Returns:
|
|
$(BOOKTABLE,
|
|
$(TR $(TD this < rhs) $(TD < 0))
|
|
$(TR $(TD this == rhs) $(TD 0))
|
|
$(TR $(TD this > rhs) $(TD > 0))
|
|
)
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if either of the given strings is not a valid
|
|
time unit string.
|
|
+/
|
|
int cmpTimeUnits(string lhs, string rhs) @safe pure
|
|
{
|
|
import std.format : format;
|
|
import std.algorithm : countUntil;
|
|
|
|
auto tstrings = timeStrings;
|
|
immutable indexOfLHS = countUntil(tstrings, lhs);
|
|
immutable indexOfRHS = countUntil(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)
|
|
{
|
|
assert(cmpTimeUnits(outerUnits, outerUnits) == 0);
|
|
|
|
//For some reason, $ won't compile.
|
|
foreach(innerUnits; timeStrings[i+1 .. timeStrings.length])
|
|
assert(cmpTimeUnits(outerUnits, innerUnits) == -1);
|
|
}
|
|
|
|
foreach(i, outerUnits; timeStrings)
|
|
{
|
|
foreach(innerUnits; timeStrings[0 .. i])
|
|
assert(cmpTimeUnits(outerUnits, innerUnits) == 1);
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
Compares two time unit strings at compile time. $(D "years") are the largest
|
|
units and $(D "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:
|
|
$(BOOKTABLE,
|
|
$(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 $(D CmpTimeUnits).
|
|
+/
|
|
private int cmpTimeUnitsCTFE(string lhs, string rhs) @safe pure nothrow
|
|
{
|
|
import std.algorithm : countUntil;
|
|
auto tstrings = timeStrings;
|
|
immutable indexOfLHS = countUntil(tstrings, lhs);
|
|
immutable indexOfRHS = countUntil(tstrings, rhs);
|
|
|
|
if(indexOfLHS < indexOfRHS)
|
|
return -1;
|
|
if(indexOfLHS > indexOfRHS)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.format : format;
|
|
import std.string;
|
|
import std.typecons;
|
|
import std.meta;
|
|
|
|
static string genTest(size_t index)
|
|
{
|
|
auto currUnits = timeStrings[index];
|
|
auto test = format(`assert(CmpTimeUnits!("%s", "%s") == 0);`, currUnits, currUnits);
|
|
|
|
foreach(units; timeStrings[index + 1 .. $])
|
|
test ~= format(`assert(CmpTimeUnits!("%s", "%s") == -1);`, currUnits, units);
|
|
|
|
foreach(units; timeStrings[0 .. index])
|
|
test ~= format(`assert(CmpTimeUnits!("%s", "%s") == 1);`, currUnits, units);
|
|
|
|
return test;
|
|
}
|
|
|
|
static assert(timeStrings.length == 10);
|
|
foreach(n; TypeTuple!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9))
|
|
mixin(genTest(n));
|
|
}
|
|
|
|
|
|
/++
|
|
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.
|
|
+/
|
|
bool valid(string units)(int value) @safe 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
|
|
{
|
|
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) @safe 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 $(LREF DateTimeException) will list if thrown.
|
|
line = The line number that the $(LREF DateTimeException) will list if
|
|
thrown.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if $(D valid!units(value)) is false.
|
|
+/
|
|
void enforceValid(string units)(int value, string file = __FILE__, size_t line = __LINE__) @safe pure
|
|
if(units == "months" ||
|
|
units == "hours" ||
|
|
units == "minutes" ||
|
|
units == "seconds")
|
|
{
|
|
import std.format : format;
|
|
|
|
static if(units == "months")
|
|
{
|
|
if(!valid!units(value))
|
|
throw new DateTimeException(format("%s is not a valid month of the year.", value), file, line);
|
|
}
|
|
else static if(units == "hours")
|
|
{
|
|
if(!valid!units(value))
|
|
throw new DateTimeException(format("%s is not a valid hour of the day.", value), file, line);
|
|
}
|
|
else static if(units == "minutes")
|
|
{
|
|
if(!valid!units(value))
|
|
throw new DateTimeException(format("%s is not a valid minute of an hour.", value), file, line);
|
|
}
|
|
else static if(units == "seconds")
|
|
{
|
|
if(!valid!units(value))
|
|
throw new DateTimeException(format("%s is not a valid second of a minute.", value), 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 $(LREF DateTimeException) will list if thrown.
|
|
line = The line number that the $(LREF DateTimeException) will list if
|
|
thrown.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if $(D valid!"days"(year, month, day)) is false.
|
|
+/
|
|
void enforceValid(string units)
|
|
(int year, Month month, int day, string file = __FILE__, size_t line = __LINE__) @safe pure
|
|
if(units == "days")
|
|
{
|
|
import std.format : format;
|
|
if(!valid!"days"(year, month, day))
|
|
throw new DateTimeException(format("%s is not a valid day in %s in %s", day, month, 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) @safe pure
|
|
{
|
|
enforceValid!"months"(currMonth);
|
|
enforceValid!"months"(month);
|
|
|
|
if(currMonth == month)
|
|
return 0;
|
|
|
|
if(currMonth < month)
|
|
return month - currMonth;
|
|
|
|
return (Month.dec - currMonth) + month;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(monthsToMonth(Month.jan, Month.jan) == 0);
|
|
assert(monthsToMonth(Month.jan, Month.feb) == 1);
|
|
assert(monthsToMonth(Month.jan, Month.mar) == 2);
|
|
assert(monthsToMonth(Month.jan, Month.apr) == 3);
|
|
assert(monthsToMonth(Month.jan, Month.may) == 4);
|
|
assert(monthsToMonth(Month.jan, Month.jun) == 5);
|
|
assert(monthsToMonth(Month.jan, Month.jul) == 6);
|
|
assert(monthsToMonth(Month.jan, Month.aug) == 7);
|
|
assert(monthsToMonth(Month.jan, Month.sep) == 8);
|
|
assert(monthsToMonth(Month.jan, Month.oct) == 9);
|
|
assert(monthsToMonth(Month.jan, Month.nov) == 10);
|
|
assert(monthsToMonth(Month.jan, Month.dec) == 11);
|
|
|
|
assert(monthsToMonth(Month.may, Month.jan) == 8);
|
|
assert(monthsToMonth(Month.may, Month.feb) == 9);
|
|
assert(monthsToMonth(Month.may, Month.mar) == 10);
|
|
assert(monthsToMonth(Month.may, Month.apr) == 11);
|
|
assert(monthsToMonth(Month.may, Month.may) == 0);
|
|
assert(monthsToMonth(Month.may, Month.jun) == 1);
|
|
assert(monthsToMonth(Month.may, Month.jul) == 2);
|
|
assert(monthsToMonth(Month.may, Month.aug) == 3);
|
|
assert(monthsToMonth(Month.may, Month.sep) == 4);
|
|
assert(monthsToMonth(Month.may, Month.oct) == 5);
|
|
assert(monthsToMonth(Month.may, Month.nov) == 6);
|
|
assert(monthsToMonth(Month.may, Month.dec) == 7);
|
|
|
|
assert(monthsToMonth(Month.oct, Month.jan) == 3);
|
|
assert(monthsToMonth(Month.oct, Month.feb) == 4);
|
|
assert(monthsToMonth(Month.oct, Month.mar) == 5);
|
|
assert(monthsToMonth(Month.oct, Month.apr) == 6);
|
|
assert(monthsToMonth(Month.oct, Month.may) == 7);
|
|
assert(monthsToMonth(Month.oct, Month.jun) == 8);
|
|
assert(monthsToMonth(Month.oct, Month.jul) == 9);
|
|
assert(monthsToMonth(Month.oct, Month.aug) == 10);
|
|
assert(monthsToMonth(Month.oct, Month.sep) == 11);
|
|
assert(monthsToMonth(Month.oct, Month.oct) == 0);
|
|
assert(monthsToMonth(Month.oct, Month.nov) == 1);
|
|
assert(monthsToMonth(Month.oct, Month.dec) == 2);
|
|
|
|
assert(monthsToMonth(Month.dec, Month.jan) == 1);
|
|
assert(monthsToMonth(Month.dec, Month.feb) == 2);
|
|
assert(monthsToMonth(Month.dec, Month.mar) == 3);
|
|
assert(monthsToMonth(Month.dec, Month.apr) == 4);
|
|
assert(monthsToMonth(Month.dec, Month.may) == 5);
|
|
assert(monthsToMonth(Month.dec, Month.jun) == 6);
|
|
assert(monthsToMonth(Month.dec, Month.jul) == 7);
|
|
assert(monthsToMonth(Month.dec, Month.aug) == 8);
|
|
assert(monthsToMonth(Month.dec, Month.sep) == 9);
|
|
assert(monthsToMonth(Month.dec, Month.oct) == 10);
|
|
assert(monthsToMonth(Month.dec, Month.nov) == 11);
|
|
assert(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) @safe pure nothrow
|
|
{
|
|
if(currDoW == dow)
|
|
return 0;
|
|
|
|
if(currDoW < dow)
|
|
return dow - currDoW;
|
|
|
|
return (DayOfWeek.sat - currDoW) + dow + 1;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.sun) == 0);
|
|
assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.mon) == 1);
|
|
assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.tue) == 2);
|
|
assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.wed) == 3);
|
|
assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.thu) == 4);
|
|
assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.fri) == 5);
|
|
assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.sat) == 6);
|
|
|
|
assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sun) == 6);
|
|
assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.mon) == 0);
|
|
assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.tue) == 1);
|
|
assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.wed) == 2);
|
|
assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.thu) == 3);
|
|
assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.fri) == 4);
|
|
assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sat) == 5);
|
|
|
|
assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.sun) == 5);
|
|
assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.mon) == 6);
|
|
assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.tue) == 0);
|
|
assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.wed) == 1);
|
|
assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.thu) == 2);
|
|
assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.fri) == 3);
|
|
assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.sat) == 4);
|
|
|
|
assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.sun) == 4);
|
|
assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.mon) == 5);
|
|
assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.tue) == 6);
|
|
assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.wed) == 0);
|
|
assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.thu) == 1);
|
|
assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.fri) == 2);
|
|
assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.sat) == 3);
|
|
|
|
assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.sun) == 3);
|
|
assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.mon) == 4);
|
|
assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.tue) == 5);
|
|
assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.wed) == 6);
|
|
assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.thu) == 0);
|
|
assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.fri) == 1);
|
|
assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.sat) == 2);
|
|
|
|
assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.sun) == 2);
|
|
assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.mon) == 3);
|
|
assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.tue) == 4);
|
|
assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.wed) == 5);
|
|
assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.thu) == 6);
|
|
assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.fri) == 0);
|
|
assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.sat) == 1);
|
|
|
|
assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.sun) == 1);
|
|
assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.mon) == 2);
|
|
assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.tue) == 3);
|
|
assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.wed) == 4);
|
|
assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.thu) == 5);
|
|
assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.fri) == 6);
|
|
assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.sat) == 0);
|
|
}
|
|
|
|
|
|
version(StdDdoc)
|
|
{
|
|
/++
|
|
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
|
|
$(CXREF time, TickDuration).
|
|
|
|
Examples:
|
|
--------------------
|
|
{
|
|
auto mt = measureTime!((TickDuration a)
|
|
{ /+ do something when the scope is exited +/ });
|
|
// do something that needs to be timed
|
|
}
|
|
--------------------
|
|
|
|
which is functionally equivalent to
|
|
|
|
--------------------
|
|
{
|
|
auto sw = StopWatch(AutoStart.yes);
|
|
scope(exit)
|
|
{
|
|
TickDuration a = sw.peek();
|
|
/+ do something when the scope is exited +/
|
|
}
|
|
// do something that needs to be timed
|
|
}
|
|
--------------------
|
|
|
|
See_Also:
|
|
$(LREF benchmark)
|
|
+/
|
|
auto measureTime(alias func)();
|
|
}
|
|
else
|
|
{
|
|
@safe auto measureTime(alias func)()
|
|
if(isSafe!((){StopWatch sw; unaryFun!func(sw.peek());}))
|
|
{
|
|
struct Result
|
|
{
|
|
private StopWatch _sw = void;
|
|
this(AutoStart as)
|
|
{
|
|
_sw = StopWatch(as);
|
|
}
|
|
~this()
|
|
{
|
|
unaryFun!(func)(_sw.peek());
|
|
}
|
|
}
|
|
return Result(AutoStart.yes);
|
|
}
|
|
|
|
auto measureTime(alias func)()
|
|
if(!isSafe!((){StopWatch sw; unaryFun!func(sw.peek());}))
|
|
{
|
|
struct Result
|
|
{
|
|
private StopWatch _sw = void;
|
|
this(AutoStart as)
|
|
{
|
|
_sw = StopWatch(as);
|
|
}
|
|
~this()
|
|
{
|
|
unaryFun!(func)(_sw.peek());
|
|
}
|
|
}
|
|
return Result(AutoStart.yes);
|
|
}
|
|
}
|
|
|
|
// Verify Example.
|
|
unittest
|
|
{
|
|
{
|
|
auto mt = measureTime!((TickDuration a)
|
|
{ /+ do something when the scope is exited +/ });
|
|
// do something that needs to be timed
|
|
}
|
|
|
|
{
|
|
auto sw = StopWatch(AutoStart.yes);
|
|
scope(exit)
|
|
{
|
|
TickDuration a = sw.peek();
|
|
/+ do something when the scope is exited +/
|
|
}
|
|
// do something that needs to be timed
|
|
}
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
import std.math : isNaN;
|
|
|
|
@safe static void func(TickDuration td)
|
|
{
|
|
assert(!td.to!("seconds", real)().isNaN());
|
|
}
|
|
|
|
auto mt = measureTime!(func)();
|
|
|
|
/+
|
|
with (measureTime!((a){assert(a.seconds);}))
|
|
{
|
|
// doSomething();
|
|
// @@@BUG@@@ doesn't work yet.
|
|
}
|
|
+/
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.math : isNaN;
|
|
|
|
static void func(TickDuration td)
|
|
{
|
|
assert(!td.to!("seconds", real)().isNaN());
|
|
}
|
|
|
|
auto mt = measureTime!(func)();
|
|
|
|
/+
|
|
with (measureTime!((a){assert(a.seconds);}))
|
|
{
|
|
// doSomething();
|
|
// @@@BUG@@@ doesn't work yet.
|
|
}
|
|
+/
|
|
}
|
|
|
|
//Bug# 8450
|
|
unittest
|
|
{
|
|
@safe void safeFunc() {}
|
|
@trusted void trustFunc() {}
|
|
@system void sysFunc() {}
|
|
auto safeResult = measureTime!((a){safeFunc();})();
|
|
auto trustResult = measureTime!((a){trustFunc();})();
|
|
auto sysResult = measureTime!((a){sysFunc();})();
|
|
}
|
|
|
|
//==============================================================================
|
|
// Private Section.
|
|
//==============================================================================
|
|
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.
|
|
|
|
/+
|
|
Array of integers representing the last days of each month in a year.
|
|
+/
|
|
immutable int[13] lastDayNonLeap = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365];
|
|
|
|
/+
|
|
Array of integers representing the last days of each month in a leap year.
|
|
+/
|
|
immutable int[13] lastDayLeap = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366];
|
|
|
|
/+
|
|
Array of the short (three letter) names of each month.
|
|
+/
|
|
immutable string[12] _monthNames = ["Jan",
|
|
"Feb",
|
|
"Mar",
|
|
"Apr",
|
|
"May",
|
|
"Jun",
|
|
"Jul",
|
|
"Aug",
|
|
"Sep",
|
|
"Oct",
|
|
"Nov",
|
|
"Dec"];
|
|
|
|
|
|
//==============================================================================
|
|
// 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 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.
|
|
+/
|
|
long splitUnitsFromHNSecs(string units)(ref long hnsecs) @safe pure nothrow
|
|
if(validTimeUnits(units) &&
|
|
CmpTimeUnits!(units, "months") < 0)
|
|
{
|
|
immutable value = convert!("hnsecs", units)(hnsecs);
|
|
hnsecs -= convert!(units, "hnsecs")(value);
|
|
|
|
return value;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
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:
|
|
$(LREF splitUnitsFromHNSecs)
|
|
|
|
Params:
|
|
units = The units to split out.
|
|
hnsecs = The current total hnsecs.
|
|
|
|
Returns:
|
|
The split out value.
|
|
+/
|
|
long getUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow
|
|
if(validTimeUnits(units) &&
|
|
CmpTimeUnits!(units, "months") < 0)
|
|
{
|
|
return convert!("hnsecs", units)(hnsecs);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
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:
|
|
$(LREF splitUnitsFromHNSecs)
|
|
|
|
Params:
|
|
units = The units to split out.
|
|
hnsecs = The current total hnsecs.
|
|
|
|
Returns:
|
|
The remaining hnsecs.
|
|
+/
|
|
long removeUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow
|
|
if(validTimeUnits(units) &&
|
|
CmpTimeUnits!(units, "months") < 0)
|
|
{
|
|
immutable value = convert!("hnsecs", units)(hnsecs);
|
|
|
|
return hnsecs - convert!(units, "hnsecs")(value);
|
|
}
|
|
|
|
unittest
|
|
{
|
|
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) @safe 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.
|
|
assert(maxDay(1999, 1) == 31);
|
|
assert(maxDay(1999, 2) == 28);
|
|
assert(maxDay(1999, 3) == 31);
|
|
assert(maxDay(1999, 4) == 30);
|
|
assert(maxDay(1999, 5) == 31);
|
|
assert(maxDay(1999, 6) == 30);
|
|
assert(maxDay(1999, 7) == 31);
|
|
assert(maxDay(1999, 8) == 31);
|
|
assert(maxDay(1999, 9) == 30);
|
|
assert(maxDay(1999, 10) == 31);
|
|
assert(maxDay(1999, 11) == 30);
|
|
assert(maxDay(1999, 12) == 31);
|
|
|
|
assert(maxDay(2000, 1) == 31);
|
|
assert(maxDay(2000, 2) == 29);
|
|
assert(maxDay(2000, 3) == 31);
|
|
assert(maxDay(2000, 4) == 30);
|
|
assert(maxDay(2000, 5) == 31);
|
|
assert(maxDay(2000, 6) == 30);
|
|
assert(maxDay(2000, 7) == 31);
|
|
assert(maxDay(2000, 8) == 31);
|
|
assert(maxDay(2000, 9) == 30);
|
|
assert(maxDay(2000, 10) == 31);
|
|
assert(maxDay(2000, 11) == 30);
|
|
assert(maxDay(2000, 12) == 31);
|
|
|
|
//Test B.C.
|
|
assert(maxDay(-1999, 1) == 31);
|
|
assert(maxDay(-1999, 2) == 28);
|
|
assert(maxDay(-1999, 3) == 31);
|
|
assert(maxDay(-1999, 4) == 30);
|
|
assert(maxDay(-1999, 5) == 31);
|
|
assert(maxDay(-1999, 6) == 30);
|
|
assert(maxDay(-1999, 7) == 31);
|
|
assert(maxDay(-1999, 8) == 31);
|
|
assert(maxDay(-1999, 9) == 30);
|
|
assert(maxDay(-1999, 10) == 31);
|
|
assert(maxDay(-1999, 11) == 30);
|
|
assert(maxDay(-1999, 12) == 31);
|
|
|
|
assert(maxDay(-2000, 1) == 31);
|
|
assert(maxDay(-2000, 2) == 29);
|
|
assert(maxDay(-2000, 3) == 31);
|
|
assert(maxDay(-2000, 4) == 30);
|
|
assert(maxDay(-2000, 5) == 31);
|
|
assert(maxDay(-2000, 6) == 30);
|
|
assert(maxDay(-2000, 7) == 31);
|
|
assert(maxDay(-2000, 8) == 31);
|
|
assert(maxDay(-2000, 9) == 30);
|
|
assert(maxDay(-2000, 10) == 31);
|
|
assert(maxDay(-2000, 11) == 30);
|
|
assert(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) @safe 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.
|
|
assert(getDayOfWeek(SysTime(Date(1, 1, 1)).dayOfGregorianCal) == DayOfWeek.mon);
|
|
assert(getDayOfWeek(SysTime(Date(1, 1, 2)).dayOfGregorianCal) == DayOfWeek.tue);
|
|
assert(getDayOfWeek(SysTime(Date(1, 1, 3)).dayOfGregorianCal) == DayOfWeek.wed);
|
|
assert(getDayOfWeek(SysTime(Date(1, 1, 4)).dayOfGregorianCal) == DayOfWeek.thu);
|
|
assert(getDayOfWeek(SysTime(Date(1, 1, 5)).dayOfGregorianCal) == DayOfWeek.fri);
|
|
assert(getDayOfWeek(SysTime(Date(1, 1, 6)).dayOfGregorianCal) == DayOfWeek.sat);
|
|
assert(getDayOfWeek(SysTime(Date(1, 1, 7)).dayOfGregorianCal) == DayOfWeek.sun);
|
|
assert(getDayOfWeek(SysTime(Date(1, 1, 8)).dayOfGregorianCal) == DayOfWeek.mon);
|
|
assert(getDayOfWeek(SysTime(Date(1, 1, 9)).dayOfGregorianCal) == DayOfWeek.tue);
|
|
assert(getDayOfWeek(SysTime(Date(2, 1, 1)).dayOfGregorianCal) == DayOfWeek.tue);
|
|
assert(getDayOfWeek(SysTime(Date(3, 1, 1)).dayOfGregorianCal) == DayOfWeek.wed);
|
|
assert(getDayOfWeek(SysTime(Date(4, 1, 1)).dayOfGregorianCal) == DayOfWeek.thu);
|
|
assert(getDayOfWeek(SysTime(Date(5, 1, 1)).dayOfGregorianCal) == DayOfWeek.sat);
|
|
assert(getDayOfWeek(SysTime(Date(2000, 1, 1)).dayOfGregorianCal) == DayOfWeek.sat);
|
|
assert(getDayOfWeek(SysTime(Date(2010, 8, 22)).dayOfGregorianCal) == DayOfWeek.sun);
|
|
assert(getDayOfWeek(SysTime(Date(2010, 8, 23)).dayOfGregorianCal) == DayOfWeek.mon);
|
|
assert(getDayOfWeek(SysTime(Date(2010, 8, 24)).dayOfGregorianCal) == DayOfWeek.tue);
|
|
assert(getDayOfWeek(SysTime(Date(2010, 8, 25)).dayOfGregorianCal) == DayOfWeek.wed);
|
|
assert(getDayOfWeek(SysTime(Date(2010, 8, 26)).dayOfGregorianCal) == DayOfWeek.thu);
|
|
assert(getDayOfWeek(SysTime(Date(2010, 8, 27)).dayOfGregorianCal) == DayOfWeek.fri);
|
|
assert(getDayOfWeek(SysTime(Date(2010, 8, 28)).dayOfGregorianCal) == DayOfWeek.sat);
|
|
assert(getDayOfWeek(SysTime(Date(2010, 8, 29)).dayOfGregorianCal) == DayOfWeek.sun);
|
|
|
|
//Test B.C.
|
|
assert(getDayOfWeek(SysTime(Date(0, 12, 31)).dayOfGregorianCal) == DayOfWeek.sun);
|
|
assert(getDayOfWeek(SysTime(Date(0, 12, 30)).dayOfGregorianCal) == DayOfWeek.sat);
|
|
assert(getDayOfWeek(SysTime(Date(0, 12, 29)).dayOfGregorianCal) == DayOfWeek.fri);
|
|
assert(getDayOfWeek(SysTime(Date(0, 12, 28)).dayOfGregorianCal) == DayOfWeek.thu);
|
|
assert(getDayOfWeek(SysTime(Date(0, 12, 27)).dayOfGregorianCal) == DayOfWeek.wed);
|
|
assert(getDayOfWeek(SysTime(Date(0, 12, 26)).dayOfGregorianCal) == DayOfWeek.tue);
|
|
assert(getDayOfWeek(SysTime(Date(0, 12, 25)).dayOfGregorianCal) == DayOfWeek.mon);
|
|
assert(getDayOfWeek(SysTime(Date(0, 12, 24)).dayOfGregorianCal) == DayOfWeek.sun);
|
|
assert(getDayOfWeek(SysTime(Date(0, 12, 23)).dayOfGregorianCal) == DayOfWeek.sat);
|
|
}
|
|
|
|
|
|
/+
|
|
Returns the string representation of the given month.
|
|
+/
|
|
string monthToString(Month month) @safe pure
|
|
{
|
|
import std.format : format;
|
|
assert(month >= Month.jan && month <= Month.dec, format("Invalid month: %s", month));
|
|
return _monthNames[month - Month.jan];
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(monthToString(Month.jan) == "Jan");
|
|
assert(monthToString(Month.feb) == "Feb");
|
|
assert(monthToString(Month.mar) == "Mar");
|
|
assert(monthToString(Month.apr) == "Apr");
|
|
assert(monthToString(Month.may) == "May");
|
|
assert(monthToString(Month.jun) == "Jun");
|
|
assert(monthToString(Month.jul) == "Jul");
|
|
assert(monthToString(Month.aug) == "Aug");
|
|
assert(monthToString(Month.sep) == "Sep");
|
|
assert(monthToString(Month.oct) == "Oct");
|
|
assert(monthToString(Month.nov) == "Nov");
|
|
assert(monthToString(Month.dec) == "Dec");
|
|
}
|
|
|
|
|
|
/+
|
|
Returns the Month corresponding to the given string.
|
|
|
|
Params:
|
|
monthStr = The string representation of the month to get the Month for.
|
|
|
|
Throws:
|
|
$(LREF DateTimeException) if the given month is not a valid month string.
|
|
+/
|
|
Month monthFromString(string monthStr) @safe pure
|
|
{
|
|
import std.format : format;
|
|
switch(monthStr)
|
|
{
|
|
case "Jan":
|
|
return Month.jan;
|
|
case "Feb":
|
|
return Month.feb;
|
|
case "Mar":
|
|
return Month.mar;
|
|
case "Apr":
|
|
return Month.apr;
|
|
case "May":
|
|
return Month.may;
|
|
case "Jun":
|
|
return Month.jun;
|
|
case "Jul":
|
|
return Month.jul;
|
|
case "Aug":
|
|
return Month.aug;
|
|
case "Sep":
|
|
return Month.sep;
|
|
case "Oct":
|
|
return Month.oct;
|
|
case "Nov":
|
|
return Month.nov;
|
|
case "Dec":
|
|
return Month.dec;
|
|
default:
|
|
throw new DateTimeException(format("Invalid month %s", monthStr));
|
|
}
|
|
}
|
|
|
|
unittest
|
|
{
|
|
foreach(badStr; ["Ja", "Janu", "Januar", "Januarys", "JJanuary", "JANUARY",
|
|
"JAN", "january", "jaNuary", "jaN", "jaNuaRy", "jAn"])
|
|
{
|
|
scope(failure) writeln(badStr);
|
|
assertThrown!DateTimeException(monthFromString(badStr));
|
|
}
|
|
|
|
foreach(month; EnumMembers!Month)
|
|
{
|
|
scope(failure) writeln(month);
|
|
assert(monthFromString(monthToString(month)) == month);
|
|
}
|
|
}
|
|
|
|
|
|
/+
|
|
The time units which are one step smaller than the given units.
|
|
+/
|
|
template nextSmallerTimeUnits(string units)
|
|
if(validTimeUnits(units) &&
|
|
timeStrings.front != units)
|
|
{
|
|
import std.algorithm : countUntil;
|
|
enum nextSmallerTimeUnits = timeStrings[countUntil(timeStrings, units) - 1];
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(nextSmallerTimeUnits!"years" == "months");
|
|
assert(nextSmallerTimeUnits!"months" == "weeks");
|
|
assert(nextSmallerTimeUnits!"weeks" == "days");
|
|
assert(nextSmallerTimeUnits!"days" == "hours");
|
|
assert(nextSmallerTimeUnits!"hours" == "minutes");
|
|
assert(nextSmallerTimeUnits!"minutes" == "seconds");
|
|
assert(nextSmallerTimeUnits!"seconds" == "msecs");
|
|
assert(nextSmallerTimeUnits!"msecs" == "usecs");
|
|
assert(nextSmallerTimeUnits!"usecs" == "hnsecs");
|
|
static assert(!__traits(compiles, nextSmallerTimeUnits!"hnsecs"));
|
|
}
|
|
|
|
|
|
/+
|
|
The time units which are one step larger than the given units.
|
|
+/
|
|
template nextLargerTimeUnits(string units)
|
|
if(validTimeUnits(units) &&
|
|
timeStrings.back != units)
|
|
{
|
|
import std.algorithm : countUntil;
|
|
enum nextLargerTimeUnits = timeStrings[countUntil(timeStrings, units) + 1];
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(nextLargerTimeUnits!"hnsecs" == "usecs");
|
|
assert(nextLargerTimeUnits!"usecs" == "msecs");
|
|
assert(nextLargerTimeUnits!"msecs" == "seconds");
|
|
assert(nextLargerTimeUnits!"seconds" == "minutes");
|
|
assert(nextLargerTimeUnits!"minutes" == "hours");
|
|
assert(nextLargerTimeUnits!"hours" == "days");
|
|
assert(nextLargerTimeUnits!"days" == "weeks");
|
|
assert(nextLargerTimeUnits!"weeks" == "months");
|
|
assert(nextLargerTimeUnits!"months" == "years");
|
|
static assert(!__traits(compiles, nextLargerTimeUnits!"years"));
|
|
}
|
|
|
|
|
|
/+
|
|
Returns the given hnsecs as an ISO string of fractional seconds.
|
|
+/
|
|
static string fracSecsToISOString(int hnsecs) @safe pure nothrow
|
|
{
|
|
import std.format : format;
|
|
assert(hnsecs >= 0);
|
|
|
|
try
|
|
{
|
|
if(hnsecs == 0)
|
|
return "";
|
|
|
|
string isoString = format(".%07d", hnsecs);
|
|
|
|
while(isoString[$ - 1] == '0')
|
|
isoString.popBack();
|
|
|
|
return isoString;
|
|
}
|
|
catch(Exception e)
|
|
assert(0, "format() threw.");
|
|
}
|
|
|
|
unittest
|
|
{
|
|
assert(fracSecsToISOString(0) == "");
|
|
assert(fracSecsToISOString(1) == ".0000001");
|
|
assert(fracSecsToISOString(10) == ".000001");
|
|
assert(fracSecsToISOString(100) == ".00001");
|
|
assert(fracSecsToISOString(1000) == ".0001");
|
|
assert(fracSecsToISOString(10_000) == ".001");
|
|
assert(fracSecsToISOString(100_000) == ".01");
|
|
assert(fracSecsToISOString(1_000_000) == ".1");
|
|
assert(fracSecsToISOString(1_000_001) == ".1000001");
|
|
assert(fracSecsToISOString(1_001_001) == ".1001001");
|
|
assert(fracSecsToISOString(1_071_601) == ".1071601");
|
|
assert(fracSecsToISOString(1_271_641) == ".1271641");
|
|
assert(fracSecsToISOString(9_999_999) == ".9999999");
|
|
assert(fracSecsToISOString(9_999_990) == ".999999");
|
|
assert(fracSecsToISOString(9_999_900) == ".99999");
|
|
assert(fracSecsToISOString(9_999_000) == ".9999");
|
|
assert(fracSecsToISOString(9_990_000) == ".999");
|
|
assert(fracSecsToISOString(9_900_000) == ".99");
|
|
assert(fracSecsToISOString(9_000_000) == ".9");
|
|
assert(fracSecsToISOString(999) == ".0000999");
|
|
assert(fracSecsToISOString(9990) == ".000999");
|
|
assert(fracSecsToISOString(99_900) == ".00999");
|
|
assert(fracSecsToISOString(999_000) == ".0999");
|
|
}
|
|
|
|
|
|
/+
|
|
Returns a Duration corresponding to to the given ISO string of
|
|
fractional seconds.
|
|
+/
|
|
static Duration fracSecsFromISOString(S)(in S isoString) @trusted pure
|
|
if(isSomeString!S)
|
|
{
|
|
import std.ascii : isDigit;
|
|
import std.string : representation;
|
|
import std.conv : to;
|
|
import std.algorithm : all;
|
|
|
|
if(isoString.empty)
|
|
return Duration.zero;
|
|
|
|
auto str = isoString.representation;
|
|
|
|
enforce(str[0] == '.', new DateTimeException("Invalid ISO String"));
|
|
str.popFront();
|
|
|
|
enforce(!str.empty && str.length <= 7, new DateTimeException("Invalid ISO String"));
|
|
enforce(all!isDigit(str), new DateTimeException("Invalid ISO String"));
|
|
|
|
dchar[7] fullISOString = void;
|
|
foreach(i, ref dchar c; fullISOString)
|
|
{
|
|
if(i < str.length)
|
|
c = str[i];
|
|
else
|
|
c = '0';
|
|
}
|
|
|
|
return hnsecs(to!int(fullISOString[]));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
static void testFSInvalid(string isoString)
|
|
{
|
|
fracSecsFromISOString(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"));
|
|
|
|
assert(fracSecsFromISOString("") == Duration.zero);
|
|
assert(fracSecsFromISOString(".0000001") == hnsecs(1));
|
|
assert(fracSecsFromISOString(".000001") == hnsecs(10));
|
|
assert(fracSecsFromISOString(".00001") == hnsecs(100));
|
|
assert(fracSecsFromISOString(".0001") == hnsecs(1000));
|
|
assert(fracSecsFromISOString(".001") == hnsecs(10_000));
|
|
assert(fracSecsFromISOString(".01") == hnsecs(100_000));
|
|
assert(fracSecsFromISOString(".1") == hnsecs(1_000_000));
|
|
assert(fracSecsFromISOString(".1000001") == hnsecs(1_000_001));
|
|
assert(fracSecsFromISOString(".1001001") == hnsecs(1_001_001));
|
|
assert(fracSecsFromISOString(".1071601") == hnsecs(1_071_601));
|
|
assert(fracSecsFromISOString(".1271641") == hnsecs(1_271_641));
|
|
assert(fracSecsFromISOString(".9999999") == hnsecs(9_999_999));
|
|
assert(fracSecsFromISOString(".9999990") == hnsecs(9_999_990));
|
|
assert(fracSecsFromISOString(".999999") == hnsecs(9_999_990));
|
|
assert(fracSecsFromISOString(".9999900") == hnsecs(9_999_900));
|
|
assert(fracSecsFromISOString(".99999") == hnsecs(9_999_900));
|
|
assert(fracSecsFromISOString(".9999000") == hnsecs(9_999_000));
|
|
assert(fracSecsFromISOString(".9999") == hnsecs(9_999_000));
|
|
assert(fracSecsFromISOString(".9990000") == hnsecs(9_990_000));
|
|
assert(fracSecsFromISOString(".999") == hnsecs(9_990_000));
|
|
assert(fracSecsFromISOString(".9900000") == hnsecs(9_900_000));
|
|
assert(fracSecsFromISOString(".9900") == hnsecs(9_900_000));
|
|
assert(fracSecsFromISOString(".99") == hnsecs(9_900_000));
|
|
assert(fracSecsFromISOString(".9000000") == hnsecs(9_000_000));
|
|
assert(fracSecsFromISOString(".9") == hnsecs(9_000_000));
|
|
assert(fracSecsFromISOString(".0000999") == hnsecs(999));
|
|
assert(fracSecsFromISOString(".0009990") == hnsecs(9990));
|
|
assert(fracSecsFromISOString(".000999") == hnsecs(9990));
|
|
assert(fracSecsFromISOString(".0099900") == hnsecs(99_900));
|
|
assert(fracSecsFromISOString(".00999") == hnsecs(99_900));
|
|
assert(fracSecsFromISOString(".0999000") == hnsecs(999_000));
|
|
assert(fracSecsFromISOString(".0999") == hnsecs(999_000));
|
|
}
|
|
|
|
|
|
/+
|
|
Strips what RFC 5322, section 3.2.2 refers to as CFWS from the left-hand
|
|
side of the given range (it strips comments delimited by $(D '(') and
|
|
$(D ')') as well as folding whitespace).
|
|
|
|
It is assumed that the given range contains the value of a header field and
|
|
no terminating CRLF for the line (though the CRLF for folding whitespace is
|
|
of course expected and stripped) and thus that the only case of CR or LF is
|
|
in folding whitespace.
|
|
|
|
If a comment does not terminate correctly (e.g. mismatched parens) or if the
|
|
the FWS is malformed, then the range will be empty when stripCWFS is done.
|
|
However, only minimal validation of the content is done (e.g. quoted pairs
|
|
within a comment aren't validated beyond \$LPAREN or \$RPAREN, because
|
|
they're inside a comment, and thus their value doesn't matter anyway). It's
|
|
only when the content does not conform to the grammar rules for FWS and thus
|
|
literally cannot be parsed that content is considered invalid, and an empty
|
|
range is returned.
|
|
|
|
Note that _stripCFWS is eager, not lazy. It does not create a new range.
|
|
Rather, it pops off the CFWS from the range and returns it.
|
|
+/
|
|
R _stripCFWS(R)(R range)
|
|
if(isRandomAccessRange!R && hasSlicing!R && hasLength!R &&
|
|
(is(Unqual!(ElementType!R) == char) || is(Unqual!(ElementType!R) == ubyte)))
|
|
{
|
|
immutable e = range.length;
|
|
outer: for(size_t i = 0; i < e; )
|
|
{
|
|
switch(range[i])
|
|
{
|
|
case ' ': case '\t':
|
|
{
|
|
++i;
|
|
break;
|
|
}
|
|
case '\r':
|
|
{
|
|
if(i + 2 < e && range[i + 1] == '\n' && (range[i + 2] == ' ' || range[i + 2] == '\t'))
|
|
{
|
|
i += 3;
|
|
break;
|
|
}
|
|
break outer;
|
|
}
|
|
case '\n':
|
|
{
|
|
if(i + 1 < e && (range[i + 1] == ' ' || range[i + 1] == '\t'))
|
|
{
|
|
i += 2;
|
|
break;
|
|
}
|
|
break outer;
|
|
}
|
|
case '(':
|
|
{
|
|
++i;
|
|
size_t commentLevel = 1;
|
|
while(i < e)
|
|
{
|
|
if(range[i] == '(')
|
|
++commentLevel;
|
|
else if(range[i] == ')')
|
|
{
|
|
++i;
|
|
if(--commentLevel == 0)
|
|
continue outer;
|
|
continue;
|
|
}
|
|
else if(range[i] == '\\')
|
|
{
|
|
if(++i == e)
|
|
break outer;
|
|
}
|
|
++i;
|
|
}
|
|
break outer;
|
|
}
|
|
default: return range[i .. e];
|
|
}
|
|
}
|
|
return range[e .. e];
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.algorithm;
|
|
import std.string;
|
|
import std.typecons;
|
|
import std.meta;
|
|
|
|
foreach(cr; TypeTuple!(function(string a){return cast(ubyte[])a;},
|
|
function(string a){return map!(b => cast(char)b)(a.representation);}))
|
|
(){ // avoid slow optimizations for large functions @@@BUG@@@ 2396
|
|
scope(failure) writeln(typeof(cr).stringof);
|
|
|
|
assert(_stripCFWS(cr("")).empty);
|
|
assert(_stripCFWS(cr("\r")).empty);
|
|
assert(_stripCFWS(cr("\r\n")).empty);
|
|
assert(_stripCFWS(cr("\r\n ")).empty);
|
|
assert(_stripCFWS(cr(" \t\r\n")).empty);
|
|
assert(equal(_stripCFWS(cr(" \t\r\n hello")), cr("hello")));
|
|
assert(_stripCFWS(cr(" \t\r\nhello")).empty);
|
|
assert(_stripCFWS(cr(" \t\r\n\v")).empty);
|
|
assert(equal(_stripCFWS(cr("\v \t\r\n\v")), cr("\v \t\r\n\v")));
|
|
assert(_stripCFWS(cr("()")).empty);
|
|
assert(_stripCFWS(cr("(hello world)")).empty);
|
|
assert(_stripCFWS(cr("(hello world)(hello world)")).empty);
|
|
assert(_stripCFWS(cr("(hello world\r\n foo\r where's\nwaldo)")).empty);
|
|
assert(_stripCFWS(cr(" \t (hello \tworld\r\n foo\r where's\nwaldo)\t\t ")).empty);
|
|
assert(_stripCFWS(cr(" ")).empty);
|
|
assert(_stripCFWS(cr("\t\t\t")).empty);
|
|
assert(_stripCFWS(cr("\t \r\n\r \n")).empty);
|
|
assert(_stripCFWS(cr("(hello world) (can't find waldo) (he's lost)")).empty);
|
|
assert(_stripCFWS(cr("(hello\\) world) (can't \\(find waldo) (he's \\(\\)lost)")).empty);
|
|
assert(_stripCFWS(cr("(((((")).empty);
|
|
assert(_stripCFWS(cr("(((()))")).empty);
|
|
assert(_stripCFWS(cr("(((())))")).empty);
|
|
assert(equal(_stripCFWS(cr("(((()))))")), cr(")")));
|
|
assert(equal(_stripCFWS(cr(")))))")), cr(")))))")));
|
|
assert(equal(_stripCFWS(cr("()))))")), cr("))))")));
|
|
assert(equal(_stripCFWS(cr(" hello hello ")), cr("hello hello ")));
|
|
assert(equal(_stripCFWS(cr("\thello (world)")), cr("hello (world)")));
|
|
assert(equal(_stripCFWS(cr(" \r\n \\((\\)) foo")), cr("\\((\\)) foo")));
|
|
assert(equal(_stripCFWS(cr(" \r\n (\\((\\))) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" \r\n (\\(())) foo")), cr(") foo")));
|
|
assert(_stripCFWS(cr(" \r\n (((\\))) foo")).empty);
|
|
|
|
assert(_stripCFWS(cr("(hello)(hello)")).empty);
|
|
assert(_stripCFWS(cr(" \r\n (hello)\r\n (hello)")).empty);
|
|
assert(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n ")).empty);
|
|
assert(_stripCFWS(cr("\t\t\t\t(hello)\t\t\t\t(hello)\t\t\t\t")).empty);
|
|
assert(equal(_stripCFWS(cr(" \r\n (hello)\r\n (hello) \r\n hello")), cr("hello")));
|
|
assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n hello")), cr("hello")));
|
|
assert(equal(_stripCFWS(cr("\t\r\n\t(hello)\r\n\t(hello)\t\r\n hello")), cr("hello")));
|
|
assert(equal(_stripCFWS(cr("\t\r\n\t(hello)\t\r\n\t(hello)\t\r\n hello")), cr("hello")));
|
|
assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n \r\n (hello) \r\n hello")), cr("hello")));
|
|
assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n \r\n hello")), cr("hello")));
|
|
assert(equal(_stripCFWS(cr(" \r\n \r\n (hello)\t\r\n (hello) \r\n hello")), cr("hello")));
|
|
assert(equal(_stripCFWS(cr(" \r\n\t\r\n\t(hello)\t\r\n (hello) \r\n hello")), cr("hello")));
|
|
|
|
assert(equal(_stripCFWS(cr(" (\r\n ( \r\n ) \r\n ) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n ) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" (\t\r\n ( \r\n ) \r\n ) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" (\r\n\t( \r\n ) \r\n ) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" ( \r\n (\t\r\n ) \r\n ) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" ( \r\n (\r\n ) \r\n ) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" ( \r\n (\r\n\t) \r\n ) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n) \r\n ) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n )\t\r\n ) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n )\r\n ) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n\t) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n ) \r\n foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n )\t\r\n foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n )\r\n foo")), cr("foo")));
|
|
|
|
assert(equal(_stripCFWS(cr(" ( \r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" ( \r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" (\t\r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" (\r\n \r\n\t( \r\n \r\n ) \r\n ) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" (\r\n \r\n( \r\n \r\n ) \r\n ) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n\t) \r\n ) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n )\t\r\n ) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n )\r\n ) foo")), cr("foo")));
|
|
|
|
assert(equal(_stripCFWS(cr(" ( \r\n bar \r\n ( \r\n bar \r\n ) \r\n ) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" ( \r\n () \r\n ( \r\n () \r\n ) \r\n ) foo")), cr("foo")));
|
|
assert(equal(_stripCFWS(cr(" ( \r\n \\\\ \r\n ( \r\n \\\\ \r\n ) \r\n ) foo")), cr("foo")));
|
|
|
|
assert(_stripCFWS(cr("(hello)(hello)")).empty);
|
|
assert(_stripCFWS(cr(" \n (hello)\n (hello) \n ")).empty);
|
|
assert(_stripCFWS(cr(" \n (hello) \n (hello) \n ")).empty);
|
|
assert(equal(_stripCFWS(cr(" \n (hello)\n (hello) \n hello")), cr("hello")));
|
|
assert(equal(_stripCFWS(cr(" \n (hello) \n (hello) \n hello")), cr("hello")));
|
|
assert(equal(_stripCFWS(cr("\t\n\t(hello)\n\t(hello)\t\n hello")), cr("hello")));
|
|
assert(equal(_stripCFWS(cr("\t\n\t(hello)\t\n\t(hello)\t\n hello")), cr("hello")));
|
|
assert(equal(_stripCFWS(cr(" \n (hello) \n \n (hello) \n hello")), cr("hello")));
|
|
assert(equal(_stripCFWS(cr(" \n (hello) \n (hello) \n \n hello")), cr("hello")));
|
|
assert(equal(_stripCFWS(cr(" \n \n (hello)\t\n (hello) \n hello")), cr("hello")));
|
|
assert(equal(_stripCFWS(cr(" \n\t\n\t(hello)\t\n (hello) \n hello")), cr("hello")));
|
|
}();
|
|
}
|
|
|
|
// This is so that we don't have to worry about std.conv.to throwing. It also
|
|
// doesn't have to worry about quite as many cases as std.conv.to, since it
|
|
// doesn't have to worry about a sign on the value or about whether it fits.
|
|
T _convDigits(T, R)(R str)
|
|
if(isIntegral!T && isSigned!T) // The constraints on R were already covered by parseRFC822DateTime.
|
|
{
|
|
import std.ascii : isDigit;
|
|
|
|
assert(!str.empty);
|
|
T num = 0;
|
|
foreach(i; 0 .. str.length)
|
|
{
|
|
if(i != 0)
|
|
num *= 10;
|
|
if(!std.ascii.isDigit(str[i]))
|
|
return -1;
|
|
num += str[i] - '0';
|
|
}
|
|
return num;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
import std.conv : to;
|
|
import std.range;
|
|
foreach(i; chain(iota(0, 101), [250, 999, 1000, 1001, 2345, 9999]))
|
|
{
|
|
scope(failure) writeln(i);
|
|
assert(_convDigits!int(to!string(i)) == i);
|
|
}
|
|
foreach(str; ["-42", "+42", "1a", "1 ", " ", " 42 "])
|
|
{
|
|
scope(failure) writeln(str);
|
|
assert(_convDigits!int(str) == -1);
|
|
}
|
|
}
|
|
|
|
|
|
/+
|
|
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(typeof(T.min) == Unqual!T);
|
|
}
|
|
|
|
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(typeof(T.max) == Unqual!T);
|
|
}
|
|
|
|
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:
|
|
|
|
$(BOOKTABLE,
|
|
$(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:
|
|
|
|
$(BOOKTABLE,
|
|
$(TR $(TD TimePoint opOpAssign"+"(duration)))
|
|
$(TR $(TD TimePoint opOpAssign"-"(duration)))
|
|
)
|
|
+/
|
|
template hasOverloadedOpAssignWithDuration(T)
|
|
{
|
|
enum hasOverloadedOpAssignWithDuration = is(typeof(
|
|
{
|
|
auto d = dur!"days"(5);
|
|
auto td = TickDuration.from!"hnsecs"(5);
|
|
alias U = Unqual!T;
|
|
static assert(is(typeof(U.init += d) == U));
|
|
static assert(is(typeof(U.init -= d) == U));
|
|
static assert(is(typeof(U.init += td) == U));
|
|
static assert(is(typeof(U.init -= td) == U));
|
|
}));
|
|
}
|
|
|
|
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:
|
|
|
|
$(BOOKTABLE,
|
|
$(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));
|
|
}
|
|
|
|
|
|
version(unittest)
|
|
{
|
|
import std.typecons;
|
|
import std.algorithm;
|
|
//Variables to help in testing.
|
|
Duration currLocalDiffFromUTC;
|
|
immutable (TimeZone)[] testTZs;
|
|
|
|
//All of these helper arrays are sorted in ascending order.
|
|
auto testYearsBC = [-1999, -1200, -600, -4, -1, 0];
|
|
auto testYearsAD = [1, 4, 1000, 1999, 2000, 2012];
|
|
|
|
//I'd use a Tuple, but I get forward reference errors if I try.
|
|
struct MonthDay
|
|
{
|
|
Month month;
|
|
short day;
|
|
|
|
this(int m, short d)
|
|
{
|
|
month = cast(Month)m;
|
|
day = d;
|
|
}
|
|
}
|
|
|
|
MonthDay[] testMonthDays = [MonthDay(1, 1),
|
|
MonthDay(1, 2),
|
|
MonthDay(3, 17),
|
|
MonthDay(7, 4),
|
|
MonthDay(10, 27),
|
|
MonthDay(12, 30),
|
|
MonthDay(12, 31)];
|
|
|
|
auto testDays = [1, 2, 9, 10, 16, 20, 25, 28, 29, 30, 31];
|
|
|
|
auto testTODs = [TimeOfDay(0, 0, 0),
|
|
TimeOfDay(0, 0, 1),
|
|
TimeOfDay(0, 1, 0),
|
|
TimeOfDay(1, 0, 0),
|
|
TimeOfDay(13, 13, 13),
|
|
TimeOfDay(23, 59, 59)];
|
|
|
|
auto testHours = [0, 1, 12, 22, 23];
|
|
auto testMinSecs = [0, 1, 30, 58, 59];
|
|
|
|
//Throwing exceptions is incredibly expensive, so we want to use a smaller
|
|
//set of values for tests using assertThrown.
|
|
auto testTODsThrown = [TimeOfDay(0, 0, 0),
|
|
TimeOfDay(13, 13, 13),
|
|
TimeOfDay(23, 59, 59)];
|
|
|
|
Date[] testDatesBC;
|
|
Date[] testDatesAD;
|
|
|
|
DateTime[] testDateTimesBC;
|
|
DateTime[] testDateTimesAD;
|
|
|
|
Duration[] testFracSecs;
|
|
|
|
SysTime[] testSysTimesBC;
|
|
SysTime[] testSysTimesAD;
|
|
|
|
//I'd use a Tuple, but I get forward reference errors if I try.
|
|
struct GregDay { int day; Date date; }
|
|
auto testGregDaysBC = [GregDay(-1_373_427, Date(-3760, 9, 7)), //Start of the Hebrew Calendar
|
|
GregDay(-735_233, Date(-2012, 1, 1)),
|
|
GregDay(-735_202, Date(-2012, 2, 1)),
|
|
GregDay(-735_175, Date(-2012, 2, 28)),
|
|
GregDay(-735_174, Date(-2012, 2, 29)),
|
|
GregDay(-735_173, Date(-2012, 3, 1)),
|
|
GregDay(-734_502, Date(-2010, 1, 1)),
|
|
GregDay(-734_472, Date(-2010, 1, 31)),
|
|
GregDay(-734_471, Date(-2010, 2, 1)),
|
|
GregDay(-734_444, Date(-2010, 2, 28)),
|
|
GregDay(-734_443, Date(-2010, 3, 1)),
|
|
GregDay(-734_413, Date(-2010, 3, 31)),
|
|
GregDay(-734_412, Date(-2010, 4, 1)),
|
|
GregDay(-734_383, Date(-2010, 4, 30)),
|
|
GregDay(-734_382, Date(-2010, 5, 1)),
|
|
GregDay(-734_352, Date(-2010, 5, 31)),
|
|
GregDay(-734_351, Date(-2010, 6, 1)),
|
|
GregDay(-734_322, Date(-2010, 6, 30)),
|
|
GregDay(-734_321, Date(-2010, 7, 1)),
|
|
GregDay(-734_291, Date(-2010, 7, 31)),
|
|
GregDay(-734_290, Date(-2010, 8, 1)),
|
|
GregDay(-734_260, Date(-2010, 8, 31)),
|
|
GregDay(-734_259, Date(-2010, 9, 1)),
|
|
GregDay(-734_230, Date(-2010, 9, 30)),
|
|
GregDay(-734_229, Date(-2010, 10, 1)),
|
|
GregDay(-734_199, Date(-2010, 10, 31)),
|
|
GregDay(-734_198, Date(-2010, 11, 1)),
|
|
GregDay(-734_169, Date(-2010, 11, 30)),
|
|
GregDay(-734_168, Date(-2010, 12, 1)),
|
|
GregDay(-734_139, Date(-2010, 12, 30)),
|
|
GregDay(-734_138, Date(-2010, 12, 31)),
|
|
GregDay(-731_215, Date(-2001, 1, 1)),
|
|
GregDay(-730_850, Date(-2000, 1, 1)),
|
|
GregDay(-730_849, Date(-2000, 1, 2)),
|
|
GregDay(-730_486, Date(-2000, 12, 30)),
|
|
GregDay(-730_485, Date(-2000, 12, 31)),
|
|
GregDay(-730_484, Date(-1999, 1, 1)),
|
|
GregDay(-694_690, Date(-1901, 1, 1)),
|
|
GregDay(-694_325, Date(-1900, 1, 1)),
|
|
GregDay(-585_118, Date(-1601, 1, 1)),
|
|
GregDay(-584_753, Date(-1600, 1, 1)),
|
|
GregDay(-584_388, Date(-1600, 12, 31)),
|
|
GregDay(-584_387, Date(-1599, 1, 1)),
|
|
GregDay(-365_972, Date(-1001, 1, 1)),
|
|
GregDay(-365_607, Date(-1000, 1, 1)),
|
|
GregDay(-183_351, Date(-501, 1, 1)),
|
|
GregDay(-182_986, Date(-500, 1, 1)),
|
|
GregDay(-182_621, Date(-499, 1, 1)),
|
|
GregDay(-146_827, Date(-401, 1, 1)),
|
|
GregDay(-146_462, Date(-400, 1, 1)),
|
|
GregDay(-146_097, Date(-400, 12, 31)),
|
|
GregDay(-110_302, Date(-301, 1, 1)),
|
|
GregDay(-109_937, Date(-300, 1, 1)),
|
|
GregDay(-73_778, Date(-201, 1, 1)),
|
|
GregDay(-73_413, Date(-200, 1, 1)),
|
|
GregDay(-38_715, Date(-105, 1, 1)),
|
|
GregDay(-37_254, Date(-101, 1, 1)),
|
|
GregDay(-36_889, Date(-100, 1, 1)),
|
|
GregDay(-36_524, Date(-99, 1, 1)),
|
|
GregDay(-36_160, Date(-99, 12, 31)),
|
|
GregDay(-35_794, Date(-97, 1, 1)),
|
|
GregDay(-18_627, Date(-50, 1, 1)),
|
|
GregDay(-18_262, Date(-49, 1, 1)),
|
|
GregDay(-3652, Date(-9, 1, 1)),
|
|
GregDay(-2191, Date(-5, 1, 1)),
|
|
GregDay(-1827, Date(-5, 12, 31)),
|
|
GregDay(-1826, Date(-4, 1, 1)),
|
|
GregDay(-1825, Date(-4, 1, 2)),
|
|
GregDay(-1462, Date(-4, 12, 30)),
|
|
GregDay(-1461, Date(-4, 12, 31)),
|
|
GregDay(-1460, Date(-3, 1, 1)),
|
|
GregDay(-1096, Date(-3, 12, 31)),
|
|
GregDay(-1095, Date(-2, 1, 1)),
|
|
GregDay(-731, Date(-2, 12, 31)),
|
|
GregDay(-730, Date(-1, 1, 1)),
|
|
GregDay(-367, Date(-1, 12, 30)),
|
|
GregDay(-366, Date(-1, 12, 31)),
|
|
GregDay(-365, Date(0, 1, 1)),
|
|
GregDay(-31, Date(0, 11, 30)),
|
|
GregDay(-30, Date(0, 12, 1)),
|
|
GregDay(-1, Date(0, 12, 30)),
|
|
GregDay(0, Date(0, 12, 31))];
|
|
|
|
auto testGregDaysAD = [GregDay(1, Date(1, 1, 1)),
|
|
GregDay(2, Date(1, 1, 2)),
|
|
GregDay(32, Date(1, 2, 1)),
|
|
GregDay(365, Date(1, 12, 31)),
|
|
GregDay(366, Date(2, 1, 1)),
|
|
GregDay(731, Date(3, 1, 1)),
|
|
GregDay(1096, Date(4, 1, 1)),
|
|
GregDay(1097, Date(4, 1, 2)),
|
|
GregDay(1460, Date(4, 12, 30)),
|
|
GregDay(1461, Date(4, 12, 31)),
|
|
GregDay(1462, Date(5, 1, 1)),
|
|
GregDay(17_898, Date(50, 1, 1)),
|
|
GregDay(35_065, Date(97, 1, 1)),
|
|
GregDay(36_160, Date(100, 1, 1)),
|
|
GregDay(36_525, Date(101, 1, 1)),
|
|
GregDay(37_986, Date(105, 1, 1)),
|
|
GregDay(72_684, Date(200, 1, 1)),
|
|
GregDay(73_049, Date(201, 1, 1)),
|
|
GregDay(109_208, Date(300, 1, 1)),
|
|
GregDay(109_573, Date(301, 1, 1)),
|
|
GregDay(145_732, Date(400, 1, 1)),
|
|
GregDay(146_098, Date(401, 1, 1)),
|
|
GregDay(182_257, Date(500, 1, 1)),
|
|
GregDay(182_622, Date(501, 1, 1)),
|
|
GregDay(364_878, Date(1000, 1, 1)),
|
|
GregDay(365_243, Date(1001, 1, 1)),
|
|
GregDay(584_023, Date(1600, 1, 1)),
|
|
GregDay(584_389, Date(1601, 1, 1)),
|
|
GregDay(693_596, Date(1900, 1, 1)),
|
|
GregDay(693_961, Date(1901, 1, 1)),
|
|
GregDay(729_755, Date(1999, 1, 1)),
|
|
GregDay(730_120, Date(2000, 1, 1)),
|
|
GregDay(730_121, Date(2000, 1, 2)),
|
|
GregDay(730_484, Date(2000, 12, 30)),
|
|
GregDay(730_485, Date(2000, 12, 31)),
|
|
GregDay(730_486, Date(2001, 1, 1)),
|
|
GregDay(733_773, Date(2010, 1, 1)),
|
|
GregDay(733_774, Date(2010, 1, 2)),
|
|
GregDay(733_803, Date(2010, 1, 31)),
|
|
GregDay(733_804, Date(2010, 2, 1)),
|
|
GregDay(733_831, Date(2010, 2, 28)),
|
|
GregDay(733_832, Date(2010, 3, 1)),
|
|
GregDay(733_862, Date(2010, 3, 31)),
|
|
GregDay(733_863, Date(2010, 4, 1)),
|
|
GregDay(733_892, Date(2010, 4, 30)),
|
|
GregDay(733_893, Date(2010, 5, 1)),
|
|
GregDay(733_923, Date(2010, 5, 31)),
|
|
GregDay(733_924, Date(2010, 6, 1)),
|
|
GregDay(733_953, Date(2010, 6, 30)),
|
|
GregDay(733_954, Date(2010, 7, 1)),
|
|
GregDay(733_984, Date(2010, 7, 31)),
|
|
GregDay(733_985, Date(2010, 8, 1)),
|
|
GregDay(734_015, Date(2010, 8, 31)),
|
|
GregDay(734_016, Date(2010, 9, 1)),
|
|
GregDay(734_045, Date(2010, 9, 30)),
|
|
GregDay(734_046, Date(2010, 10, 1)),
|
|
GregDay(734_076, Date(2010, 10, 31)),
|
|
GregDay(734_077, Date(2010, 11, 1)),
|
|
GregDay(734_106, Date(2010, 11, 30)),
|
|
GregDay(734_107, Date(2010, 12, 1)),
|
|
GregDay(734_136, Date(2010, 12, 30)),
|
|
GregDay(734_137, Date(2010, 12, 31)),
|
|
GregDay(734_503, Date(2012, 1, 1)),
|
|
GregDay(734_534, Date(2012, 2, 1)),
|
|
GregDay(734_561, Date(2012, 2, 28)),
|
|
GregDay(734_562, Date(2012, 2, 29)),
|
|
GregDay(734_563, Date(2012, 3, 1)),
|
|
GregDay(734_858, Date(2012, 12, 21))];
|
|
|
|
//I'd use a Tuple, but I get forward reference errors if I try.
|
|
struct DayOfYear { int day; MonthDay md; }
|
|
auto testDaysOfYear = [DayOfYear(1, MonthDay(1, 1)),
|
|
DayOfYear(2, MonthDay(1, 2)),
|
|
DayOfYear(3, MonthDay(1, 3)),
|
|
DayOfYear(31, MonthDay(1, 31)),
|
|
DayOfYear(32, MonthDay(2, 1)),
|
|
DayOfYear(59, MonthDay(2, 28)),
|
|
DayOfYear(60, MonthDay(3, 1)),
|
|
DayOfYear(90, MonthDay(3, 31)),
|
|
DayOfYear(91, MonthDay(4, 1)),
|
|
DayOfYear(120, MonthDay(4, 30)),
|
|
DayOfYear(121, MonthDay(5, 1)),
|
|
DayOfYear(151, MonthDay(5, 31)),
|
|
DayOfYear(152, MonthDay(6, 1)),
|
|
DayOfYear(181, MonthDay(6, 30)),
|
|
DayOfYear(182, MonthDay(7, 1)),
|
|
DayOfYear(212, MonthDay(7, 31)),
|
|
DayOfYear(213, MonthDay(8, 1)),
|
|
DayOfYear(243, MonthDay(8, 31)),
|
|
DayOfYear(244, MonthDay(9, 1)),
|
|
DayOfYear(273, MonthDay(9, 30)),
|
|
DayOfYear(274, MonthDay(10, 1)),
|
|
DayOfYear(304, MonthDay(10, 31)),
|
|
DayOfYear(305, MonthDay(11, 1)),
|
|
DayOfYear(334, MonthDay(11, 30)),
|
|
DayOfYear(335, MonthDay(12, 1)),
|
|
DayOfYear(363, MonthDay(12, 29)),
|
|
DayOfYear(364, MonthDay(12, 30)),
|
|
DayOfYear(365, MonthDay(12, 31))];
|
|
|
|
auto testDaysOfLeapYear = [DayOfYear(1, MonthDay(1, 1)),
|
|
DayOfYear(2, MonthDay(1, 2)),
|
|
DayOfYear(3, MonthDay(1, 3)),
|
|
DayOfYear(31, MonthDay(1, 31)),
|
|
DayOfYear(32, MonthDay(2, 1)),
|
|
DayOfYear(59, MonthDay(2, 28)),
|
|
DayOfYear(60, MonthDay(2, 29)),
|
|
DayOfYear(61, MonthDay(3, 1)),
|
|
DayOfYear(91, MonthDay(3, 31)),
|
|
DayOfYear(92, MonthDay(4, 1)),
|
|
DayOfYear(121, MonthDay(4, 30)),
|
|
DayOfYear(122, MonthDay(5, 1)),
|
|
DayOfYear(152, MonthDay(5, 31)),
|
|
DayOfYear(153, MonthDay(6, 1)),
|
|
DayOfYear(182, MonthDay(6, 30)),
|
|
DayOfYear(183, MonthDay(7, 1)),
|
|
DayOfYear(213, MonthDay(7, 31)),
|
|
DayOfYear(214, MonthDay(8, 1)),
|
|
DayOfYear(244, MonthDay(8, 31)),
|
|
DayOfYear(245, MonthDay(9, 1)),
|
|
DayOfYear(274, MonthDay(9, 30)),
|
|
DayOfYear(275, MonthDay(10, 1)),
|
|
DayOfYear(305, MonthDay(10, 31)),
|
|
DayOfYear(306, MonthDay(11, 1)),
|
|
DayOfYear(335, MonthDay(11, 30)),
|
|
DayOfYear(336, MonthDay(12, 1)),
|
|
DayOfYear(364, MonthDay(12, 29)),
|
|
DayOfYear(365, MonthDay(12, 30)),
|
|
DayOfYear(366, MonthDay(12, 31))];
|
|
|
|
void initializeTests()
|
|
{
|
|
immutable lt = LocalTime().utcToTZ(0);
|
|
currLocalDiffFromUTC = dur!"hnsecs"(lt);
|
|
|
|
immutable otherTZ = lt < 0 ? TimeZone.getTimeZone("Australia/Sydney")
|
|
: TimeZone.getTimeZone("America/Denver");
|
|
immutable ot = otherTZ.utcToTZ(0);
|
|
|
|
auto diffs = [0L, lt, ot];
|
|
auto diffAA = [0L : Rebindable!(immutable TimeZone)(UTC())];
|
|
diffAA[lt] = Rebindable!(immutable TimeZone)(LocalTime());
|
|
diffAA[ot] = Rebindable!(immutable TimeZone)(otherTZ);
|
|
|
|
sort(diffs);
|
|
testTZs = [diffAA[diffs[0]], diffAA[diffs[1]], diffAA[diffs[2]]];
|
|
|
|
testFracSecs = [Duration.zero, hnsecs(1), hnsecs(5007), hnsecs(9999999)];
|
|
|
|
foreach(year; testYearsBC)
|
|
{
|
|
foreach(md; testMonthDays)
|
|
testDatesBC ~= Date(year, md.month, md.day);
|
|
}
|
|
|
|
foreach(year; testYearsAD)
|
|
{
|
|
foreach(md; testMonthDays)
|
|
testDatesAD ~= Date(year, md.month, md.day);
|
|
}
|
|
|
|
foreach(dt; testDatesBC)
|
|
{
|
|
foreach(tod; testTODs)
|
|
testDateTimesBC ~= DateTime(dt, tod);
|
|
}
|
|
|
|
foreach(dt; testDatesAD)
|
|
{
|
|
foreach(tod; testTODs)
|
|
testDateTimesAD ~= DateTime(dt, tod);
|
|
}
|
|
|
|
foreach(dt; testDateTimesBC)
|
|
{
|
|
foreach(tz; testTZs)
|
|
{
|
|
foreach(fs; testFracSecs)
|
|
testSysTimesBC ~= SysTime(dt, fs, tz);
|
|
}
|
|
}
|
|
|
|
foreach(dt; testDateTimesAD)
|
|
{
|
|
foreach(tz; testTZs)
|
|
{
|
|
foreach(fs; testFracSecs)
|
|
testSysTimesAD ~= SysTime(dt, fs, tz);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
unittest
|
|
{
|
|
/* Issue 6642 */
|
|
static assert(!hasUnsharedAliasing!Date);
|
|
static assert(!hasUnsharedAliasing!TimeOfDay);
|
|
static assert(!hasUnsharedAliasing!DateTime);
|
|
static assert(!hasUnsharedAliasing!SysTime);
|
|
}
|
|
|
|
|
|
|
|
// This script is for regenerating tzDatabaseNameToWindowsTZName and
|
|
// windowsTZNameToTZDatabaseName from
|
|
// http://unicode.org/cldr/data/common/supplemental/windowsZones.xml
|
|
|
|
/+
|
|
#!/bin/rdmd
|
|
|
|
import std.algorithm;
|
|
import std.array;
|
|
import std.conv;
|
|
import std.datetime;
|
|
import std.exception;
|
|
import std.path;
|
|
import std.stdio;
|
|
import std.string;
|
|
|
|
int main(string[] args)
|
|
{
|
|
if(args.length != 4 || args[1].baseName != "windowsZones.xml")
|
|
{
|
|
stderr.writeln("genTZs.d windowsZones.xml <nix2WinFile> <win2NixFile>");
|
|
return -1;
|
|
}
|
|
|
|
string[][string] win2Nix;
|
|
string[][string] nix2Win;
|
|
immutable f1 = `<mapZone other="`;
|
|
immutable f2 = `type="`;
|
|
|
|
auto file = File(args[1]);
|
|
foreach(line; file.byLine())
|
|
{
|
|
line = line.find(f1);
|
|
if(line.empty)
|
|
continue;
|
|
line = line[f1.length .. $];
|
|
auto next = line.find('"');
|
|
auto win = to!string(line[0 .. $ - next.length]);
|
|
line = next.find(f2);
|
|
line = line[f2.length .. $];
|
|
next = line.find('"');
|
|
auto nixes = to!string(line[0 .. $ - next.length]).split();
|
|
|
|
if(auto l = win in win2Nix)
|
|
*l ~= nixes;
|
|
else
|
|
win2Nix[win] = nixes;
|
|
foreach(nix; nixes)
|
|
{
|
|
if(auto w = nix in nix2Win)
|
|
*w ~= win;
|
|
else
|
|
nix2Win[nix] = [win];
|
|
}
|
|
}
|
|
|
|
foreach(nix; nix2Win.byKey())
|
|
{
|
|
auto wins = nix2Win[nix];
|
|
nix2Win[nix] = wins.sort().uniq().array();
|
|
}
|
|
|
|
foreach(win; win2Nix.byKey())
|
|
{
|
|
auto nixes = win2Nix[win];
|
|
win2Nix[win] = nixes.sort().uniq().array();
|
|
}
|
|
|
|
// AFAIK, there should be no cases of a TZ Database time zone converting to
|
|
// multiple windows time zones.
|
|
foreach(nix, wins; nix2Win)
|
|
enforce(wins.length == 1, format("%s -> %s", nix, wins));
|
|
|
|
// We'll try to eliminate multiples by favoring a conversion if it's already
|
|
// in Phobos, but if it's new, then the correct one will have to be chosen
|
|
// manually from the results.
|
|
string[] haveMultiple;
|
|
foreach(win, nixes; win2Nix)
|
|
{
|
|
if(nixes.length > 1)
|
|
haveMultiple ~= win;
|
|
}
|
|
bool[string] haveConflicts;
|
|
foreach(win; haveMultiple)
|
|
{
|
|
if(auto curr = windowsTZNameToTZDatabaseName(win))
|
|
{
|
|
if(auto other = curr in nix2Win)
|
|
{
|
|
if((*other)[0] == win)
|
|
{
|
|
win2Nix[win] = [curr];
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
haveConflicts[win] = true;
|
|
writefln("Warning: %s -> %s", win, win2Nix[win]);
|
|
}
|
|
|
|
|
|
string[] nix2WinLines = [
|
|
`string tzDatabaseNameToWindowsTZName(string tzName) @safe pure nothrow @nogc`,
|
|
`{`,
|
|
` switch(tzName)`,
|
|
` {`];
|
|
|
|
foreach(nix; nix2Win.keys.sort())
|
|
nix2WinLines ~= format(` case "%s": return "%s";`, nix, nix2Win[nix][0]);
|
|
|
|
nix2WinLines ~= [
|
|
` default: return null;`,
|
|
` }`,
|
|
`}`];
|
|
|
|
|
|
string[] win2NixLines = [
|
|
`string windowsTZNameToTZDatabaseName(string tzName) @safe pure nothrow @nogc`,
|
|
`{`,
|
|
` switch(tzName)`,
|
|
` {`];
|
|
foreach(win; win2Nix.keys.sort())
|
|
{
|
|
immutable hasMultiple = cast(bool)(win in haveConflicts);
|
|
foreach(nix; win2Nix[win])
|
|
win2NixLines ~= format(` case "%s": return "%s";%s`, win, nix, hasMultiple ? " FIXME" : "");
|
|
}
|
|
|
|
win2NixLines ~= [
|
|
` default: return null;`,
|
|
` }`,
|
|
`}`];
|
|
|
|
|
|
auto nix2WinFile = args[2];
|
|
std.file.write(nix2WinFile, nix2WinLines.join("\n"));
|
|
|
|
auto win2NixFile = args[3];
|
|
std.file.write(win2NixFile, win2NixLines.join("\n"));
|
|
|
|
return 0;
|
|
}
|
|
+/
|