mirror of
https://github.com/dlang/phobos.git
synced 2025-04-26 21:22:20 +03:00

* Fix UndocumentedDeclarationCheck linting issue * Fix IfConstraintsIndentCheck linting issue * Address feedback * Fix publictests CI * Fix old (libdparse) D-Scanner linting warn
10905 lines
422 KiB
D
10905 lines
422 KiB
D
// Written in the D programming language
|
|
/++
|
|
|
|
$(SCRIPT inhibitQuickIndex = 1;)
|
|
$(DIVC quickindex,
|
|
$(BOOKTABLE,
|
|
$(TR $(TH Category) $(TH Functions))
|
|
$(TR $(TD Main date types) $(TD
|
|
$(LREF Date)
|
|
$(LREF DateTime)
|
|
))
|
|
$(TR $(TD Other date types) $(TD
|
|
$(LREF Month)
|
|
$(LREF DayOfWeek)
|
|
$(LREF TimeOfDay)
|
|
))
|
|
$(TR $(TD Date checking) $(TD
|
|
$(LREF valid)
|
|
$(LREF validTimeUnits)
|
|
$(LREF yearIsLeapYear)
|
|
$(LREF isTimePoint)
|
|
$(LREF enforceValid)
|
|
))
|
|
$(TR $(TD Date conversion) $(TD
|
|
$(LREF daysToDayOfWeek)
|
|
$(LREF monthsToMonth)
|
|
))
|
|
$(TR $(TD Time units) $(TD
|
|
$(LREF cmpTimeUnits)
|
|
$(LREF timeStrings)
|
|
))
|
|
$(TR $(TD Other) $(TD
|
|
$(LREF AllowDayOverflow)
|
|
$(LREF DateTimeException)
|
|
))
|
|
))
|
|
|
|
License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
|
|
Authors: $(HTTP jmdavisprog.com, Jonathan M Davis)
|
|
Source: $(PHOBOSSRC std/datetime/date.d)
|
|
+/
|
|
module std.datetime.date;
|
|
|
|
import core.time : TimeException;
|
|
import std.traits : isSomeString, Unqual;
|
|
import std.typecons : Flag;
|
|
import std.range.primitives : isOutputRange;
|
|
|
|
version (StdUnittest) import std.exception : assertThrown;
|
|
|
|
@safe unittest
|
|
{
|
|
initializeTests();
|
|
}
|
|
|
|
|
|
/++
|
|
Exception type used by std.datetime. It's an alias to
|
|
$(REF TimeException,core,time). Either can be caught without concern about
|
|
which module it came from.
|
|
+/
|
|
alias DateTimeException = TimeException;
|
|
|
|
|
|
/++
|
|
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 ///
|
|
}
|
|
|
|
///
|
|
@safe pure unittest
|
|
{
|
|
assert(Date(2018, 10, 1).month == Month.oct);
|
|
assert(DateTime(1, 1, 1).month == Month.jan);
|
|
}
|
|
|
|
|
|
/++
|
|
Represents the 7 days of the Gregorian week (Sunday is 0).
|
|
+/
|
|
enum DayOfWeek : ubyte
|
|
{
|
|
sun = 0, ///
|
|
mon, ///
|
|
tue, ///
|
|
wed, ///
|
|
thu, ///
|
|
fri, ///
|
|
sat ///
|
|
}
|
|
|
|
///
|
|
@safe pure unittest
|
|
{
|
|
assert(Date(2018, 10, 1).dayOfWeek == DayOfWeek.mon);
|
|
assert(DateTime(5, 5, 5).dayOfWeek == DayOfWeek.thu);
|
|
}
|
|
|
|
/++
|
|
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.
|
|
|
|
If set to `AllowDayOverflow.no`, then day overflow is not allowed.
|
|
|
|
Otherwise, if set to `AllowDayOverflow.yes`, then day overflow is
|
|
allowed.
|
|
+/
|
|
alias AllowDayOverflow = Flag!"allowDayOverflow";
|
|
|
|
|
|
/++
|
|
Array of the strings representing time units, starting with the smallest
|
|
unit and going to the largest. It does not include `"nsecs"`.
|
|
|
|
Includes `"hnsecs"` (hecto-nanoseconds (100 ns)),
|
|
`"usecs"` (microseconds), `"msecs"` (milliseconds), `"seconds"`,
|
|
`"minutes"`, `"hours"`, `"days"`, `"weeks"`, `"months"`, and
|
|
`"years"`
|
|
+/
|
|
immutable string[] timeStrings = ["hnsecs", "usecs", "msecs", "seconds", "minutes",
|
|
"hours", "days", "weeks", "months", "years"];
|
|
|
|
|
|
/++
|
|
Combines the $(REF Date,std,datetime,date) and
|
|
$(REF TimeOfDay,std,datetime,date) 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
|
|
$(REF SysTime,std,datetime,systime). $(REF SysTime,std,datetime,systime) has
|
|
a concept of time zone and has much higher precision (hnsecs). `DateTime`
|
|
is intended primarily for calendar-based uses rather than precise time
|
|
operations.
|
|
+/
|
|
struct DateTime
|
|
{
|
|
public:
|
|
|
|
/++
|
|
Params:
|
|
date = The date portion of $(LREF DateTime).
|
|
tod = The time portion of $(LREF DateTime).
|
|
+/
|
|
this(Date date, TimeOfDay tod = TimeOfDay.init) @safe pure nothrow @nogc
|
|
{
|
|
_date = date;
|
|
_tod = tod;
|
|
}
|
|
|
|
@safe 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 (January is 1).
|
|
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);
|
|
}
|
|
|
|
@safe 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 `DateTime.`.
|
|
|
|
Returns:
|
|
$(BOOKTABLE,
|
|
$(TR $(TD this < rhs) $(TD < 0))
|
|
$(TR $(TD this == rhs) $(TD 0))
|
|
$(TR $(TD this > rhs) $(TD > 0))
|
|
)
|
|
+/
|
|
int opCmp(DateTime rhs) const @safe pure nothrow @nogc
|
|
{
|
|
immutable dateResult = _date.opCmp(rhs._date);
|
|
|
|
if (dateResult != 0)
|
|
return dateResult;
|
|
|
|
return _tod.opCmp(rhs._tod);
|
|
}
|
|
|
|
@safe 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));
|
|
assert(dt.opCmp(dt) == 0);
|
|
assert(dt.opCmp(cdt) == 0);
|
|
assert(dt.opCmp(idt) == 0);
|
|
assert(cdt.opCmp(dt) == 0);
|
|
assert(cdt.opCmp(cdt) == 0);
|
|
assert(cdt.opCmp(idt) == 0);
|
|
assert(idt.opCmp(dt) == 0);
|
|
assert(idt.opCmp(cdt) == 0);
|
|
assert(idt.opCmp(idt) == 0);
|
|
}
|
|
|
|
|
|
/++
|
|
The date portion of $(LREF DateTime).
|
|
+/
|
|
@property Date date() const @safe pure nothrow @nogc
|
|
{
|
|
return _date;
|
|
}
|
|
|
|
@safe 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);
|
|
assert(cdt.date == Date(1999, 7, 6));
|
|
assert(idt.date == Date(1999, 7, 6));
|
|
}
|
|
|
|
|
|
/++
|
|
The date portion of $(LREF DateTime).
|
|
|
|
Params:
|
|
date = The Date to set this $(LREF DateTime)'s date portion to.
|
|
+/
|
|
@property void date(Date date) @safe pure nothrow @nogc
|
|
{
|
|
_date = date;
|
|
}
|
|
|
|
@safe 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() const @safe pure nothrow @nogc
|
|
{
|
|
return _tod;
|
|
}
|
|
|
|
@safe 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);
|
|
assert(cdt.timeOfDay == TimeOfDay(12, 30, 33));
|
|
assert(idt.timeOfDay == TimeOfDay(12, 30, 33));
|
|
}
|
|
|
|
|
|
/++
|
|
The time portion of $(LREF DateTime).
|
|
|
|
Params:
|
|
tod = The $(REF TimeOfDay,std,datetime,date) to set this
|
|
$(LREF DateTime)'s time portion to.
|
|
+/
|
|
@property void timeOfDay(TimeOfDay tod) @safe pure nothrow @nogc
|
|
{
|
|
_tod = tod;
|
|
}
|
|
|
|
@safe 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() const @safe pure nothrow @nogc
|
|
{
|
|
return _date.year;
|
|
}
|
|
|
|
@safe 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);
|
|
assert(idt.year == 1999);
|
|
assert(idt.year == 1999);
|
|
}
|
|
|
|
|
|
/++
|
|
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:
|
|
$(REF DateTimeException,std,datetime,date) 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;
|
|
}
|
|
|
|
///
|
|
@safe 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);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
static void testDT(DateTime dt, int year, 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:
|
|
$(REF DateTimeException,std,datetime,date) if `isAD` is true.
|
|
+/
|
|
@property short yearBC() const @safe pure
|
|
{
|
|
return _date.yearBC;
|
|
}
|
|
|
|
///
|
|
@safe 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);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
assertThrown!DateTimeException((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);
|
|
dt.yearBC = 12;
|
|
assert(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:
|
|
$(REF DateTimeException,std,datetime,date) if a non-positive value
|
|
is given.
|
|
+/
|
|
@property void yearBC(int year) @safe pure
|
|
{
|
|
_date.yearBC = year;
|
|
}
|
|
|
|
///
|
|
@safe 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)));
|
|
}
|
|
|
|
@safe 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);
|
|
dt.yearBC = 12;
|
|
assert(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() const @safe pure nothrow @nogc
|
|
{
|
|
return _date.month;
|
|
}
|
|
|
|
///
|
|
@safe 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);
|
|
}
|
|
|
|
@safe 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);
|
|
assert(cdt.month == 7);
|
|
assert(idt.month == 7);
|
|
}
|
|
|
|
|
|
/++
|
|
Month of a Gregorian Year.
|
|
|
|
Params:
|
|
month = The month to set this $(LREF DateTime)'s month to.
|
|
|
|
Throws:
|
|
$(REF DateTimeException,std,datetime,date) if the given month is
|
|
not a valid month.
|
|
+/
|
|
@property void month(Month month) @safe pure
|
|
{
|
|
_date.month = month;
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
static void testDT(DateTime dt, Month month, 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() const @safe pure nothrow @nogc
|
|
{
|
|
return _date.day;
|
|
}
|
|
|
|
///
|
|
@safe 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);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
import std.format : format;
|
|
import std.range : chain;
|
|
|
|
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);
|
|
assert(cdt.day == 6);
|
|
assert(idt.day == 6);
|
|
}
|
|
|
|
|
|
/++
|
|
Day of a Gregorian Month.
|
|
|
|
Params:
|
|
day = The day of the month to set this $(LREF DateTime)'s day to.
|
|
|
|
Throws:
|
|
$(REF DateTimeException,std,datetime,date) if the given day is not
|
|
a valid day of the current month.
|
|
+/
|
|
@property void day(int day) @safe pure
|
|
{
|
|
_date.day = day;
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
import std.exception : assertNotThrown;
|
|
|
|
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() const @safe pure nothrow @nogc
|
|
{
|
|
return _tod.hour;
|
|
}
|
|
|
|
@safe 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);
|
|
assert(cdt.hour == 12);
|
|
assert(idt.hour == 12);
|
|
}
|
|
|
|
|
|
/++
|
|
Hours past midnight.
|
|
|
|
Params:
|
|
hour = The hour of the day to set this $(LREF DateTime)'s hour to.
|
|
|
|
Throws:
|
|
$(REF DateTimeException,std,datetime,date) if the given hour would
|
|
result in an invalid $(LREF DateTime).
|
|
+/
|
|
@property void hour(int hour) @safe pure
|
|
{
|
|
_tod.hour = hour;
|
|
}
|
|
|
|
@safe 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() const @safe pure nothrow @nogc
|
|
{
|
|
return _tod.minute;
|
|
}
|
|
|
|
@safe 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);
|
|
assert(cdt.minute == 30);
|
|
assert(idt.minute == 30);
|
|
}
|
|
|
|
|
|
/++
|
|
Minutes past the hour.
|
|
|
|
Params:
|
|
minute = The minute to set this $(LREF DateTime)'s minute to.
|
|
|
|
Throws:
|
|
$(REF DateTimeException,std,datetime,date) if the given minute
|
|
would result in an invalid $(LREF DateTime).
|
|
+/
|
|
@property void minute(int minute) @safe pure
|
|
{
|
|
_tod.minute = minute;
|
|
}
|
|
|
|
@safe 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() const @safe pure nothrow @nogc
|
|
{
|
|
return _tod.second;
|
|
}
|
|
|
|
@safe 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);
|
|
assert(cdt.second == 33);
|
|
assert(idt.second == 33);
|
|
}
|
|
|
|
|
|
/++
|
|
Seconds past the minute.
|
|
|
|
Params:
|
|
second = The second to set this $(LREF DateTime)'s second to.
|
|
|
|
Throws:
|
|
$(REF DateTimeException,std,datetime,date) if the given seconds
|
|
would result in an invalid $(LREF DateTime).
|
|
+/
|
|
@property void second(int second) @safe pure
|
|
{
|
|
_tod.second = second;
|
|
}
|
|
|
|
@safe 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),
|
|
mutating it. 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.
|
|
|
|
Returns:
|
|
A reference to the `DateTime` (`this`).
|
|
+/
|
|
ref DateTime add(string units)
|
|
(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow @nogc
|
|
if (units == "years" || units == "months")
|
|
{
|
|
_date.add!units(value, allowOverflow);
|
|
return this;
|
|
}
|
|
|
|
///
|
|
@safe 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));
|
|
}
|
|
|
|
@safe 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),
|
|
mutating it. 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.
|
|
|
|
Returns:
|
|
A reference to the `DateTime` (`this`).
|
|
+/
|
|
ref DateTime roll(string units)
|
|
(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow @nogc
|
|
if (units == "years" || units == "months")
|
|
{
|
|
_date.roll!units(value, allowOverflow);
|
|
return this;
|
|
}
|
|
|
|
///
|
|
@safe 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));
|
|
}
|
|
|
|
@safe 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), mutating it. 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 `"days"`, `"minutes"`, `"hours"`,
|
|
`"minutes"`, and `"seconds"`.
|
|
|
|
Params:
|
|
units = The units to add.
|
|
value = The number of $(D_PARAM units) to add to this
|
|
$(LREF DateTime).
|
|
|
|
Returns:
|
|
A reference to the `DateTime` (`this`).
|
|
+/
|
|
ref DateTime roll(string units)(long value) @safe pure nothrow @nogc
|
|
if (units == "days")
|
|
{
|
|
_date.roll!"days"(value);
|
|
return this;
|
|
}
|
|
|
|
///
|
|
@safe 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));
|
|
}
|
|
|
|
@safe 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)));
|
|
}
|
|
|
|
|
|
/// ditto
|
|
ref DateTime roll(string units)(long value) @safe pure nothrow @nogc
|
|
if (units == "hours" ||
|
|
units == "minutes" ||
|
|
units == "seconds")
|
|
{
|
|
_tod.roll!units(value);
|
|
return this;
|
|
}
|
|
|
|
// Test roll!"hours"().
|
|
@safe unittest
|
|
{
|
|
static void testDT(DateTime orig, int hours, 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"().
|
|
@safe unittest
|
|
{
|
|
static void testDT(DateTime orig, int minutes, 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"().
|
|
@safe unittest
|
|
{
|
|
static void testDT(DateTime orig, int seconds, 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)));
|
|
}
|
|
|
|
|
|
import core.time : Duration;
|
|
/++
|
|
Gives the result of adding or subtracting a $(REF Duration, core,time)
|
|
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 $(REF Duration, core,time) to add to or subtract from
|
|
this $(LREF DateTime).
|
|
+/
|
|
DateTime opBinary(string op)(Duration duration) const @safe pure nothrow @nogc
|
|
if (op == "+" || op == "-")
|
|
{
|
|
DateTime retval = this;
|
|
immutable seconds = duration.total!"seconds";
|
|
mixin("return retval._addSeconds(" ~ op ~ "seconds);");
|
|
}
|
|
|
|
///
|
|
@safe unittest
|
|
{
|
|
import core.time : hours, seconds;
|
|
|
|
assert(DateTime(2015, 12, 31, 23, 59, 59) + seconds(1) ==
|
|
DateTime(2016, 1, 1, 0, 0, 0));
|
|
|
|
assert(DateTime(2015, 12, 31, 23, 59, 59) + hours(1) ==
|
|
DateTime(2016, 1, 1, 0, 59, 59));
|
|
|
|
assert(DateTime(2016, 1, 1, 0, 0, 0) - seconds(1) ==
|
|
DateTime(2015, 12, 31, 23, 59, 59));
|
|
|
|
assert(DateTime(2016, 1, 1, 0, 59, 59) - hours(1) ==
|
|
DateTime(2015, 12, 31, 23, 59, 59));
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
import core.time : dur;
|
|
|
|
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)));
|
|
|
|
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)));
|
|
|
|
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));
|
|
assert(cdt + duration == DateTime(1999, 7, 6, 12, 30, 45));
|
|
assert(idt + duration == DateTime(1999, 7, 6, 12, 30, 45));
|
|
assert(cdt - duration == DateTime(1999, 7, 6, 12, 30, 21));
|
|
assert(idt - duration == DateTime(1999, 7, 6, 12, 30, 21));
|
|
}
|
|
|
|
|
|
/++
|
|
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)(Duration duration) @safe pure nothrow @nogc
|
|
if (op == "+" || op == "-")
|
|
{
|
|
import core.time : convert;
|
|
import std.format : format;
|
|
|
|
DateTime retval = this;
|
|
immutable hnsecs = duration.total!"hnsecs";
|
|
|
|
mixin(format(`return _addSeconds(convert!("hnsecs", "seconds")(%shnsecs));`, op));
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
import core.time : dur;
|
|
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)(DateTime rhs) const @safe pure nothrow @nogc
|
|
if (op == "-")
|
|
{
|
|
immutable dateResult = _date - rhs.date;
|
|
immutable todResult = _tod - rhs._tod;
|
|
|
|
import core.time : dur;
|
|
return dur!"hnsecs"(dateResult.total!"hnsecs" + todResult.total!"hnsecs");
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
auto dt = DateTime(1999, 7, 6, 12, 30, 33);
|
|
|
|
import core.time : dur;
|
|
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));
|
|
assert(dt - dt == Duration.zero);
|
|
assert(cdt - dt == Duration.zero);
|
|
assert(idt - dt == Duration.zero);
|
|
|
|
assert(dt - cdt == Duration.zero);
|
|
assert(cdt - cdt == Duration.zero);
|
|
assert(idt - cdt == Duration.zero);
|
|
|
|
assert(dt - idt == Duration.zero);
|
|
assert(cdt - idt == Duration.zero);
|
|
assert(idt - idt == Duration.zero);
|
|
}
|
|
|
|
|
|
/++
|
|
Returns the difference between the two $(LREF DateTime)s in months.
|
|
|
|
To get the difference in years, subtract the year property
|
|
of two $(LREF DateTime)s. To get the difference in days or weeks,
|
|
subtract the $(LREF DateTime)s themselves and use the
|
|
$(REF Duration, core,time) that results. Because converting between
|
|
months and smaller units requires a specific date (which
|
|
$(REF Duration, core,time)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(DateTime rhs) const @safe pure nothrow @nogc
|
|
{
|
|
return _date.diffMonths(rhs._date);
|
|
}
|
|
|
|
///
|
|
@safe 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);
|
|
}
|
|
|
|
@safe 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));
|
|
assert(dt.diffMonths(dt) == 0);
|
|
assert(cdt.diffMonths(dt) == 0);
|
|
assert(idt.diffMonths(dt) == 0);
|
|
|
|
assert(dt.diffMonths(cdt) == 0);
|
|
assert(cdt.diffMonths(cdt) == 0);
|
|
assert(idt.diffMonths(cdt) == 0);
|
|
|
|
assert(dt.diffMonths(idt) == 0);
|
|
assert(cdt.diffMonths(idt) == 0);
|
|
assert(idt.diffMonths(idt) == 0);
|
|
}
|
|
|
|
|
|
/++
|
|
Whether this $(LREF DateTime) is in a leap year.
|
|
+/
|
|
@property bool isLeapYear() const @safe pure nothrow @nogc
|
|
{
|
|
return _date.isLeapYear;
|
|
}
|
|
|
|
@safe 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));
|
|
assert(!dt.isLeapYear);
|
|
assert(!cdt.isLeapYear);
|
|
assert(!idt.isLeapYear);
|
|
}
|
|
|
|
|
|
/++
|
|
Day of the week this $(LREF DateTime) is on.
|
|
+/
|
|
@property DayOfWeek dayOfWeek() const @safe pure nothrow @nogc
|
|
{
|
|
return _date.dayOfWeek;
|
|
}
|
|
|
|
@safe 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));
|
|
assert(dt.dayOfWeek == DayOfWeek.tue);
|
|
assert(cdt.dayOfWeek == DayOfWeek.tue);
|
|
assert(idt.dayOfWeek == DayOfWeek.tue);
|
|
}
|
|
|
|
|
|
/++
|
|
Day of the year this $(LREF DateTime) is on.
|
|
+/
|
|
@property ushort dayOfYear() const @safe pure nothrow @nogc
|
|
{
|
|
return _date.dayOfYear;
|
|
}
|
|
|
|
///
|
|
@safe 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);
|
|
}
|
|
|
|
@safe 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));
|
|
assert(dt.dayOfYear == 187);
|
|
assert(cdt.dayOfYear == 187);
|
|
assert(idt.dayOfYear == 187);
|
|
}
|
|
|
|
|
|
/++
|
|
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;
|
|
}
|
|
|
|
@safe 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));
|
|
dt.dayOfYear = 12;
|
|
assert(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() const @safe pure nothrow @nogc
|
|
{
|
|
return _date.dayOfGregorianCal;
|
|
}
|
|
|
|
///
|
|
@safe 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);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
|
|
immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
|
|
assert(cdt.dayOfGregorianCal == 729_941);
|
|
assert(idt.dayOfGregorianCal == 729_941);
|
|
}
|
|
|
|
|
|
/++
|
|
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 @nogc
|
|
{
|
|
_date.dayOfGregorianCal = days;
|
|
}
|
|
|
|
///
|
|
@safe 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)));
|
|
}
|
|
|
|
@safe 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:
|
|
$(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date)
|
|
+/
|
|
@property ubyte isoWeek() const @safe pure nothrow
|
|
{
|
|
return _date.isoWeek;
|
|
}
|
|
|
|
@safe 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));
|
|
assert(dt.isoWeek == 27);
|
|
assert(cdt.isoWeek == 27);
|
|
assert(idt.isoWeek == 27);
|
|
}
|
|
|
|
|
|
/++
|
|
The year of the ISO 8601 week calendar that this $(LREF DateTime) is in.
|
|
|
|
See_Also:
|
|
$(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date)
|
|
+/
|
|
@property short isoWeekYear() const @safe pure nothrow
|
|
{
|
|
return _date.isoWeekYear;
|
|
}
|
|
|
|
|
|
/++
|
|
$(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() const @safe pure nothrow
|
|
{
|
|
try
|
|
return DateTime(_date.endOfMonth, TimeOfDay(23, 59, 59));
|
|
catch (Exception e)
|
|
assert(0, "DateTime constructor threw.");
|
|
}
|
|
|
|
///
|
|
@safe 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)));
|
|
}
|
|
|
|
@safe 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));
|
|
assert(cdt.endOfMonth == DateTime(1999, 7, 31, 23, 59, 59));
|
|
assert(idt.endOfMonth == DateTime(1999, 7, 31, 23, 59, 59));
|
|
}
|
|
|
|
|
|
/++
|
|
The last day in the month that this $(LREF DateTime) is in.
|
|
+/
|
|
@property ubyte daysInMonth() const @safe pure nothrow @nogc
|
|
{
|
|
return _date.daysInMonth;
|
|
}
|
|
|
|
///
|
|
@safe 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);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
|
|
immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
|
|
assert(cdt.daysInMonth == 31);
|
|
assert(idt.daysInMonth == 31);
|
|
}
|
|
|
|
|
|
/++
|
|
Whether the current year is a date in A.D.
|
|
+/
|
|
@property bool isAD() const @safe pure nothrow @nogc
|
|
{
|
|
return _date.isAD;
|
|
}
|
|
|
|
///
|
|
@safe 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);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
|
|
immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
|
|
assert(cdt.isAD);
|
|
assert(idt.isAD);
|
|
}
|
|
|
|
|
|
/++
|
|
The $(HTTP 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() const @safe pure nothrow @nogc
|
|
{
|
|
if (_tod._hour < 12)
|
|
return _date.julianDay - 1;
|
|
else
|
|
return _date.julianDay;
|
|
}
|
|
|
|
@safe 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));
|
|
assert(cdt.julianDay == 2_451_366);
|
|
assert(idt.julianDay == 2_451_366);
|
|
}
|
|
|
|
|
|
/++
|
|
The modified $(HTTP 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() const @safe pure nothrow @nogc
|
|
{
|
|
return _date.modJulianDay;
|
|
}
|
|
|
|
@safe 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));
|
|
assert(cdt.modJulianDay == 51_365);
|
|
assert(idt.modJulianDay == 51_365);
|
|
}
|
|
|
|
|
|
/++
|
|
Converts this $(LREF DateTime) to a string with the format `YYYYMMDDTHHMMSS`.
|
|
If `writer` is set, the resulting string will be written directly to it.
|
|
|
|
Params:
|
|
writer = A `char` accepting
|
|
$(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
|
|
Returns:
|
|
A `string` when not using an output range; `void` otherwise.
|
|
+/
|
|
string toISOString() const @safe pure nothrow
|
|
{
|
|
import std.array : appender;
|
|
auto w = appender!string();
|
|
w.reserve(18);
|
|
try
|
|
toISOString(w);
|
|
catch (Exception e)
|
|
assert(0, "toISOString() threw.");
|
|
return w.data;
|
|
}
|
|
|
|
/// ditto
|
|
void toISOString(W)(ref W writer) const
|
|
if (isOutputRange!(W, char))
|
|
{
|
|
import std.format.write : formattedWrite;
|
|
_date.toISOString(writer);
|
|
formattedWrite!("T%02d%02d%02d")(
|
|
writer,
|
|
_tod._hour,
|
|
_tod._minute,
|
|
_tod._second
|
|
);
|
|
}
|
|
|
|
///
|
|
@safe 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");
|
|
}
|
|
|
|
@safe 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);
|
|
assert(cdt.toISOString() == "19990706T123033");
|
|
assert(idt.toISOString() == "19990706T123033");
|
|
}
|
|
|
|
|
|
/++
|
|
Converts this $(LREF DateTime) to a string with the format
|
|
`YYYY-MM-DDTHH:MM:SS`. If `writer` is set, the resulting
|
|
string will be written directly to it.
|
|
|
|
Params:
|
|
writer = A `char` accepting
|
|
$(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
|
|
Returns:
|
|
A `string` when not using an output range; `void` otherwise.
|
|
+/
|
|
string toISOExtString() const @safe pure nothrow
|
|
{
|
|
import std.array : appender;
|
|
auto w = appender!string();
|
|
w.reserve(20);
|
|
try
|
|
toISOExtString(w);
|
|
catch (Exception e)
|
|
assert(0, "toISOExtString() threw.");
|
|
return w.data;
|
|
}
|
|
|
|
/// ditto
|
|
void toISOExtString(W)(ref W writer) const
|
|
if (isOutputRange!(W, char))
|
|
{
|
|
import std.format.write : formattedWrite;
|
|
_date.toISOExtString(writer);
|
|
formattedWrite!("T%02d:%02d:%02d")(
|
|
writer,
|
|
_tod._hour,
|
|
_tod._minute,
|
|
_tod._second
|
|
);
|
|
}
|
|
|
|
///
|
|
@safe 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");
|
|
}
|
|
|
|
@safe 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);
|
|
assert(cdt.toISOExtString() == "1999-07-06T12:30:33");
|
|
assert(idt.toISOExtString() == "1999-07-06T12:30:33");
|
|
}
|
|
|
|
/++
|
|
Converts this $(LREF DateTime) to a string with the format
|
|
`YYYY-Mon-DD HH:MM:SS`. If `writer` is set, the resulting
|
|
string will be written directly to it.
|
|
|
|
Params:
|
|
writer = A `char` accepting
|
|
$(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
|
|
Returns:
|
|
A `string` when not using an output range; `void` otherwise.
|
|
+/
|
|
string toSimpleString() const @safe pure nothrow
|
|
{
|
|
import std.array : appender;
|
|
auto w = appender!string();
|
|
w.reserve(22);
|
|
try
|
|
toSimpleString(w);
|
|
catch (Exception e)
|
|
assert(0, "toSimpleString() threw.");
|
|
return w.data;
|
|
}
|
|
|
|
/// ditto
|
|
void toSimpleString(W)(ref W writer) const
|
|
if (isOutputRange!(W, char))
|
|
{
|
|
import std.format.write : formattedWrite;
|
|
_date.toSimpleString(writer);
|
|
formattedWrite!(" %02d:%02d:%02d")(
|
|
writer,
|
|
_tod._hour,
|
|
_tod._minute,
|
|
_tod._second
|
|
);
|
|
}
|
|
|
|
///
|
|
@safe 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");
|
|
}
|
|
|
|
@safe 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);
|
|
assert(cdt.toSimpleString() == "1999-Jul-06 12:30:33");
|
|
assert(idt.toSimpleString() == "1999-Jul-06 12:30:33");
|
|
}
|
|
|
|
|
|
/++
|
|
Converts this $(LREF DateTime) to a string.
|
|
|
|
This function exists to make it easy to convert a $(LREF DateTime) to a
|
|
string for code that does not care what the exact format is - just that
|
|
it presents the information in a clear manner. It also makes it easy to
|
|
simply convert a $(LREF DateTime) to a string when using functions such
|
|
as `to!string`, `format`, or `writeln` which use toString to convert
|
|
user-defined types. So, it is unlikely that much code will call
|
|
toString directly.
|
|
|
|
The format of the string is purposefully unspecified, and code that
|
|
cares about the format of the string should use `toISOString`,
|
|
`toISOExtString`, `toSimpleString`, or some other custom formatting
|
|
function that explicitly generates the format that the code needs. The
|
|
reason is that the code is then clear about what format it's using,
|
|
making it less error-prone to maintain the code and interact with other
|
|
software that consumes the generated strings. It's for this same reason
|
|
that $(LREF DateTime) has no `fromString` function, whereas it does have
|
|
`fromISOString`, `fromISOExtString`, and `fromSimpleString`.
|
|
|
|
The format returned by toString may or may not change in the future.
|
|
+/
|
|
string toString() const @safe pure nothrow
|
|
{
|
|
return toSimpleString();
|
|
}
|
|
|
|
@safe 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));
|
|
assert(dt.toString());
|
|
assert(cdt.toString());
|
|
assert(idt.toString());
|
|
}
|
|
|
|
/// ditto
|
|
void toString(W)(ref W writer) const
|
|
if (isOutputRange!(W, char))
|
|
{
|
|
toSimpleString(writer);
|
|
}
|
|
|
|
/++
|
|
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:
|
|
$(REF DateTimeException,std,datetime,date) if the given string is
|
|
not in the ISO format or if the resulting $(LREF DateTime) would not
|
|
be valid.
|
|
+/
|
|
static DateTime fromISOString(S)(scope const S isoString) @safe pure
|
|
if (isSomeString!S)
|
|
{
|
|
import std.algorithm.searching : countUntil;
|
|
import std.exception : enforce;
|
|
import std.format : format;
|
|
import std.string : strip;
|
|
import std.utf : byCodeUnit;
|
|
|
|
auto str = strip(isoString);
|
|
|
|
enforce!DateTimeException(str.length >= 15, format("Invalid format for DateTime.fromISOString %s", isoString));
|
|
auto t = str.byCodeUnit.countUntil('T');
|
|
|
|
enforce!DateTimeException(t != -1, format("Invalid format for DateTime.fromISOString: %s", isoString));
|
|
|
|
immutable date = Date.fromISOString(str[0 .. t]);
|
|
immutable tod = TimeOfDay.fromISOString(str[t+1 .. $]);
|
|
|
|
return DateTime(date, tod);
|
|
}
|
|
|
|
///
|
|
@safe 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)));
|
|
}
|
|
|
|
@safe 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, 1)));
|
|
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)));
|
|
}
|
|
|
|
// https://issues.dlang.org/show_bug.cgi?id=17801
|
|
@safe unittest
|
|
{
|
|
import std.conv : to;
|
|
import std.meta : AliasSeq;
|
|
static foreach (C; AliasSeq!(char, wchar, dchar))
|
|
{
|
|
static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
|
|
assert(DateTime.fromISOString(to!S("20121221T141516")) == DateTime(2012, 12, 21, 14, 15, 16));
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
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:
|
|
$(REF DateTimeException,std,datetime,date) 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)(scope const S isoExtString) @safe pure
|
|
if (isSomeString!(S))
|
|
{
|
|
import std.algorithm.searching : countUntil;
|
|
import std.exception : enforce;
|
|
import std.format : format;
|
|
import std.string : strip;
|
|
import std.utf : byCodeUnit;
|
|
|
|
auto str = strip(isoExtString);
|
|
|
|
enforce!DateTimeException(str.length >= 15,
|
|
format("Invalid format for DateTime.fromISOExtString: %s", isoExtString));
|
|
auto t = str.byCodeUnit.countUntil('T');
|
|
|
|
enforce!DateTimeException(t != -1, format("Invalid format for DateTime.fromISOExtString: %s", isoExtString));
|
|
|
|
immutable date = Date.fromISOExtString(str[0 .. t]);
|
|
immutable tod = TimeOfDay.fromISOExtString(str[t+1 .. $]);
|
|
|
|
return DateTime(date, tod);
|
|
}
|
|
|
|
///
|
|
@safe 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)));
|
|
}
|
|
|
|
@safe 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, 1)));
|
|
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)));
|
|
}
|
|
|
|
// https://issues.dlang.org/show_bug.cgi?id=17801
|
|
@safe unittest
|
|
{
|
|
import std.conv : to;
|
|
import std.meta : AliasSeq;
|
|
static foreach (C; AliasSeq!(char, wchar, dchar))
|
|
{
|
|
static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
|
|
assert(DateTime.fromISOExtString(to!S("2012-12-21T14:15:16")) == DateTime(2012, 12, 21, 14, 15, 16));
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
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:
|
|
$(REF DateTimeException,std,datetime,date) if the given string is
|
|
not in the correct format or if the resulting $(LREF DateTime)
|
|
would not be valid.
|
|
+/
|
|
static DateTime fromSimpleString(S)(scope const S simpleString) @safe pure
|
|
if (isSomeString!(S))
|
|
{
|
|
import std.algorithm.searching : countUntil;
|
|
import std.exception : enforce;
|
|
import std.format : format;
|
|
import std.string : strip;
|
|
import std.utf : byCodeUnit;
|
|
|
|
auto str = strip(simpleString);
|
|
|
|
enforce!DateTimeException(str.length >= 15,
|
|
format("Invalid format for DateTime.fromSimpleString: %s", simpleString));
|
|
auto t = str.byCodeUnit.countUntil(' ');
|
|
|
|
enforce!DateTimeException(t != -1, format("Invalid format for DateTime.fromSimpleString: %s", simpleString));
|
|
|
|
immutable date = Date.fromSimpleString(str[0 .. t]);
|
|
immutable tod = TimeOfDay.fromISOExtString(str[t+1 .. $]);
|
|
|
|
return DateTime(date, tod);
|
|
}
|
|
|
|
///
|
|
@safe 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)));
|
|
}
|
|
|
|
@safe 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, 1)));
|
|
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)));
|
|
}
|
|
|
|
// https://issues.dlang.org/show_bug.cgi?id=17801
|
|
@safe unittest
|
|
{
|
|
import std.conv : to;
|
|
import std.meta : AliasSeq;
|
|
static foreach (C; AliasSeq!(char, wchar, dchar))
|
|
{
|
|
static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
|
|
assert(DateTime.fromSimpleString(to!S("2012-Dec-21 14:15:16")) == DateTime(2012, 12, 21, 14, 15, 16));
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
Returns the $(LREF DateTime) farthest in the past which is representable
|
|
by $(LREF DateTime).
|
|
+/
|
|
@property static DateTime min() @safe pure nothrow @nogc
|
|
out(result)
|
|
{
|
|
assert(result._date == Date.min);
|
|
assert(result._tod == TimeOfDay.min);
|
|
}
|
|
do
|
|
{
|
|
auto dt = DateTime.init;
|
|
dt._date._year = short.min;
|
|
dt._date._month = Month.jan;
|
|
dt._date._day = 1;
|
|
|
|
return dt;
|
|
}
|
|
|
|
@safe 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 @nogc
|
|
out(result)
|
|
{
|
|
assert(result._date == Date.max);
|
|
assert(result._tod == TimeOfDay.max);
|
|
}
|
|
do
|
|
{
|
|
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;
|
|
}
|
|
|
|
@safe 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 @nogc
|
|
{
|
|
import core.time : convert;
|
|
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;
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
static void testDT(DateTime orig, int seconds, 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;
|
|
}
|
|
|
|
///
|
|
@safe pure unittest
|
|
{
|
|
import core.time : days, seconds;
|
|
|
|
auto dt = DateTime(2000, 6, 1, 10, 30, 0);
|
|
|
|
assert(dt.date == Date(2000, 6, 1));
|
|
assert(dt.timeOfDay == TimeOfDay(10, 30, 0));
|
|
assert(dt.dayOfYear == 153);
|
|
assert(dt.dayOfWeek == DayOfWeek.thu);
|
|
|
|
dt += 10.days + 100.seconds;
|
|
assert(dt == DateTime(2000, 6, 11, 10, 31, 40));
|
|
|
|
assert(dt.toISOExtString() == "2000-06-11T10:31:40");
|
|
assert(dt.toISOString() == "20000611T103140");
|
|
assert(dt.toSimpleString() == "2000-Jun-11 10:31:40");
|
|
|
|
assert(DateTime.fromISOExtString("2018-01-01T12:00:00") == DateTime(2018, 1, 1, 12, 0, 0));
|
|
assert(DateTime.fromISOString("20180101T120000") == DateTime(2018, 1, 1, 12, 0, 0));
|
|
assert(DateTime.fromSimpleString("2018-Jan-01 12:00:00") == DateTime(2018, 1, 1, 12, 0, 0));
|
|
}
|
|
|
|
/++
|
|
Represents a date in the
|
|
$(HTTP 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 `Date` is
|
|
optimized for calendar-based operations.
|
|
|
|
`Date` uses the Proleptic Gregorian Calendar, so it assumes the Gregorian
|
|
leap year calculations for its entire length. As per
|
|
$(HTTP 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:
|
|
$(REF DateTimeException,std,datetime,date) 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 (January is 1).
|
|
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 = year.castToYear;
|
|
_month = cast(Month) month;
|
|
_day = cast(ubyte) day;
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
import std.exception : assertNotThrown;
|
|
assert(Date(1, 1, 1) == Date.init);
|
|
|
|
static void testDate(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));
|
|
assertThrown!DateTimeException(Date(short.max+1, 1, 1));
|
|
|
|
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));
|
|
assertThrown!DateTimeException(Date(short.min-1, 1, 1));
|
|
}
|
|
|
|
|
|
/++
|
|
Params:
|
|
day = The Xth day of the Gregorian Calendar that the constructed
|
|
$(LREF Date) will be for.
|
|
+/
|
|
this(int day) @safe pure nothrow @nogc
|
|
{
|
|
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;
|
|
|
|
setDayOfYear(day);
|
|
}
|
|
}
|
|
else if (day <= 0 && -day < daysInLeapYear)
|
|
{
|
|
_year = 0;
|
|
|
|
setDayOfYear(daysInLeapYear + day);
|
|
}
|
|
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;
|
|
|
|
setDayOfYear(newDoY);
|
|
}
|
|
}
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
import std.range : chain;
|
|
|
|
// 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(Date rhs) const @safe pure nothrow @nogc
|
|
{
|
|
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;
|
|
}
|
|
|
|
@safe 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);
|
|
assert(date.opCmp(date) == 0);
|
|
assert(date.opCmp(cdate) == 0);
|
|
assert(date.opCmp(idate) == 0);
|
|
assert(cdate.opCmp(date) == 0);
|
|
assert(cdate.opCmp(cdate) == 0);
|
|
assert(cdate.opCmp(idate) == 0);
|
|
assert(idate.opCmp(date) == 0);
|
|
assert(idate.opCmp(cdate) == 0);
|
|
assert(idate.opCmp(idate) == 0);
|
|
}
|
|
|
|
|
|
/++
|
|
Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
|
|
are B.C.
|
|
+/
|
|
@property short year() const @safe pure nothrow @nogc
|
|
{
|
|
return _year;
|
|
}
|
|
|
|
///
|
|
@safe unittest
|
|
{
|
|
assert(Date(1999, 7, 6).year == 1999);
|
|
assert(Date(2010, 10, 4).year == 2010);
|
|
assert(Date(-7, 4, 5).year == -7);
|
|
}
|
|
|
|
@safe 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);
|
|
assert(cdate.year == 1999);
|
|
assert(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:
|
|
$(REF DateTimeException,std,datetime,date) 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 = year.castToYear;
|
|
}
|
|
|
|
///
|
|
@safe unittest
|
|
{
|
|
assert(Date(1999, 7, 6).year == 1999);
|
|
assert(Date(2010, 10, 4).year == 2010);
|
|
assert(Date(-7, 4, 5).year == -7);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
static void testDateInvalid(Date date, int year)
|
|
{
|
|
date.year = year;
|
|
}
|
|
|
|
static void testDate(Date date, int year, 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:
|
|
$(REF DateTimeException,std,datetime,date) if `isAD` is true.
|
|
+/
|
|
@property ushort yearBC() const @safe pure
|
|
{
|
|
import std.format : format;
|
|
|
|
if (isAD)
|
|
throw new DateTimeException(format("Year %s is A.D.", _year));
|
|
return cast(ushort)((_year * -1) + 1);
|
|
}
|
|
|
|
///
|
|
@safe unittest
|
|
{
|
|
assert(Date(0, 1, 1).yearBC == 1);
|
|
assert(Date(-1, 1, 1).yearBC == 2);
|
|
assert(Date(-100, 1, 1).yearBC == 101);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
assertThrown!DateTimeException((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);
|
|
assert(date.yearBC == 1);
|
|
assert(cdate.yearBC == 1);
|
|
assert(idate.yearBC == 1);
|
|
}
|
|
|
|
|
|
/++
|
|
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:
|
|
$(REF DateTimeException,std,datetime,date) 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 = castToYear((year - 1) * -1);
|
|
}
|
|
|
|
///
|
|
@safe 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));
|
|
}
|
|
|
|
@safe 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);
|
|
date.yearBC = 7;
|
|
assert(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() const @safe pure nothrow @nogc
|
|
{
|
|
return _month;
|
|
}
|
|
|
|
///
|
|
@safe unittest
|
|
{
|
|
assert(Date(1999, 7, 6).month == 7);
|
|
assert(Date(2010, 10, 4).month == 10);
|
|
assert(Date(-7, 4, 5).month == 4);
|
|
}
|
|
|
|
@safe 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);
|
|
assert(cdate.month == 7);
|
|
assert(idate.month == 7);
|
|
}
|
|
|
|
/++
|
|
Month of a Gregorian Year.
|
|
|
|
Params:
|
|
month = The month to set this $(LREF Date)'s month to.
|
|
|
|
Throws:
|
|
$(REF DateTimeException,std,datetime,date) 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;
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
static void testDate(Date date, Month month, 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() const @safe pure nothrow @nogc
|
|
{
|
|
return _day;
|
|
}
|
|
|
|
///
|
|
@safe unittest
|
|
{
|
|
assert(Date(1999, 7, 6).day == 6);
|
|
assert(Date(2010, 10, 4).day == 4);
|
|
assert(Date(-7, 4, 5).day == 5);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
import std.format : format;
|
|
import std.range : chain;
|
|
|
|
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);
|
|
assert(cdate.day == 6);
|
|
assert(idate.day == 6);
|
|
}
|
|
|
|
/++
|
|
Day of a Gregorian Month.
|
|
|
|
Params:
|
|
day = The day of the month to set this $(LREF Date)'s day to.
|
|
|
|
Throws:
|
|
$(REF DateTimeException,std,datetime,date) 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;
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
import std.exception : assertNotThrown;
|
|
|
|
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), mutating
|
|
it. 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.
|
|
|
|
Returns:
|
|
A reference to the `Date` (`this`).
|
|
+/
|
|
@safe pure nothrow @nogc
|
|
ref Date add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
|
|
if (units == "years")
|
|
{
|
|
_year += value;
|
|
|
|
if (_month == Month.feb && _day == 29 && !yearIsLeapYear(_year))
|
|
{
|
|
if (allowOverflow == AllowDayOverflow.yes)
|
|
{
|
|
_month = Month.mar;
|
|
_day = 1;
|
|
}
|
|
else
|
|
_day = 28;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
///
|
|
@safe 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 AllowDayOverflow.yes
|
|
@safe 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 AllowDayOverflow.no
|
|
@safe 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.
|
|
@safe pure nothrow @nogc
|
|
ref Date add(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
|
|
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 AllowDayOverflow.yes
|
|
@safe 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 AllowDayOverflow.no
|
|
@safe 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), mutating
|
|
it. 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.
|
|
|
|
Returns:
|
|
A reference to the `Date` (`this`).
|
|
+/
|
|
@safe pure nothrow @nogc
|
|
ref Date roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
|
|
if (units == "years")
|
|
{
|
|
return add!"years"(value, allowOverflow);
|
|
}
|
|
|
|
///
|
|
@safe 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));
|
|
}
|
|
|
|
@safe 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.
|
|
@safe pure nothrow @nogc
|
|
ref Date roll(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
|
|
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 AllowDayOverflow.yes
|
|
@safe 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 AllowDayOverflow.no
|
|
@safe 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), mutating it. 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 `"days"`.
|
|
|
|
Params:
|
|
units = The units to add. Must be `"days"`.
|
|
days = The number of days to add to this $(LREF Date).
|
|
|
|
Returns:
|
|
A reference to the `Date` (`this`).
|
|
+/
|
|
ref Date roll(string units)(long days) @safe pure nothrow @nogc
|
|
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;
|
|
}
|
|
|
|
///
|
|
@safe 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));
|
|
}
|
|
|
|
@safe 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)));
|
|
}
|
|
|
|
import core.time : Duration;
|
|
/++
|
|
Gives the result of adding or subtracting a $(REF Duration, core,time)
|
|
from
|
|
|
|
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 $(REF Duration, core,time) to add to or subtract from
|
|
this $(LREF Date).
|
|
+/
|
|
Date opBinary(string op)(Duration duration) const @safe pure nothrow @nogc
|
|
if (op == "+" || op == "-")
|
|
{
|
|
Date retval = this;
|
|
immutable days = duration.total!"days";
|
|
mixin("return retval._addDays(" ~ op ~ "days);");
|
|
}
|
|
|
|
///
|
|
@safe unittest
|
|
{
|
|
import core.time : days;
|
|
|
|
assert(Date(2015, 12, 31) + days(1) == Date(2016, 1, 1));
|
|
assert(Date(2004, 2, 26) + days(4) == Date(2004, 3, 1));
|
|
|
|
assert(Date(2016, 1, 1) - days(1) == Date(2015, 12, 31));
|
|
assert(Date(2004, 3, 1) - days(4) == Date(2004, 2, 26));
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
|
|
import core.time : dur;
|
|
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));
|
|
|
|
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));
|
|
|
|
auto duration = dur!"days"(12);
|
|
const cdate = Date(1999, 7, 6);
|
|
immutable idate = Date(1999, 7, 6);
|
|
assert(date + duration == Date(1999, 7, 18));
|
|
assert(cdate + duration == Date(1999, 7, 18));
|
|
assert(idate + duration == Date(1999, 7, 18));
|
|
|
|
assert(date - duration == Date(1999, 6, 24));
|
|
assert(cdate - duration == Date(1999, 6, 24));
|
|
assert(idate - duration == Date(1999, 6, 24));
|
|
}
|
|
|
|
|
|
/++
|
|
Gives the result of adding or subtracting a $(REF Duration, core,time)
|
|
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 $(REF Duration, core,time) to add to or subtract from
|
|
this $(LREF Date).
|
|
+/
|
|
ref Date opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc
|
|
if (op == "+" || op == "-")
|
|
{
|
|
immutable days = duration.total!"days";
|
|
mixin("return _addDays(" ~ op ~ "days);");
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
import core.time : dur;
|
|
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);
|
|
date += duration;
|
|
static assert(!__traits(compiles, cdate += duration));
|
|
static assert(!__traits(compiles, idate += duration));
|
|
|
|
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 $(LREF Date) using this operator are
|
|
|
|
$(BOOKTABLE,
|
|
$(TR $(TD Date) $(TD -) $(TD Date) $(TD -->) $(TD duration))
|
|
)
|
|
+/
|
|
Duration opBinary(string op)(Date rhs) const @safe pure nothrow @nogc
|
|
if (op == "-")
|
|
{
|
|
import core.time : dur;
|
|
return dur!"days"(this.dayOfGregorianCal - rhs.dayOfGregorianCal);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
|
|
import core.time : dur;
|
|
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);
|
|
assert(date - date == Duration.zero);
|
|
assert(cdate - date == Duration.zero);
|
|
assert(idate - date == Duration.zero);
|
|
|
|
assert(date - cdate == Duration.zero);
|
|
assert(cdate - cdate == Duration.zero);
|
|
assert(idate - cdate == Duration.zero);
|
|
|
|
assert(date - idate == Duration.zero);
|
|
assert(cdate - idate == Duration.zero);
|
|
assert(idate - idate == Duration.zero);
|
|
}
|
|
|
|
|
|
/++
|
|
Returns the difference between the two $(LREF Date)s in months.
|
|
|
|
To get the difference in years, subtract the year property
|
|
of two $(LREF Date)s. To get the difference in days or weeks,
|
|
subtract the $(LREF Date)s themselves and use the
|
|
$(REF Duration, core,time) that results. Because converting between
|
|
months and smaller units requires a specific date (which
|
|
$(REF Duration, core,time)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(Date rhs) const @safe pure nothrow @nogc
|
|
{
|
|
immutable yearDiff = _year - rhs._year;
|
|
immutable monthDiff = _month - rhs._month;
|
|
|
|
return yearDiff * 12 + monthDiff;
|
|
}
|
|
|
|
///
|
|
@safe 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);
|
|
}
|
|
|
|
@safe 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);
|
|
assert(date.diffMonths(date) == 0);
|
|
assert(cdate.diffMonths(date) == 0);
|
|
assert(idate.diffMonths(date) == 0);
|
|
|
|
assert(date.diffMonths(cdate) == 0);
|
|
assert(cdate.diffMonths(cdate) == 0);
|
|
assert(idate.diffMonths(cdate) == 0);
|
|
|
|
assert(date.diffMonths(idate) == 0);
|
|
assert(cdate.diffMonths(idate) == 0);
|
|
assert(idate.diffMonths(idate) == 0);
|
|
}
|
|
|
|
|
|
/++
|
|
Whether this $(LREF Date) is in a leap year.
|
|
+/
|
|
@property bool isLeapYear() const @safe pure nothrow @nogc
|
|
{
|
|
return yearIsLeapYear(_year);
|
|
}
|
|
|
|
@safe 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() const @safe pure nothrow @nogc
|
|
{
|
|
return getDayOfWeek(dayOfGregorianCal);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
const cdate = Date(1999, 7, 6);
|
|
immutable idate = Date(1999, 7, 6);
|
|
assert(cdate.dayOfWeek == DayOfWeek.tue);
|
|
static assert(!__traits(compiles, cdate.dayOfWeek = DayOfWeek.sun));
|
|
assert(idate.dayOfWeek == DayOfWeek.tue);
|
|
static assert(!__traits(compiles, idate.dayOfWeek = DayOfWeek.sun));
|
|
}
|
|
|
|
|
|
/++
|
|
Day of the year this $(LREF Date) is on.
|
|
+/
|
|
@property ushort dayOfYear() const @safe pure nothrow @nogc
|
|
{
|
|
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.");
|
|
}
|
|
|
|
///
|
|
@safe unittest
|
|
{
|
|
assert(Date(1999, 1, 1).dayOfYear == 1);
|
|
assert(Date(1999, 12, 31).dayOfYear == 365);
|
|
assert(Date(2000, 12, 31).dayOfYear == 366);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
import std.algorithm.iteration : filter;
|
|
import std.range : chain;
|
|
|
|
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);
|
|
assert(cdate.dayOfYear == 187);
|
|
assert(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:
|
|
$(REF DateTimeException,std,datetime,date) if the given day is an
|
|
invalid day of the year.
|
|
+/
|
|
@property void dayOfYear(int day) @safe pure
|
|
{
|
|
setDayOfYear!true(day);
|
|
}
|
|
|
|
private void setDayOfYear(bool useExceptions = false)(int day)
|
|
{
|
|
immutable int[] lastDay = isLeapYear ? lastDayLeap : lastDayNonLeap;
|
|
|
|
bool dayOutOfRange = day <= 0 || day > (isLeapYear ? daysInLeapYear : daysInYear);
|
|
enum errorMsg = "Invalid day of the year.";
|
|
|
|
static if (useExceptions)
|
|
{
|
|
if (dayOutOfRange) throw new DateTimeException(errorMsg);
|
|
}
|
|
else
|
|
{
|
|
assert(!dayOutOfRange, errorMsg);
|
|
}
|
|
|
|
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.");
|
|
}
|
|
|
|
@safe 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() const @safe pure nothrow @nogc
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
///
|
|
@safe 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);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
import std.range : chain;
|
|
|
|
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);
|
|
assert(date.dayOfGregorianCal == 729_941);
|
|
assert(cdate.dayOfGregorianCal == 729_941);
|
|
assert(idate.dayOfGregorianCal == 729_941);
|
|
}
|
|
|
|
/++
|
|
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 @nogc
|
|
{
|
|
this = Date(day);
|
|
}
|
|
|
|
///
|
|
@safe 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));
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
const cdate = Date(1999, 7, 6);
|
|
immutable idate = Date(1999, 7, 6);
|
|
date.dayOfGregorianCal = 187;
|
|
assert(date.dayOfGregorianCal == 187);
|
|
static assert(!__traits(compiles, cdate.dayOfGregorianCal = 187));
|
|
static assert(!__traits(compiles, idate.dayOfGregorianCal = 187));
|
|
}
|
|
|
|
|
|
/++
|
|
The ISO 8601 week and year of the year that this $(LREF Date) is in.
|
|
|
|
Returns:
|
|
An anonymous struct with the members $(D isoWeekYear) for the
|
|
resulting year and $(D isoWeek) for the resulting ISO week.
|
|
|
|
See_Also:
|
|
$(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date)
|
|
+/
|
|
@property auto isoWeekAndYear() const @safe pure nothrow
|
|
{
|
|
struct ISOWeekAndYear { short isoWeekYear; ubyte isoWeek; }
|
|
|
|
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 ISOWeekAndYear(cast(short) (_year + 1), 1);
|
|
case DayOfWeek.fri:
|
|
case DayOfWeek.sat:
|
|
case DayOfWeek.sun:
|
|
return ISOWeekAndYear(_year, 53);
|
|
default:
|
|
assert(0, "Invalid ISO Week");
|
|
}
|
|
}
|
|
else if (week > 0)
|
|
return ISOWeekAndYear(_year, cast(ubyte) week);
|
|
else
|
|
return Date(_year - 1, 12, 31).isoWeekAndYear;
|
|
}
|
|
catch (Exception e)
|
|
assert(0, "Date's constructor threw.");
|
|
}
|
|
|
|
/++
|
|
The ISO 8601 week of the year that this $(LREF Date) is in.
|
|
|
|
See_Also:
|
|
$(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date)
|
|
+/
|
|
@property ubyte isoWeek() const @safe pure nothrow
|
|
{
|
|
return isoWeekAndYear().isoWeek;
|
|
}
|
|
|
|
@safe 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);
|
|
assert(cdate.isoWeek == 27);
|
|
static assert(!__traits(compiles, cdate.isoWeek = 3));
|
|
assert(idate.isoWeek == 27);
|
|
static assert(!__traits(compiles, idate.isoWeek = 3));
|
|
}
|
|
|
|
/++
|
|
The year inside the ISO 8601 week calendar that this $(LREF Date) is in.
|
|
|
|
May differ from $(LREF year) between 28 December and 4 January.
|
|
|
|
See_Also:
|
|
$(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date)
|
|
+/
|
|
@property short isoWeekYear() const @safe pure nothrow
|
|
{
|
|
return isoWeekAndYear().isoWeekYear;
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
// Test A.D.
|
|
assert(Date(2009, 12, 28).isoWeekYear == 2009);
|
|
assert(Date(2009, 12, 29).isoWeekYear == 2009);
|
|
assert(Date(2009, 12, 30).isoWeekYear == 2009);
|
|
assert(Date(2009, 12, 31).isoWeekYear == 2009);
|
|
assert(Date(2010, 1, 1).isoWeekYear == 2009);
|
|
assert(Date(2010, 1, 2).isoWeekYear == 2009);
|
|
assert(Date(2010, 1, 3).isoWeekYear == 2009);
|
|
assert(Date(2010, 1, 4).isoWeekYear == 2010);
|
|
assert(Date(2010, 1, 5).isoWeekYear == 2010);
|
|
assert(Date(2010, 1, 6).isoWeekYear == 2010);
|
|
assert(Date(2010, 1, 7).isoWeekYear == 2010);
|
|
assert(Date(2010, 1, 8).isoWeekYear == 2010);
|
|
assert(Date(2010, 1, 9).isoWeekYear == 2010);
|
|
assert(Date(2010, 1, 10).isoWeekYear == 2010);
|
|
assert(Date(2010, 1, 11).isoWeekYear == 2010);
|
|
assert(Date(2010, 12, 31).isoWeekYear == 2010);
|
|
|
|
assert(Date(2004, 12, 26).isoWeekYear == 2004);
|
|
assert(Date(2004, 12, 27).isoWeekYear == 2004);
|
|
assert(Date(2004, 12, 28).isoWeekYear == 2004);
|
|
assert(Date(2004, 12, 29).isoWeekYear == 2004);
|
|
assert(Date(2004, 12, 30).isoWeekYear == 2004);
|
|
assert(Date(2004, 12, 31).isoWeekYear == 2004);
|
|
assert(Date(2005, 1, 1).isoWeekYear == 2004);
|
|
assert(Date(2005, 1, 2).isoWeekYear == 2004);
|
|
assert(Date(2005, 1, 3).isoWeekYear == 2005);
|
|
|
|
assert(Date(2005, 12, 31).isoWeekYear == 2005);
|
|
assert(Date(2007, 1, 1).isoWeekYear == 2007);
|
|
|
|
assert(Date(2007, 12, 30).isoWeekYear == 2007);
|
|
assert(Date(2007, 12, 31).isoWeekYear == 2008);
|
|
assert(Date(2008, 1, 1).isoWeekYear == 2008);
|
|
|
|
assert(Date(2008, 12, 28).isoWeekYear == 2008);
|
|
assert(Date(2008, 12, 29).isoWeekYear == 2009);
|
|
assert(Date(2008, 12, 30).isoWeekYear == 2009);
|
|
assert(Date(2008, 12, 31).isoWeekYear == 2009);
|
|
assert(Date(2009, 1, 1).isoWeekYear == 2009);
|
|
assert(Date(2009, 1, 2).isoWeekYear == 2009);
|
|
assert(Date(2009, 1, 3).isoWeekYear == 2009);
|
|
assert(Date(2009, 1, 4).isoWeekYear == 2009);
|
|
|
|
// Test B.C.
|
|
assert(Date(0, 12, 31).isoWeekYear == 0);
|
|
assert(Date(0, 1, 4).isoWeekYear == 0);
|
|
assert(Date(0, 1, 1).isoWeekYear == -1);
|
|
|
|
const cdate = Date(1999, 7, 6);
|
|
immutable idate = Date(1999, 7, 6);
|
|
assert(cdate.isoWeekYear == 1999);
|
|
assert(idate.isoWeekYear == 1999);
|
|
}
|
|
|
|
static Date fromISOWeek(short isoWeekYear, ubyte isoWeek, DayOfWeek weekday) @safe pure nothrow @nogc
|
|
{
|
|
immutable adjustedWeekday = weekday == DayOfWeek.sun ? 7 : weekday;
|
|
immutable dayOffset = (isoWeek - 1) * 7 + adjustedWeekday;
|
|
|
|
Date date;
|
|
date._year = isoWeekYear;
|
|
date._month = Month.jan;
|
|
date._day = 3;
|
|
immutable startOfYear = date.dayOfWeek;
|
|
return date._addDays(dayOffset - startOfYear);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
// Test -30000 days to 30000 days for matching construction <-> deconstruction
|
|
Date date = Date(1, 1, 1);
|
|
date._addDays(-30_000);
|
|
foreach (day; 0 .. 60_000)
|
|
{
|
|
const year = date.isoWeekYear;
|
|
const dow = date.dayOfWeek;
|
|
const isoWeek = date.isoWeek;
|
|
const reversed = Date.fromISOWeek(year, isoWeek, dow);
|
|
assert(reversed == date, date.toISOExtString ~ " != " ~ reversed.toISOExtString);
|
|
date = date._addDays(1);
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
$(LREF Date) for the last day in the month that this $(LREF Date) is in.
|
|
+/
|
|
@property Date endOfMonth() const @safe pure nothrow
|
|
{
|
|
try
|
|
return Date(_year, _month, maxDay(_year, _month));
|
|
catch (Exception e)
|
|
assert(0, "Date's constructor threw.");
|
|
}
|
|
|
|
///
|
|
@safe 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));
|
|
}
|
|
|
|
@safe 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() const @safe pure nothrow @nogc
|
|
{
|
|
return maxDay(_year, _month);
|
|
}
|
|
|
|
///
|
|
@safe 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);
|
|
}
|
|
|
|
@safe 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() const @safe pure nothrow @nogc
|
|
{
|
|
return _year > 0;
|
|
}
|
|
|
|
///
|
|
@safe 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);
|
|
}
|
|
|
|
@safe 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);
|
|
assert(cdate.isAD);
|
|
assert(idate.isAD);
|
|
}
|
|
|
|
|
|
/++
|
|
The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for this
|
|
$(LREF Date) at noon (since the Julian day changes at noon).
|
|
+/
|
|
@property long julianDay() const @safe pure nothrow @nogc
|
|
{
|
|
return dayOfGregorianCal + 1_721_425;
|
|
}
|
|
|
|
@safe 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);
|
|
assert(cdate.julianDay == 2_451_366);
|
|
assert(idate.julianDay == 2_451_366);
|
|
}
|
|
|
|
|
|
/++
|
|
The modified $(HTTP 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() const @safe pure nothrow @nogc
|
|
{
|
|
return julianDay - 2_400_001;
|
|
}
|
|
|
|
@safe 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);
|
|
assert(cdate.modJulianDay == 51_365);
|
|
assert(idate.modJulianDay == 51_365);
|
|
}
|
|
|
|
|
|
/++
|
|
Converts this $(LREF Date) to a string with the format `YYYYMMDD`.
|
|
If `writer` is set, the resulting string will be written directly
|
|
to it.
|
|
|
|
Params:
|
|
writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
|
|
Returns:
|
|
A `string` when not using an output range; `void` otherwise.
|
|
+/
|
|
string toISOString() const @safe pure nothrow
|
|
{
|
|
import std.array : appender;
|
|
auto w = appender!string();
|
|
w.reserve(8);
|
|
try
|
|
toISOString(w);
|
|
catch (Exception e)
|
|
assert(0, "toISOString() threw.");
|
|
return w.data;
|
|
}
|
|
|
|
///
|
|
@safe 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");
|
|
}
|
|
|
|
@safe 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);
|
|
assert(cdate.toISOString() == "19990706");
|
|
assert(idate.toISOString() == "19990706");
|
|
}
|
|
|
|
/// ditto
|
|
void toISOString(W)(ref W writer) const
|
|
if (isOutputRange!(W, char))
|
|
{
|
|
import std.format.write : formattedWrite;
|
|
if (_year >= 0)
|
|
{
|
|
if (_year < 10_000)
|
|
formattedWrite(writer, "%04d%02d%02d", _year, _month, _day);
|
|
else
|
|
formattedWrite(writer, "+%05d%02d%02d", _year, _month, _day);
|
|
}
|
|
else if (_year > -10_000)
|
|
formattedWrite(writer, "%05d%02d%02d", _year, _month, _day);
|
|
else
|
|
formattedWrite(writer, "%06d%02d%02d", _year, _month, _day);
|
|
}
|
|
|
|
@safe pure unittest
|
|
{
|
|
import std.array : appender;
|
|
|
|
auto w = appender!(char[])();
|
|
Date(2010, 7, 4).toISOString(w);
|
|
assert(w.data == "20100704");
|
|
w.clear();
|
|
Date(1998, 12, 25).toISOString(w);
|
|
assert(w.data == "19981225");
|
|
}
|
|
|
|
/++
|
|
Converts this $(LREF Date) to a string with the format `YYYY-MM-DD`.
|
|
If `writer` is set, the resulting string will be written directly
|
|
to it.
|
|
|
|
Params:
|
|
writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
|
|
Returns:
|
|
A `string` when not using an output range; `void` otherwise.
|
|
+/
|
|
string toISOExtString() const @safe pure nothrow
|
|
{
|
|
import std.array : appender;
|
|
auto w = appender!string();
|
|
w.reserve(10);
|
|
try
|
|
toISOExtString(w);
|
|
catch (Exception e)
|
|
assert(0, "toISOExtString() threw.");
|
|
return w.data;
|
|
}
|
|
|
|
///
|
|
@safe 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");
|
|
}
|
|
|
|
@safe 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);
|
|
assert(cdate.toISOExtString() == "1999-07-06");
|
|
assert(idate.toISOExtString() == "1999-07-06");
|
|
}
|
|
|
|
/// ditto
|
|
void toISOExtString(W)(ref W writer) const
|
|
if (isOutputRange!(W, char))
|
|
{
|
|
import std.format.write : formattedWrite;
|
|
if (_year >= 0)
|
|
{
|
|
if (_year < 10_000)
|
|
formattedWrite(writer, "%04d-%02d-%02d", _year, _month, _day);
|
|
else
|
|
formattedWrite(writer, "+%05d-%02d-%02d", _year, _month, _day);
|
|
}
|
|
else if (_year > -10_000)
|
|
formattedWrite(writer, "%05d-%02d-%02d", _year, _month, _day);
|
|
else
|
|
formattedWrite(writer, "%06d-%02d-%02d", _year, _month, _day);
|
|
}
|
|
|
|
@safe pure unittest
|
|
{
|
|
import std.array : appender;
|
|
|
|
auto w = appender!(char[])();
|
|
Date(2010, 7, 4).toISOExtString(w);
|
|
assert(w.data == "2010-07-04");
|
|
w.clear();
|
|
Date(-4, 1, 5).toISOExtString(w);
|
|
assert(w.data == "-0004-01-05");
|
|
}
|
|
|
|
/++
|
|
Converts this $(LREF Date) to a string with the format `YYYY-Mon-DD`.
|
|
If `writer` is set, the resulting string will be written directly
|
|
to it.
|
|
|
|
Params:
|
|
writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
|
|
Returns:
|
|
A `string` when not using an output range; `void` otherwise.
|
|
+/
|
|
string toSimpleString() const @safe pure nothrow
|
|
{
|
|
import std.array : appender;
|
|
auto w = appender!string();
|
|
w.reserve(11);
|
|
try
|
|
toSimpleString(w);
|
|
catch (Exception e)
|
|
assert(0, "toSimpleString() threw.");
|
|
return w.data;
|
|
}
|
|
|
|
///
|
|
@safe 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");
|
|
}
|
|
|
|
@safe 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);
|
|
assert(cdate.toSimpleString() == "1999-Jul-06");
|
|
assert(idate.toSimpleString() == "1999-Jul-06");
|
|
}
|
|
|
|
/// ditto
|
|
void toSimpleString(W)(ref W writer) const
|
|
if (isOutputRange!(W, char))
|
|
{
|
|
import std.format.write : formattedWrite;
|
|
if (_year >= 0)
|
|
{
|
|
if (_year < 10_000)
|
|
formattedWrite(writer, "%04d-%s-%02d", _year, monthToString(_month), _day);
|
|
else
|
|
formattedWrite(writer, "+%05d-%s-%02d", _year, monthToString(_month), _day);
|
|
}
|
|
else if (_year > -10_000)
|
|
formattedWrite(writer, "%05d-%s-%02d", _year, monthToString(_month), _day);
|
|
else
|
|
formattedWrite(writer, "%06d-%s-%02d", _year, monthToString(_month), _day);
|
|
}
|
|
|
|
@safe pure unittest
|
|
{
|
|
import std.array : appender;
|
|
|
|
auto w = appender!(char[])();
|
|
Date(9, 12, 4).toSimpleString(w);
|
|
assert(w.data == "0009-Dec-04");
|
|
w.clear();
|
|
Date(-10000, 10, 20).toSimpleString(w);
|
|
assert(w.data == "-10000-Oct-20");
|
|
}
|
|
|
|
/++
|
|
Converts this $(LREF Date) to a string.
|
|
|
|
This function exists to make it easy to convert a $(LREF Date) to a
|
|
string for code that does not care what the exact format is - just that
|
|
it presents the information in a clear manner. It also makes it easy to
|
|
simply convert a $(LREF Date) to a string when using functions such as
|
|
`to!string`, `format`, or `writeln` which use toString to convert
|
|
user-defined types. So, it is unlikely that much code will call
|
|
toString directly.
|
|
|
|
The format of the string is purposefully unspecified, and code that
|
|
cares about the format of the string should use `toISOString`,
|
|
`toISOExtString`, `toSimpleString`, or some other custom formatting
|
|
function that explicitly generates the format that the code needs. The
|
|
reason is that the code is then clear about what format it's using,
|
|
making it less error-prone to maintain the code and interact with other
|
|
software that consumes the generated strings. It's for this same reason
|
|
$(LREF Date) has no `fromString` function, whereas it does have
|
|
`fromISOString`, `fromISOExtString`, and `fromSimpleString`.
|
|
|
|
The format returned by toString may or may not change in the future.
|
|
+/
|
|
string toString() const @safe pure nothrow
|
|
{
|
|
return toSimpleString();
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
auto date = Date(1999, 7, 6);
|
|
const cdate = Date(1999, 7, 6);
|
|
immutable idate = Date(1999, 7, 6);
|
|
assert(date.toString());
|
|
assert(cdate.toString());
|
|
assert(idate.toString());
|
|
}
|
|
|
|
/// ditto
|
|
void toString(W)(ref W writer) const
|
|
if (isOutputRange!(W, char))
|
|
{
|
|
toSimpleString(writer);
|
|
}
|
|
|
|
/++
|
|
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:
|
|
$(REF DateTimeException,std,datetime,date) if the given string is
|
|
not in the ISO format or if the resulting $(LREF Date) would not be
|
|
valid.
|
|
+/
|
|
static Date fromISOString(S)(scope const S isoString) @safe pure
|
|
if (isSomeString!S)
|
|
{
|
|
import std.algorithm.searching : startsWith;
|
|
import std.conv : to, text, ConvException;
|
|
import std.exception : enforce;
|
|
import std.string : strip;
|
|
|
|
auto str = isoString.strip;
|
|
|
|
enforce!DateTimeException(str.length >= 8, text("Invalid format for Date.fromISOString: ", isoString));
|
|
|
|
int day, month, year;
|
|
auto yearStr = str[0 .. $ - 4];
|
|
|
|
try
|
|
{
|
|
// using conversion to uint plus cast because it checks for +/-
|
|
// for us quickly while throwing ConvException
|
|
day = cast(int) to!uint(str[$ - 2 .. $]);
|
|
month = cast(int) to!uint(str[$ - 4 .. $ - 2]);
|
|
|
|
if (yearStr.length > 4)
|
|
{
|
|
enforce!DateTimeException(yearStr.startsWith('-', '+'),
|
|
text("Invalid format for Date.fromISOString: ", isoString));
|
|
year = to!int(yearStr);
|
|
}
|
|
else
|
|
{
|
|
year = cast(int) to!uint(yearStr);
|
|
}
|
|
}
|
|
catch (ConvException)
|
|
{
|
|
throw new DateTimeException(text("Invalid format for Date.fromISOString: ", isoString));
|
|
}
|
|
|
|
return Date(year, month, day);
|
|
}
|
|
|
|
///
|
|
@safe 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));
|
|
}
|
|
|
|
@safe 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));
|
|
}
|
|
|
|
// https://issues.dlang.org/show_bug.cgi?id=17801
|
|
@safe unittest
|
|
{
|
|
import std.conv : to;
|
|
import std.meta : AliasSeq;
|
|
static foreach (C; AliasSeq!(char, wchar, dchar))
|
|
{
|
|
static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
|
|
assert(Date.fromISOString(to!S("20121221")) == Date(2012, 12, 21));
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
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:
|
|
$(REF DateTimeException,std,datetime,date) 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)(scope const S isoExtString) @safe pure
|
|
if (isSomeString!(S))
|
|
{
|
|
import std.algorithm.searching : startsWith;
|
|
import std.conv : to, ConvException;
|
|
import std.format : format;
|
|
import std.string : strip;
|
|
|
|
auto str = strip(isoExtString);
|
|
short year;
|
|
ubyte month, day;
|
|
|
|
if (str.length < 10 || str[$-3] != '-' || str[$-6] != '-')
|
|
throw new DateTimeException(format("Invalid format for Date.fromISOExtString: %s", isoExtString));
|
|
|
|
auto yearStr = str[0 .. $-6];
|
|
auto signAtBegining = cast(bool) yearStr.startsWith('-', '+');
|
|
if ((yearStr.length > 4) != signAtBegining)
|
|
{
|
|
throw new DateTimeException(format("Invalid format for Date.fromISOExtString: %s", isoExtString));
|
|
}
|
|
|
|
try
|
|
{
|
|
day = to!ubyte(str[$-2 .. $]);
|
|
month = to!ubyte(str[$-5 .. $-3]);
|
|
year = to!short(yearStr);
|
|
}
|
|
catch (ConvException)
|
|
{
|
|
throw new DateTimeException(format("Invalid format for Date.fromISOExtString: %s", isoExtString));
|
|
}
|
|
|
|
return Date(year, month, day);
|
|
}
|
|
|
|
///
|
|
@safe 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));
|
|
}
|
|
|
|
@safe 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));
|
|
}
|
|
|
|
// https://issues.dlang.org/show_bug.cgi?id=17801
|
|
@safe unittest
|
|
{
|
|
import std.conv : to;
|
|
import std.meta : AliasSeq;
|
|
static foreach (C; AliasSeq!(char, wchar, dchar))
|
|
{
|
|
static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
|
|
assert(Date.fromISOExtString(to!S("2012-12-21")) == Date(2012, 12, 21));
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
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:
|
|
$(REF DateTimeException,std,datetime,date) if the given string is
|
|
not in the correct format or if the resulting $(LREF Date) would not
|
|
be valid.
|
|
+/
|
|
static Date fromSimpleString(S)(scope const S simpleString) @safe pure
|
|
if (isSomeString!(S))
|
|
{
|
|
import std.algorithm.searching : startsWith;
|
|
import std.conv : to, ConvException;
|
|
import std.format : format;
|
|
import std.string : strip;
|
|
|
|
auto str = strip(simpleString);
|
|
|
|
if (str.length < 11 || str[$-3] != '-' || str[$-7] != '-')
|
|
throw new DateTimeException(format!"Invalid format for Date.fromSimpleString: %s"(simpleString));
|
|
|
|
int year;
|
|
uint day;
|
|
auto month = monthFromString(str[$ - 6 .. $ - 3]);
|
|
auto yearStr = str[0 .. $ - 7];
|
|
auto signAtBegining = cast(bool) yearStr.startsWith('-', '+');
|
|
if ((yearStr.length > 4) != signAtBegining)
|
|
{
|
|
throw new DateTimeException(format!"Invalid format for Date.fromSimpleString: %s"(simpleString));
|
|
}
|
|
|
|
try
|
|
{
|
|
day = to!uint(str[$ - 2 .. $]);
|
|
year = to!int(yearStr);
|
|
}
|
|
catch (ConvException)
|
|
{
|
|
throw new DateTimeException(format!"Invalid format for Date.fromSimpleString: %s"(simpleString));
|
|
}
|
|
|
|
return Date(year, month, day);
|
|
}
|
|
|
|
///
|
|
@safe 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));
|
|
}
|
|
|
|
@safe 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));
|
|
}
|
|
|
|
// https://issues.dlang.org/show_bug.cgi?id=17801
|
|
@safe unittest
|
|
{
|
|
import std.conv : to;
|
|
import std.meta : AliasSeq;
|
|
static foreach (C; AliasSeq!(char, wchar, dchar))
|
|
{
|
|
static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
|
|
assert(Date.fromSimpleString(to!S("2012-Dec-21")) == Date(2012, 12, 21));
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
Returns the $(LREF Date) farthest in the past which is representable by
|
|
$(LREF Date).
|
|
+/
|
|
@property static Date min() @safe pure nothrow @nogc
|
|
{
|
|
auto date = Date.init;
|
|
date._year = short.min;
|
|
date._month = Month.jan;
|
|
date._day = 1;
|
|
|
|
return date;
|
|
}
|
|
|
|
@safe 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 @nogc
|
|
{
|
|
auto date = Date.init;
|
|
date._year = short.max;
|
|
date._month = Month.dec;
|
|
date._day = 31;
|
|
|
|
return date;
|
|
}
|
|
|
|
@safe 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 @nogc
|
|
{
|
|
if (!valid!"months"(month))
|
|
return false;
|
|
return valid!"days"(year, month, day);
|
|
}
|
|
|
|
|
|
package:
|
|
|
|
/+
|
|
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.
|
|
|
|
`_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 @nogc
|
|
{
|
|
dayOfGregorianCal = cast(int)(dayOfGregorianCal + days);
|
|
return this;
|
|
}
|
|
|
|
@safe 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;
|
|
}
|
|
|
|
///
|
|
@safe pure unittest
|
|
{
|
|
import core.time : days;
|
|
|
|
auto d = Date(2000, 6, 1);
|
|
|
|
assert(d.dayOfYear == 153);
|
|
assert(d.dayOfWeek == DayOfWeek.thu);
|
|
|
|
d += 10.days;
|
|
assert(d == Date(2000, 6, 11));
|
|
|
|
assert(d.toISOExtString() == "2000-06-11");
|
|
assert(d.toISOString() == "20000611");
|
|
assert(d.toSimpleString() == "2000-Jun-11");
|
|
|
|
assert(Date.fromISOExtString("2018-01-01") == Date(2018, 1, 1));
|
|
assert(Date.fromISOString("20180101") == Date(2018, 1, 1));
|
|
assert(Date.fromSimpleString("2018-Jan-01") == Date(2018, 1, 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:
|
|
$(REF DateTimeException,std,datetime,date) 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;
|
|
}
|
|
|
|
@safe 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(TimeOfDay rhs) const @safe pure nothrow @nogc
|
|
{
|
|
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;
|
|
}
|
|
|
|
@safe 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);
|
|
assert(ctod.opCmp(itod) == 0);
|
|
assert(itod.opCmp(ctod) == 0);
|
|
}
|
|
|
|
|
|
/++
|
|
Hours past midnight.
|
|
+/
|
|
@property ubyte hour() const @safe pure nothrow @nogc
|
|
{
|
|
return _hour;
|
|
}
|
|
|
|
@safe 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);
|
|
assert(ctod.hour == 12);
|
|
assert(itod.hour == 12);
|
|
}
|
|
|
|
|
|
/++
|
|
Hours past midnight.
|
|
|
|
Params:
|
|
hour = The hour of the day to set this $(LREF TimeOfDay)'s hour to.
|
|
|
|
Throws:
|
|
$(REF DateTimeException,std,datetime,date) 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;
|
|
}
|
|
|
|
@safe 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() const @safe pure nothrow @nogc
|
|
{
|
|
return _minute;
|
|
}
|
|
|
|
@safe 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);
|
|
assert(ctod.minute == 30);
|
|
assert(itod.minute == 30);
|
|
}
|
|
|
|
|
|
/++
|
|
Minutes past the hour.
|
|
|
|
Params:
|
|
minute = The minute to set this $(LREF TimeOfDay)'s minute to.
|
|
|
|
Throws:
|
|
$(REF DateTimeException,std,datetime,date) 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;
|
|
}
|
|
|
|
@safe 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() const @safe pure nothrow @nogc
|
|
{
|
|
return _second;
|
|
}
|
|
|
|
@safe 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);
|
|
assert(ctod.second == 33);
|
|
assert(itod.second == 33);
|
|
}
|
|
|
|
|
|
/++
|
|
Seconds past the minute.
|
|
|
|
Params:
|
|
second = The second to set this $(LREF TimeOfDay)'s second to.
|
|
|
|
Throws:
|
|
$(REF DateTimeException,std,datetime,date) 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;
|
|
}
|
|
|
|
@safe 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), mutating it. 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 `"hours"`, `"minutes"`, and `"seconds"`.
|
|
|
|
Params:
|
|
units = The units to add.
|
|
value = The number of $(D_PARAM units) to add to this
|
|
$(LREF TimeOfDay).
|
|
|
|
Returns:
|
|
A reference to the `TimeOfDay` (`this`).
|
|
+/
|
|
ref TimeOfDay roll(string units)(long value) @safe pure nothrow @nogc
|
|
if (units == "hours")
|
|
{
|
|
import core.time : dur;
|
|
return this += dur!"hours"(value);
|
|
}
|
|
|
|
///
|
|
@safe 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));
|
|
}
|
|
|
|
@safe 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)));
|
|
}
|
|
|
|
|
|
/// ditto
|
|
ref TimeOfDay roll(string units)(long value) @safe pure nothrow @nogc
|
|
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"().
|
|
@safe unittest
|
|
{
|
|
static void testTOD(TimeOfDay orig, int minutes, 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"().
|
|
@safe unittest
|
|
{
|
|
static void testTOD(TimeOfDay orig, int seconds, 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)));
|
|
}
|
|
|
|
|
|
import core.time : Duration;
|
|
/++
|
|
Gives the result of adding or subtracting a $(REF Duration, core,time)
|
|
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 $(REF Duration, core,time) to add to or subtract from
|
|
this $(LREF TimeOfDay).
|
|
+/
|
|
TimeOfDay opBinary(string op)(Duration duration) const @safe pure nothrow @nogc
|
|
if (op == "+" || op == "-")
|
|
{
|
|
TimeOfDay retval = this;
|
|
immutable seconds = duration.total!"seconds";
|
|
mixin("return retval._addSeconds(" ~ op ~ "seconds);");
|
|
}
|
|
|
|
///
|
|
@safe unittest
|
|
{
|
|
import core.time : hours, minutes, seconds;
|
|
|
|
assert(TimeOfDay(12, 12, 12) + seconds(1) == TimeOfDay(12, 12, 13));
|
|
assert(TimeOfDay(12, 12, 12) + minutes(1) == TimeOfDay(12, 13, 12));
|
|
assert(TimeOfDay(12, 12, 12) + hours(1) == TimeOfDay(13, 12, 12));
|
|
assert(TimeOfDay(23, 59, 59) + seconds(1) == TimeOfDay(0, 0, 0));
|
|
|
|
assert(TimeOfDay(12, 12, 12) - seconds(1) == TimeOfDay(12, 12, 11));
|
|
assert(TimeOfDay(12, 12, 12) - minutes(1) == TimeOfDay(12, 11, 12));
|
|
assert(TimeOfDay(12, 12, 12) - hours(1) == TimeOfDay(11, 12, 12));
|
|
assert(TimeOfDay(0, 0, 0) - seconds(1) == TimeOfDay(23, 59, 59));
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
auto tod = TimeOfDay(12, 30, 33);
|
|
|
|
import core.time : dur;
|
|
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));
|
|
|
|
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));
|
|
|
|
auto duration = dur!"hours"(11);
|
|
const ctod = TimeOfDay(12, 30, 33);
|
|
immutable itod = TimeOfDay(12, 30, 33);
|
|
assert(tod + duration == TimeOfDay(23, 30, 33));
|
|
assert(ctod + duration == TimeOfDay(23, 30, 33));
|
|
assert(itod + duration == TimeOfDay(23, 30, 33));
|
|
|
|
assert(tod - duration == TimeOfDay(1, 30, 33));
|
|
assert(ctod - duration == TimeOfDay(1, 30, 33));
|
|
assert(itod - duration == TimeOfDay(1, 30, 33));
|
|
}
|
|
|
|
|
|
/++
|
|
Gives the result of adding or subtracting a $(REF Duration, core,time)
|
|
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 $(REF Duration, core,time) to add to or subtract from
|
|
this $(LREF TimeOfDay).
|
|
+/
|
|
ref TimeOfDay opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc
|
|
if (op == "+" || op == "-")
|
|
{
|
|
immutable seconds = duration.total!"seconds";
|
|
mixin("return _addSeconds(" ~ op ~ "seconds);");
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
import core.time : dur;
|
|
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)(TimeOfDay rhs) const @safe pure nothrow @nogc
|
|
if (op == "-")
|
|
{
|
|
immutable lhsSec = _hour * 3600 + _minute * 60 + _second;
|
|
immutable rhsSec = rhs._hour * 3600 + rhs._minute * 60 + rhs._second;
|
|
|
|
import core.time : dur;
|
|
return dur!"seconds"(lhsSec - rhsSec);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
auto tod = TimeOfDay(12, 30, 33);
|
|
|
|
import core.time : dur;
|
|
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);
|
|
assert(tod - tod == Duration.zero);
|
|
assert(ctod - tod == Duration.zero);
|
|
assert(itod - tod == Duration.zero);
|
|
|
|
assert(tod - ctod == Duration.zero);
|
|
assert(ctod - ctod == Duration.zero);
|
|
assert(itod - ctod == Duration.zero);
|
|
|
|
assert(tod - itod == Duration.zero);
|
|
assert(ctod - itod == Duration.zero);
|
|
assert(itod - itod == Duration.zero);
|
|
}
|
|
|
|
|
|
/++
|
|
Converts this $(LREF TimeOfDay) to a string with the format `HHMMSS`.
|
|
If `writer` is set, the resulting string will be written directly to it.
|
|
|
|
Params:
|
|
writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
|
|
Returns:
|
|
A `string` when not using an output range; `void` otherwise.
|
|
+/
|
|
string toISOString() const @safe pure nothrow
|
|
{
|
|
import std.array : appender;
|
|
auto w = appender!string();
|
|
w.reserve(6);
|
|
try
|
|
toISOString(w);
|
|
catch (Exception e)
|
|
assert(0, "toISOString() threw.");
|
|
return w.data;
|
|
}
|
|
|
|
/// ditto
|
|
void toISOString(W)(ref W writer) const
|
|
if (isOutputRange!(W, char))
|
|
{
|
|
import std.format.write : formattedWrite;
|
|
formattedWrite(writer, "%02d%02d%02d", _hour, _minute, _second);
|
|
}
|
|
|
|
///
|
|
@safe unittest
|
|
{
|
|
assert(TimeOfDay(0, 0, 0).toISOString() == "000000");
|
|
assert(TimeOfDay(12, 30, 33).toISOString() == "123033");
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
auto tod = TimeOfDay(12, 30, 33);
|
|
const ctod = TimeOfDay(12, 30, 33);
|
|
immutable itod = TimeOfDay(12, 30, 33);
|
|
assert(tod.toISOString() == "123033");
|
|
assert(ctod.toISOString() == "123033");
|
|
assert(itod.toISOString() == "123033");
|
|
}
|
|
|
|
|
|
/++
|
|
Converts this $(LREF TimeOfDay) to a string with the format `HH:MM:SS`.
|
|
If `writer` is set, the resulting string will be written directly to it.
|
|
|
|
Params:
|
|
writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
|
|
Returns:
|
|
A `string` when not using an output range; `void` otherwise.
|
|
+/
|
|
string toISOExtString() const @safe pure nothrow
|
|
{
|
|
import std.array : appender;
|
|
auto w = appender!string();
|
|
w.reserve(8);
|
|
try
|
|
toISOExtString(w);
|
|
catch (Exception e)
|
|
assert(0, "toISOExtString() threw.");
|
|
return w.data;
|
|
}
|
|
|
|
/// ditto
|
|
void toISOExtString(W)(ref W writer) const
|
|
if (isOutputRange!(W, char))
|
|
{
|
|
import std.format.write : formattedWrite;
|
|
formattedWrite(writer, "%02d:%02d:%02d", _hour, _minute, _second);
|
|
}
|
|
|
|
///
|
|
@safe unittest
|
|
{
|
|
assert(TimeOfDay(0, 0, 0).toISOExtString() == "00:00:00");
|
|
assert(TimeOfDay(12, 30, 33).toISOExtString() == "12:30:33");
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
auto tod = TimeOfDay(12, 30, 33);
|
|
const ctod = TimeOfDay(12, 30, 33);
|
|
immutable itod = TimeOfDay(12, 30, 33);
|
|
assert(tod.toISOExtString() == "12:30:33");
|
|
assert(ctod.toISOExtString() == "12:30:33");
|
|
assert(itod.toISOExtString() == "12:30:33");
|
|
}
|
|
|
|
|
|
/++
|
|
Converts this TimeOfDay to a string.
|
|
|
|
This function exists to make it easy to convert a $(LREF TimeOfDay) to a
|
|
string for code that does not care what the exact format is - just that
|
|
it presents the information in a clear manner. It also makes it easy to
|
|
simply convert a $(LREF TimeOfDay) to a string when using functions such
|
|
as `to!string`, `format`, or `writeln` which use toString to convert
|
|
user-defined types. So, it is unlikely that much code will call
|
|
toString directly.
|
|
|
|
The format of the string is purposefully unspecified, and code that
|
|
cares about the format of the string should use `toISOString`,
|
|
`toISOExtString`, or some other custom formatting function that
|
|
explicitly generates the format that the code needs. The reason is that
|
|
the code is then clear about what format it's using, making it less
|
|
error-prone to maintain the code and interact with other software that
|
|
consumes the generated strings. It's for this same reason that
|
|
$(LREF TimeOfDay) has no `fromString` function, whereas it does have
|
|
`fromISOString` and `fromISOExtString`.
|
|
|
|
The format returned by toString may or may not change in the future.
|
|
|
|
Params:
|
|
writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
|
|
Returns:
|
|
A `string` when not using an output range; `void` otherwise.
|
|
+/
|
|
string toString() const @safe pure nothrow
|
|
{
|
|
return toISOExtString();
|
|
}
|
|
|
|
/// ditto
|
|
void toString(W)(ref W writer) const
|
|
if (isOutputRange!(W, char))
|
|
{
|
|
toISOExtString(writer);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
auto tod = TimeOfDay(12, 30, 33);
|
|
const ctod = TimeOfDay(12, 30, 33);
|
|
immutable itod = TimeOfDay(12, 30, 33);
|
|
assert(tod.toString());
|
|
assert(ctod.toString());
|
|
assert(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:
|
|
$(REF DateTimeException,std,datetime,date) if the given string is
|
|
not in the ISO format or if the resulting $(LREF TimeOfDay) would
|
|
not be valid.
|
|
+/
|
|
static TimeOfDay fromISOString(S)(scope const S isoString) @safe pure
|
|
if (isSomeString!S)
|
|
{
|
|
import std.conv : to, text, ConvException;
|
|
import std.exception : enforce;
|
|
import std.string : strip;
|
|
|
|
int hours, minutes, seconds;
|
|
auto str = strip(isoString);
|
|
|
|
enforce!DateTimeException(str.length == 6, text("Invalid format for TimeOfDay.fromISOString: ", isoString));
|
|
|
|
try
|
|
{
|
|
// cast to int from uint is used because it checks for
|
|
// non digits without extra loops
|
|
hours = cast(int) to!uint(str[0 .. 2]);
|
|
minutes = cast(int) to!uint(str[2 .. 4]);
|
|
seconds = cast(int) to!uint(str[4 .. $]);
|
|
}
|
|
catch (ConvException)
|
|
{
|
|
throw new DateTimeException(text("Invalid format for TimeOfDay.fromISOString: ", isoString));
|
|
}
|
|
|
|
return TimeOfDay(hours, minutes, seconds);
|
|
}
|
|
|
|
///
|
|
@safe 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));
|
|
}
|
|
|
|
@safe 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));
|
|
}
|
|
|
|
// https://issues.dlang.org/show_bug.cgi?id=17801
|
|
@safe unittest
|
|
{
|
|
import std.conv : to;
|
|
import std.meta : AliasSeq;
|
|
static foreach (C; AliasSeq!(char, wchar, dchar))
|
|
{
|
|
static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
|
|
assert(TimeOfDay.fromISOString(to!S("141516")) == TimeOfDay(14, 15, 16));
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
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:
|
|
$(REF DateTimeException,std,datetime,date) 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)(scope const S isoExtString) @safe pure
|
|
if (isSomeString!S)
|
|
{
|
|
import std.conv : ConvException, text, to;
|
|
import std.string : strip;
|
|
|
|
auto str = strip(isoExtString);
|
|
int hours, minutes, seconds;
|
|
|
|
if (str.length != 8 || str[2] != ':' || str[5] != ':')
|
|
throw new DateTimeException(text("Invalid format for TimeOfDay.fromISOExtString: ", isoExtString));
|
|
|
|
try
|
|
{
|
|
// cast to int from uint is used because it checks for
|
|
// non digits without extra loops
|
|
hours = cast(int) to!uint(str[0 .. 2]);
|
|
minutes = cast(int) to!uint(str[3 .. 5]);
|
|
seconds = cast(int) to!uint(str[6 .. $]);
|
|
}
|
|
catch (ConvException)
|
|
{
|
|
throw new DateTimeException(text("Invalid format for TimeOfDay.fromISOExtString: ", isoExtString));
|
|
}
|
|
|
|
return TimeOfDay(hours, minutes, seconds);
|
|
}
|
|
|
|
///
|
|
@safe 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));
|
|
}
|
|
|
|
@safe 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));
|
|
}
|
|
|
|
// https://issues.dlang.org/show_bug.cgi?id=17801
|
|
@safe unittest
|
|
{
|
|
import std.conv : to;
|
|
import std.meta : AliasSeq;
|
|
static foreach (C; AliasSeq!(char, wchar, dchar))
|
|
{
|
|
static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
|
|
assert(TimeOfDay.fromISOExtString(to!S("14:15:16")) == TimeOfDay(14, 15, 16));
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
Returns midnight.
|
|
+/
|
|
@property static TimeOfDay min() @safe pure nothrow @nogc
|
|
{
|
|
return TimeOfDay.init;
|
|
}
|
|
|
|
@safe 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 @nogc
|
|
{
|
|
auto tod = TimeOfDay.init;
|
|
tod._hour = maxHour;
|
|
tod._minute = maxMinute;
|
|
tod._second = maxSecond;
|
|
|
|
return tod;
|
|
}
|
|
|
|
@safe 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 @nogc
|
|
{
|
|
import core.time : convert;
|
|
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;
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
static void testTOD(TimeOfDay orig, int seconds, 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 @nogc
|
|
{
|
|
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));
|
|
}
|
|
|
|
|
|
package:
|
|
|
|
ubyte _hour;
|
|
ubyte _minute;
|
|
ubyte _second;
|
|
|
|
enum ubyte maxHour = 24 - 1;
|
|
enum ubyte maxMinute = 60 - 1;
|
|
enum ubyte maxSecond = 60 - 1;
|
|
}
|
|
|
|
///
|
|
@safe pure unittest
|
|
{
|
|
import core.time : minutes, seconds;
|
|
|
|
auto t = TimeOfDay(12, 30, 0);
|
|
|
|
t += 10.minutes + 100.seconds;
|
|
assert(t == TimeOfDay(12, 41, 40));
|
|
|
|
assert(t.toISOExtString() == "12:41:40");
|
|
assert(t.toISOString() == "124140");
|
|
|
|
assert(TimeOfDay.fromISOExtString("15:00:00") == TimeOfDay(15, 0, 0));
|
|
assert(TimeOfDay.fromISOString("015000") == TimeOfDay(1, 50, 0));
|
|
}
|
|
|
|
/++
|
|
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 @nogc
|
|
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 <= 23;
|
|
else static if (units == "minutes")
|
|
return value >= 0 && value <= 59;
|
|
else static if (units == "seconds")
|
|
return value >= 0 && value <= 59;
|
|
}
|
|
|
|
///
|
|
@safe 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 (January is 1).
|
|
day = The day to validate.
|
|
+/
|
|
bool valid(string units)(int year, int month, int day) @safe pure nothrow @nogc
|
|
if (units == "days")
|
|
{
|
|
return day > 0 && day <= maxDay(year, month);
|
|
}
|
|
|
|
///
|
|
@safe pure nothrow @nogc unittest
|
|
{
|
|
assert(valid!"days"(2016, 2, 29));
|
|
assert(!valid!"days"(2016, 2, 30));
|
|
assert(valid!"days"(2017, 2, 20));
|
|
assert(!valid!"days"(2017, 2, 29));
|
|
}
|
|
|
|
private short castToYear(int year, string file = __FILE__, size_t line = __LINE__) @safe pure
|
|
{
|
|
import std.conv : to, ConvOverflowException;
|
|
import std.format : format;
|
|
|
|
try
|
|
return year.to!short;
|
|
catch (ConvOverflowException)
|
|
throw new DateTimeException(format("year %s doesn't fit to Date.", year), file, line);
|
|
}
|
|
|
|
/++
|
|
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 `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);
|
|
}
|
|
}
|
|
|
|
///
|
|
@safe pure unittest
|
|
{
|
|
import std.exception : assertThrown, assertNotThrown;
|
|
|
|
assertNotThrown(enforceValid!"months"(10));
|
|
assertNotThrown(enforceValid!"seconds"(40));
|
|
|
|
assertThrown!DateTimeException(enforceValid!"months"(0));
|
|
assertThrown!DateTimeException(enforceValid!"hours"(24));
|
|
assertThrown!DateTimeException(enforceValid!"minutes"(60));
|
|
assertThrown!DateTimeException(enforceValid!"seconds"(60));
|
|
}
|
|
|
|
|
|
/++
|
|
Because the validity of the day number depends on both on the year
|
|
and month of which the day is occurring, take all three variables
|
|
to validate the day.
|
|
|
|
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);
|
|
}
|
|
|
|
///
|
|
@safe pure unittest
|
|
{
|
|
import std.exception : assertThrown, assertNotThrown;
|
|
|
|
assertNotThrown(enforceValid!"days"(2000, Month.jan, 1));
|
|
// leap year
|
|
assertNotThrown(enforceValid!"days"(2000, Month.feb, 29));
|
|
|
|
assertThrown!DateTimeException(enforceValid!"days"(2001, Month.feb, 29));
|
|
assertThrown!DateTimeException(enforceValid!"days"(2000, Month.jan, 32));
|
|
assertThrown!DateTimeException(enforceValid!"days"(2000, Month.apr, 31));
|
|
}
|
|
|
|
|
|
/++
|
|
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.
|
|
+/
|
|
int daysToDayOfWeek(DayOfWeek currDoW, DayOfWeek dow) @safe pure nothrow @nogc
|
|
{
|
|
if (currDoW == dow)
|
|
return 0;
|
|
if (currDoW < dow)
|
|
return dow - currDoW;
|
|
return DayOfWeek.sat - currDoW + dow + 1;
|
|
}
|
|
|
|
///
|
|
@safe pure nothrow @nogc unittest
|
|
{
|
|
assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.mon) == 0);
|
|
assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sun) == 6);
|
|
assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.wed) == 2);
|
|
}
|
|
|
|
@safe 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);
|
|
}
|
|
|
|
|
|
/++
|
|
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.
|
|
+/
|
|
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;
|
|
}
|
|
|
|
///
|
|
@safe pure unittest
|
|
{
|
|
assert(monthsToMonth(Month.jan, Month.jan) == 0);
|
|
assert(monthsToMonth(Month.jan, Month.dec) == 11);
|
|
assert(monthsToMonth(Month.jul, Month.oct) == 3);
|
|
}
|
|
|
|
@safe 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);
|
|
}
|
|
|
|
|
|
/++
|
|
Whether the given Gregorian Year is a leap year.
|
|
|
|
Params:
|
|
year = The year to to be tested.
|
|
+/
|
|
bool yearIsLeapYear(int year) @safe pure nothrow @nogc
|
|
{
|
|
if (year % 400 == 0)
|
|
return true;
|
|
if (year % 100 == 0)
|
|
return false;
|
|
return year % 4 == 0;
|
|
}
|
|
|
|
///
|
|
@safe unittest
|
|
{
|
|
foreach (year; [1, 2, 100, 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010])
|
|
{
|
|
assert(!yearIsLeapYear(year));
|
|
assert(!yearIsLeapYear(-year));
|
|
}
|
|
|
|
foreach (year; [0, 4, 8, 400, 800, 1600, 1996, 2000, 2004, 2008, 2012])
|
|
{
|
|
assert(yearIsLeapYear(year));
|
|
assert(yearIsLeapYear(-year));
|
|
}
|
|
}
|
|
|
|
@safe 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));
|
|
}
|
|
}
|
|
|
|
|
|
/++
|
|
Whether the given type defines all of the necessary functions for it to
|
|
function as a time point.
|
|
|
|
1. `T` must define a static property named `min` which is the smallest
|
|
value of `T` as `Unqual!T`.
|
|
|
|
2. `T` must define a static property named `max` which is the largest
|
|
value of `T` as `Unqual!T`.
|
|
|
|
3. `T` must define an `opBinary` for addition and subtraction that
|
|
accepts $(REF Duration, core,time) and returns `Unqual!T`.
|
|
|
|
4. `T` must define an `opOpAssign` for addition and subtraction that
|
|
accepts $(REF Duration, core,time) and returns $(D ref Unqual!T).
|
|
|
|
5. `T` must define a `opBinary` for subtraction which accepts `T`
|
|
and returns $(REF Duration, core,time).
|
|
+/
|
|
template isTimePoint(T)
|
|
{
|
|
import core.time : Duration;
|
|
import std.traits : FunctionAttribute, functionAttributes, Unqual;
|
|
|
|
enum isTimePoint = hasMin &&
|
|
hasMax &&
|
|
hasOverloadedOpBinaryWithDuration &&
|
|
hasOverloadedOpAssignWithDuration &&
|
|
hasOverloadedOpBinaryWithSelf &&
|
|
!is(U == Duration);
|
|
|
|
private:
|
|
|
|
alias U = Unqual!T;
|
|
|
|
enum hasMin = __traits(hasMember, T, "min") &&
|
|
is(typeof(T.min) == U) &&
|
|
is(typeof({static assert(__traits(isStaticFunction, T.min));}));
|
|
|
|
enum hasMax = __traits(hasMember, T, "max") &&
|
|
is(typeof(T.max) == U) &&
|
|
is(typeof({static assert(__traits(isStaticFunction, T.max));}));
|
|
|
|
enum hasOverloadedOpBinaryWithDuration = is(typeof(T.init + Duration.init) == U) &&
|
|
is(typeof(T.init - Duration.init) == U);
|
|
|
|
enum hasOverloadedOpAssignWithDuration = is(typeof(U.init += Duration.init) == U) &&
|
|
is(typeof(U.init -= Duration.init) == U) &&
|
|
is(typeof(
|
|
{
|
|
alias add = U.opOpAssign!"+";
|
|
alias sub = U.opOpAssign!"-";
|
|
alias FA = FunctionAttribute;
|
|
static assert((functionAttributes!add & FA.ref_) != 0);
|
|
static assert((functionAttributes!sub & FA.ref_) != 0);
|
|
}));
|
|
|
|
enum hasOverloadedOpBinaryWithSelf = is(typeof(T.init - T.init) == Duration);
|
|
}
|
|
|
|
///
|
|
@safe unittest
|
|
{
|
|
import core.time : Duration;
|
|
import std.datetime.interval : Interval;
|
|
import std.datetime.systime : SysTime;
|
|
|
|
static assert(isTimePoint!Date);
|
|
static assert(isTimePoint!DateTime);
|
|
static assert(isTimePoint!SysTime);
|
|
static assert(isTimePoint!TimeOfDay);
|
|
|
|
static assert(!isTimePoint!int);
|
|
static assert(!isTimePoint!Duration);
|
|
static assert(!isTimePoint!(Interval!SysTime));
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
import core.time;
|
|
import std.datetime.interval;
|
|
import std.datetime.systime;
|
|
import std.meta : AliasSeq;
|
|
|
|
static foreach (TP; AliasSeq!(Date, DateTime, SysTime, TimeOfDay))
|
|
{
|
|
static assert(isTimePoint!(const TP), TP.stringof);
|
|
static assert(isTimePoint!(immutable TP), TP.stringof);
|
|
}
|
|
|
|
static foreach (T; AliasSeq!(float, string, Duration, Interval!Date, PosInfInterval!Date, NegInfInterval!Date))
|
|
static assert(!isTimePoint!T, T.stringof);
|
|
}
|
|
|
|
|
|
/++
|
|
Whether all of the given strings are valid units of time.
|
|
|
|
`"nsecs"` is not considered a valid unit of time. Nothing in std.datetime
|
|
can handle precision greater than hnsecs, and the few functions in core.time
|
|
which deal with "nsecs" deal with it explicitly.
|
|
+/
|
|
bool validTimeUnits(string[] units...) @safe pure nothrow @nogc
|
|
{
|
|
import std.algorithm.searching : canFind;
|
|
foreach (str; units)
|
|
{
|
|
if (!canFind(timeStrings[], str))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
///
|
|
@safe @nogc nothrow unittest
|
|
{
|
|
assert(validTimeUnits("msecs", "seconds", "minutes"));
|
|
assert(validTimeUnits("days", "weeks", "months"));
|
|
assert(!validTimeUnits("ms", "seconds", "minutes"));
|
|
}
|
|
|
|
|
|
/++
|
|
Compares two time unit strings. `"years"` are the largest units and
|
|
`"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.algorithm.searching : countUntil;
|
|
import std.exception : enforce;
|
|
import std.format : format;
|
|
|
|
immutable indexOfLHS = countUntil(timeStrings, lhs);
|
|
immutable indexOfRHS = countUntil(timeStrings, rhs);
|
|
|
|
enforce!DateTimeException(indexOfLHS != -1, format("%s is not a valid TimeString", lhs));
|
|
enforce!DateTimeException(indexOfRHS != -1, format("%s is not a valid TimeString", rhs));
|
|
|
|
if (indexOfLHS < indexOfRHS)
|
|
return -1;
|
|
if (indexOfLHS > indexOfRHS)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
///
|
|
@safe pure unittest
|
|
{
|
|
import std.exception : assertThrown;
|
|
|
|
assert(cmpTimeUnits("hours", "hours") == 0);
|
|
assert(cmpTimeUnits("hours", "weeks") < 0);
|
|
assert(cmpTimeUnits("months", "seconds") > 0);
|
|
|
|
assertThrown!DateTimeException(cmpTimeUnits("month", "second"));
|
|
}
|
|
|
|
@safe 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. `"years"` are the largest
|
|
units and `"hnsecs"` are the smallest.
|
|
|
|
This template is used instead of `cmpTimeUnits` because exceptions
|
|
can't be thrown at compile time and `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);
|
|
}
|
|
|
|
///
|
|
@safe pure unittest
|
|
{
|
|
static assert(CmpTimeUnits!("years", "weeks") > 0);
|
|
static assert(CmpTimeUnits!("days", "days") == 0);
|
|
static assert(CmpTimeUnits!("seconds", "hours") < 0);
|
|
}
|
|
|
|
// Helper function for CmpTimeUnits.
|
|
private int cmpTimeUnitsCTFE(string lhs, string rhs) @safe pure nothrow @nogc
|
|
{
|
|
import std.algorithm.searching : 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;
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
static foreach (i; 0 .. timeStrings.length)
|
|
{
|
|
static assert(CmpTimeUnits!(timeStrings[i], timeStrings[i]) == 0);
|
|
|
|
static foreach (next; timeStrings[i + 1 .. $])
|
|
static assert(CmpTimeUnits!(timeStrings[i], next) == -1);
|
|
|
|
static foreach (prev; timeStrings[0 .. i])
|
|
static assert(CmpTimeUnits!(timeStrings[i], prev) == 1);
|
|
}
|
|
}
|
|
|
|
|
|
package:
|
|
|
|
|
|
/+
|
|
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"];
|
|
|
|
/+
|
|
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.
|
|
+/
|
|
ubyte maxDay(int year, int month) @safe pure nothrow @nogc
|
|
in
|
|
{
|
|
assert(valid!"months"(month));
|
|
}
|
|
do
|
|
{
|
|
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.");
|
|
}
|
|
}
|
|
|
|
@safe 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);
|
|
}
|
|
|
|
/+
|
|
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 @nogc
|
|
if (validTimeUnits(units) && CmpTimeUnits!(units, "months") < 0)
|
|
{
|
|
import core.time : convert;
|
|
immutable value = convert!("hnsecs", units)(hnsecs);
|
|
hnsecs -= convert!(units, "hnsecs")(value);
|
|
return value;
|
|
}
|
|
|
|
@safe 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);
|
|
}
|
|
|
|
|
|
/+
|
|
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 @nogc
|
|
{
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
import std.datetime.systime : SysTime;
|
|
|
|
// 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);
|
|
}
|
|
|
|
|
|
private:
|
|
|
|
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];
|
|
|
|
|
|
/+
|
|
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];
|
|
}
|
|
|
|
@safe 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:
|
|
$(REF DateTimeException,std,datetime,date) if the given month is not a
|
|
valid month string.
|
|
+/
|
|
Month monthFromString(T)(T monthStr) @safe pure
|
|
if (isSomeString!T)
|
|
{
|
|
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));
|
|
}
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
import std.conv : to;
|
|
import std.traits : EnumMembers;
|
|
foreach (badStr; ["Ja", "Janu", "Januar", "Januarys", "JJanuary", "JANUARY",
|
|
"JAN", "january", "jaNuary", "jaN", "jaNuaRy", "jAn"])
|
|
{
|
|
assertThrown!DateTimeException(monthFromString(badStr), badStr);
|
|
}
|
|
|
|
foreach (month; EnumMembers!Month)
|
|
{
|
|
assert(monthFromString(monthToString(month)) == month, month.to!string);
|
|
}
|
|
}
|
|
|
|
|
|
// NOTE: all the non-simple array literals are wrapped in functions, because
|
|
// otherwise importing causes re-evaluation of the static initializers using
|
|
// CTFE with unittests enabled
|
|
version (StdUnittest)
|
|
{
|
|
private @safe:
|
|
// 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()
|
|
{
|
|
static MonthDay[] result = [MonthDay(1, 1),
|
|
MonthDay(1, 2),
|
|
MonthDay(3, 17),
|
|
MonthDay(7, 4),
|
|
MonthDay(10, 27),
|
|
MonthDay(12, 30),
|
|
MonthDay(12, 31)];
|
|
return result;
|
|
}
|
|
|
|
auto testDays = [1, 2, 9, 10, 16, 20, 25, 28, 29, 30, 31];
|
|
|
|
TimeOfDay[] testTODs()
|
|
{
|
|
static result = [TimeOfDay(0, 0, 0),
|
|
TimeOfDay(0, 0, 1),
|
|
TimeOfDay(0, 1, 0),
|
|
TimeOfDay(1, 0, 0),
|
|
TimeOfDay(13, 13, 13),
|
|
TimeOfDay(23, 59, 59)];
|
|
return result;
|
|
}
|
|
|
|
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.
|
|
TimeOfDay[] testTODsThrown()
|
|
{
|
|
static result = [TimeOfDay(0, 0, 0),
|
|
TimeOfDay(13, 13, 13),
|
|
TimeOfDay(23, 59, 59)];
|
|
return result;
|
|
}
|
|
|
|
Date[] testDatesBC;
|
|
Date[] testDatesAD;
|
|
|
|
DateTime[] testDateTimesBC;
|
|
DateTime[] testDateTimesAD;
|
|
|
|
// I'd use a Tuple, but I get forward reference errors if I try.
|
|
struct GregDay { int day; Date date; }
|
|
GregDay[] testGregDaysBC()
|
|
{
|
|
static result = [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))];
|
|
return result;
|
|
}
|
|
|
|
GregDay[] testGregDaysAD()
|
|
{
|
|
static result = [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))];
|
|
return result;
|
|
}
|
|
|
|
// I'd use a Tuple, but I get forward reference errors if I try.
|
|
struct DayOfYear { int day; MonthDay md; }
|
|
DayOfYear[] testDaysOfYear()
|
|
{
|
|
static result = [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))];
|
|
return result;
|
|
}
|
|
|
|
DayOfYear[] testDaysOfLeapYear()
|
|
{
|
|
static result = [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))];
|
|
return result;
|
|
}
|
|
|
|
void initializeTests()
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
}
|