/d/phobos2/std/datetime.d
D | 8509 lines | 6008 code | 1083 blank | 1418 comment | 252 complexity | 5de7024b9dda482701bc9e52fc10a811 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0
Large files files are truncated, but you can click here to view the full file
- //Written in the D programming language
- /++
- Module containing Date/Time functionality.
- This module provides:
- $(UL
- $(LI Types to represent points in time: $(D SysTime), $(D Date),
- $(D TimeOfDay), and $(D DateTime).)
- $(LI Types to represent intervals of time.)
- $(LI Types to represent ranges over intervals of time.)
- $(LI Types to represent time zones (used by $(D SysTime)).)
- $(LI A platform-independent, high precision stopwatch type:
- $(D StopWatch))
- $(LI Benchmarking functions.)
- $(LI Various helper functions.)
- )
- Closely related to std.datetime is <a href="core_time.html">$(D core.time)</a>,
- and some of the time types used in std.datetime come from there - such as
- $(CXREF time, Duration), $(CXREF time, TickDuration), and
- $(CXREF time, FracSec). So, you may want to look at its documentation as
- well. However, core.time is publically imported into std.datetime, so you
- don't have to import it separately.
- Three of the main concepts used in this module are time points, time
- durations, and time intervals.
- A time point is a specific point in time. e.g. January 5th, 2010
- or 5:00.
- A time duration is a length of time with units. e.g. 5 days or 231 seconds.
- A time interval indicates a period of time associated with a fixed point in
- time. So, it is either two time points associated with each other,
- indicating the time starting at the first point up to, but not including,
- the second point - e.g. [January 5th, 2010 - March 10th, 2010$(RPAREN) - or
- it is a time point and a time duration associated with one another. e.g.
- January 5th, 2010 and 5 days, indicating [January 5th, 2010 -
- January 10th, 2010$(RPAREN).
- Various arithmetic operations are supported between time points and
- durations (e.g. the difference between two time points is a time duration),
- and ranges can be gotten from time intervals, so range-based operations may
- be done on a series of time points.
- The types that the typical user is most likely to be interested in are
- $(D Date) (if they want dates but don't care about time), $(D DateTime)
- (if they want dates and times but don't care about time zones), $(D SysTime)
- (if they want the date and time from the OS and/or do care about time
- zones), and StopWatch (a platform-independent, high precision stop watch).
- $(D Date) and $(D DateTime) are optimized for calendar-based operations,
- while $(D SysTime) is designed for dealing with time from the OS. Check out
- their specific documentation for more details.
- To get the current time, use $(D Clock.currTime). It will return the current
- time as a $(D SysTime). If you want to print it, $(D toString) is
- sufficient, but if you use $(D toISOString), $(D toISOExtString), or
- $(D toSimpleString), you can use the corresponding $(D fromISOString),
- $(D fromISOExtString), or $(D fromISOExtString) to create a
- $(D SysTime) from the string.
- --------------------
- auto currentTime = Clock.currTime();
- auto timeString = currentTime.toISOExtString();
- auto restoredTime = SysTime.fromISOExtString(timeString);
- --------------------
- Various functions take a string (or strings) to represent a unit of time
- (e.g. $(D convert!("days", "hours")(numDays))). The valid strings to use
- with such functions are $(D "years"), $(D "months"), $(D "weeks"),
- $(D "days"), $(D "hours"), $(D "minutes"), $(D "seconds"),
- $(D "msecs") (milliseconds), $(D "usecs") (microseconds),
- $(D "hnsecs") (hecto-nanoseconds - i.e. 100 ns), or some subset thereof.
- There are a few functions in core.time which take $(D "nsecs"), but because
- nothing in std.datetime has precision greater than hnsecs, and very little
- in core.time does, no functions in std.datetime accept $(D "nsecs"). If
- you need help remembering which units are abbreviated and which aren't,
- notice that all units seconds and greater use their full names, and all
- sub-second units are abbreviated (since they'd be rather long if they
- weren't).
- If you're looking for the definitions of $(D Duration), $(D TickDuration),
- or $(D FracSec), they're in core.time.
- Note:
- $(D DateTimeException) is an alias for core.time's $(D TimeException),
- so you don't need to worry about core.time functions and std.datetime
- functions throwing different exception types (except in the rare case
- that they throw something other than $(D TimeException) or
- $(D DateTimeException)).
- See_Also:
- $(WEB en.wikipedia.org/wiki/ISO_8601, ISO 8601)
- $(WEB en.wikipedia.org/wiki/Tz_database, Wikipedia entry on TZ Database)
- $(WEB en.wikipedia.org/wiki/List_of_tz_database_time_zones,
- List of Time Zones)
- Copyright: Copyright 2010 - 2011
- License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
- Authors: Jonathan M Davis and Kato Shoichi
- Source: $(PHOBOSSRC std/_datetime.d)
- +/
- module std.datetime;
- public import core.time;
- import core.exception;
- import core.stdc.time;
- import std.array;
- import std.algorithm;
- import std.ascii;
- import std.conv;
- import std.exception;
- import std.file;
- import std.functional;
- import std.math;
- import std.metastrings;
- import std.path;
- import std.range;
- import std.stdio;
- import std.string;
- import std.system;
- import std.traits;
- import std.typecons;
- version(Windows)
- {
- import core.sys.windows.windows;
- import std.c.windows.winsock;
- //For system call to access the registry.
- pragma(lib, "advapi32.lib");
- }
- else version(Posix)
- {
- import core.sys.posix.arpa.inet;
- import core.sys.posix.stdlib;
- import core.sys.posix.time;
- import core.sys.posix.sys.time;
- //We need to disable many tests because building all of Phobos
- //with all of std.datetime's unit tests enables currently causes
- //dmd to run out of memory.
- //Regardless of that, however, it's also useful to be able to
- //easily turn the tests on and off.
- version = testStdDateTime;
- }
- version(unittest)
- {
- import std.c.string;
- import std.stdio;
- }
- //I'd just alias it to indexOf, but
- //http://d.puremagic.com/issues/show_bug.cgi?id=6013 would mean that that would
- //pollute the global namespace. So, for now, I've created an alias which is
- //highly unlikely to conflict with anything that anyone else is doing.
- private alias std.string.indexOf stds_indexOf;
- //Verify module example.
- version(testStdDateTime) unittest
- {
- auto currentTime = Clock.currTime();
- auto timeString = currentTime.toISOExtString();
- auto restoredTime = SysTime.fromISOExtString(timeString);
- }
- //Verify Examples for core.time.Duration which couldn't be in core.time.
- unittest
- {
- assert(std.datetime.Date(2010, 9, 7) + dur!"days"(5) ==
- std.datetime.Date(2010, 9, 12));
- assert(std.datetime.Date(2010, 9, 7) - std.datetime.Date(2010, 10, 3) ==
- dur!"days"(-26));
- }
- //Note: There various functions which void as their return type and ref of the
- // struct type which they're in as a commented out return type. Ideally,
- // they would return the ref, but there are several dmd bugs which prevent
- // that, relating to both ref and invariants. So, I've left the ref return
- // types commented out with the idea that those functions can be made to
- // return a ref to this once those bugs have been fixed.
- //==============================================================================
- // Section with public enums and constants.
- //==============================================================================
- /++
- Represents the 12 months of the Gregorian year (January is 1).
- +/
- enum Month : ubyte { jan = 1, ///
- feb, ///
- mar, ///
- apr, ///
- may, ///
- jun, ///
- jul, ///
- aug, ///
- sep, ///
- oct, ///
- nov, ///
- dec ///
- }
- /++
- Represents the 7 days of the Gregorian week (Sunday is 0).
- +/
- enum DayOfWeek : ubyte { sun = 0, ///
- mon, ///
- tue, ///
- wed, ///
- thu, ///
- fri, ///
- sat ///
- }
- /++
- In some date calculations, adding months or years can cause the date to fall
- on a day of the month which is not valid (e.g. February 29th 2001 or
- June 31st 2000). If overflow is allowed (as is the default), then the month
- will be incremented accordingly (so, February 29th 2001 would become
- March 1st 2001, and June 31st 2000 would become July 1st 2000). If overflow
- is not allowed, then the day will be adjusted to the last valid day in that
- month (so, February 29th 2001 would become February 28th 2001 and
- June 31st 2000 would become June 30th 2000).
- AllowDayOverflow only applies to calculations involving months or years.
- +/
- enum AllowDayOverflow
- {
- /// No, don't allow day overflow.
- no,
- /// Yes, allow day overflow.
- yes
- }
- /++
- Indicates a direction in time. One example of its use is $(D Interval)'s
- $(D expand) function which uses it to indicate whether the interval should
- be expanded backwards (into the past), forwards (into the future), or both.
- +/
- enum Direction
- {
- /// Backward.
- bwd,
- /// Forward.
- fwd,
- /// Both backward and forward.
- both
- }
- /++
- Used to indicate whether $(D popFront) should be called immediately upon
- creating a range. The idea is that for some functions used to generate a
- range for an interval, $(D front) is not necessarily a time point which
- would ever be generated by the range, and if you want the first time point
- in the range to match what the function generates, then you use
- $(D PopFirst.yes) to indicate that the range should have $(D popFront)
- called on it before the range is returned so that $(D front) is a time point
- which the function would generate.
- For instance, if the function used to generate a range of time points
- generated successive Easters (i.e. you're iterating over all of the Easters
- within the interval), the initial date probably isn't an Easter. By using
- $(D PopFirst.yes), you would be telling the function which returned the
- range that you wanted $(D popFront) to be called so that front would then be
- an Easter - the next one generated by the function (which if you were
- iterating forward, would be the Easter following the original $(D front),
- while if you were iterating backward, it would be the Easter prior to the
- original $(D front)). If $(D PopFirst.no) were used, then $(D front) would
- remain the original time point and it would not necessarily be a time point
- which would be generated by the range-generating function (which in many
- cases is exactly what you
- want - e.g. if you were iterating over every day starting at the beginning
- of the interval).
- +/
- enum PopFirst
- {
- /// No, don't call popFront() before returning the range.
- no,
- /// Yes, call popFront() before returning the range.
- yes
- }
- /++
- Used by StopWatch to indicate whether it should start immediately upon
- construction.
- +/
- enum AutoStart
- {
- /// No, don't start the StopWatch when it is constructed.
- no,
- /// Yes, do start the StopWatch when it is constructed.
- yes
- }
- /++
- Array of the strings representing time units, starting with the smallest
- unit and going to the largest. It does not include $(D "nsecs").
- Includes $(D "hnsecs") (hecto-nanoseconds (100 ns)),
- $(D "usecs") (microseconds), $(D "msecs") (milliseconds), $(D "seconds"),
- $(D "minutes"), $(D "hours"), $(D "days"), $(D "weeks"), $(D "months"), and
- $(D "years")
- +/
- immutable string[] timeStrings = ["hnsecs", "usecs", "msecs", "seconds", "minutes",
- "hours", "days", "weeks", "months", "years"];
- //==============================================================================
- // Section with other types.
- //==============================================================================
- /++
- Exception type used by std.datetime. It's an alias to TimeException, which
- is what core.time uses. So, you can catch either and not worry about which
- module it came from.
- +/
- alias TimeException DateTimeException;
- /++
- Effectively a namespace to make it clear that the methods it contains are
- getting the time from the system clock. It cannot be instantiated.
- +/
- final class Clock
- {
- public:
- /++
- Returns the current time in the given time zone.
- Throws:
- $(D ErrnoException) (on Posix) or $(D Exception) (on Windows)
- if it fails to get the time of day.
- +/
- static SysTime currTime(immutable TimeZone tz = LocalTime())
- {
- return SysTime(currStdTime, tz);
- }
- version(testStdDateTime) unittest
- {
- assert(currTime(UTC()).timezone is UTC());
- //I have no idea why, but for some reason, Windows/Wine likes to get
- //time_t wrong when getting it with core.stdc.time.time. On one box
- //I have (which has its local time set to UTC), it always gives time_t
- //in the real local time (America/Los_Angeles), and after the most recent
- //DST switch, every Windows box that I've tried it in is reporting
- //time_t as being 1 hour off of where it's supposed to be. So, I really
- //don't know what the deal is, but given what I'm seeing, I don't trust
- //core.stdc.time.time on Windows, so I'm just going to disable this test
- //on Windows.
- version(Posix)
- {
- immutable unixTimeD = currTime().toUnixTime();
- immutable unixTimeC = core.stdc.time.time(null);
- immutable diff = unixTimeC - unixTimeD;
- _assertPred!">="(diff, -2);
- _assertPred!"<="(diff, 2);
- }
- }
- /++
- Returns the number of hnsecs since midnight, January 1st, 1 A.D. for the
- current time.
- Throws:
- $(D DateTimeException) if it fails to get the time.
- +/
- @trusted
- static @property long currStdTime()
- {
- version(Windows)
- {
- //FILETIME represents hnsecs from midnight, January 1st, 1601.
- enum hnsecsFrom1601 = 504_911_232_000_000_000L;
- FILETIME fileTime;
- GetSystemTimeAsFileTime(&fileTime);
- ulong tempHNSecs = fileTime.dwHighDateTime;
- tempHNSecs <<= 32;
- tempHNSecs |= fileTime.dwLowDateTime;
- return cast(long)tempHNSecs + hnsecsFrom1601;
- }
- else version(Posix)
- {
- enum hnsecsToUnixEpoch = 621_355_968_000_000_000L;
- static if(is(typeof(clock_gettime)))
- {
- timespec ts;
- if(clock_gettime(CLOCK_REALTIME, &ts) != 0)
- throw new TimeException("Failed in clock_gettime().");
- return convert!("seconds", "hnsecs")(ts.tv_sec) +
- ts.tv_nsec / 100 +
- hnsecsToUnixEpoch;
- }
- else
- {
- timeval tv;
- if(gettimeofday(&tv, null) != 0)
- throw new TimeException("Failed in gettimeofday().");
- return convert!("seconds", "hnsecs")(tv.tv_sec) +
- convert!("usecs", "hnsecs")(tv.tv_usec) +
- hnsecsToUnixEpoch;
- }
- }
- }
- /++
- The current system tick. The number of ticks per second varies from
- system to system. currSystemTick uses a monotonic clock, so it's
- intended for precision timing by comparing relative time values, not
- for getting the current system time.
- Warning:
- On some systems, the monotonic clock may stop counting when
- the computer goes to sleep or hibernates. So, the monotonic
- clock could be off if that occurs. This is known to happen
- on Mac OS X. It has not been tested whether it occurs on
- either Windows or Linux.
- Throws:
- $(D DateTimeException) if it fails to get the time.
- +/
- @safe
- static @property TickDuration currSystemTick()
- {
- return TickDuration.currSystemTick();
- }
- version(testStdDateTime) unittest
- {
- assert(Clock.currSystemTick.length > 0);
- }
- /++
- The current number of system ticks since the application started.
- The number of ticks per second varies from system to system.
- This uses a monotonic clock.
- Warning:
- On some systems, the monotonic clock may stop counting when
- the computer goes to sleep or hibernates. So, the monotonic
- clock could be off if that occurs. This is known to happen
- on Mac OS X. It has not been tested whether it occurs on
- either Windows or on Linux.
- Throws:
- $(D DateTimeException) if it fails to get the time.
- +/
- @safe
- static @property TickDuration currAppTick()
- {
- return currSystemTick - TickDuration.appOrigin;
- }
- version(testStdDateTime) unittest
- {
- auto a = Clock.currSystemTick;
- auto b = Clock.currAppTick;
- assert(a.length);
- assert(b.length);
- assert(a > b);
- }
- private:
- @disable this() {}
- }
- //==============================================================================
- // Section with time points.
- //==============================================================================
- /++
- $(D SysTime) is the type used when you want to get the current time from the
- system or if you're doing anything that involves time zones. Unlike
- $(D DateTime), the time zone is an integral part of $(D SysTime) (though if
- all you care about is local time, you can pretty much ignore time zones, and
- it will work, since it defaults to using the local time zone). It holds its
- internal time in std time (hnsecs since midnight, January 1st, 1 A.D. UTC),
- so it interfaces well with the system time. However, that means that, unlike
- $(D DateTime), it is not optimized for calendar-based operations, and
- getting individual units from it such as years or days is going to involve
- conversions and be less efficient.
- Basically, if you care about calendar-based operations and don't
- necessarily care about time zones, then $(D DateTime) would be the type to
- use. However, if what you care about is the system time, then $(D SysTime)
- would be the type to use.
- $(D Clock.currTime) will return the current time as a $(D SysTime). If you
- want to convert a $(D SysTime) to a $(D Date) or $(D DateTime), simply cast
- it. And if you ever want to convert a $(D Date) or $(D DateTime) to a
- $(D SysTime), use $(D SysTime)'s constructor, and you can pass in the
- intended time zone with it (or don't pass in a $(D TimeZone), and the local
- time zone will be used). Be aware, however, that converting from a
- $(D DateTime) to a $(D SysTime) will not necessarily be 100% accurate due to
- DST (one hour of the year doesn't exist and another occurs twice). So, if
- you don't want to risk any conversion errors, keep your times as
- $(D SysTime)s. Aside from DST though, there shouldn't be any conversion
- problems.
- If you care about using time zones other than local time or UTC, you can use
- $(D PosixTimeZone) on Posix systems (or on Windows, if you provide the TZ
- Database files), and you can use $(D WindowsTimeZone) on Windows systems.
- The time in $(D SysTime) is kept internally in hnsecs from midnight,
- January 1st, 1 A.D. UTC. So, you never get conversion errors when changing
- the time zone of a $(D SysTime). $(D LocalTime) is the $(D TimeZone) class
- which represents the local time, and $(D UTC) is the $(D TimeZone) class
- which represents UTC. $(D SysTime) uses $(D LocalTime) if no $(D TimeZone)
- is provided. For more details on time zones, look at the documentation for
- $(D TimeZone), $(D PosixTimeZone), and $(D WindowsTimeZone).
- $(D SysTime)'s range is from approximately 29,000 B.C. to approximately
- 29,000 A.D.
- +/
- struct SysTime
- {
- public:
- /++
- Params:
- dateTime = The $(D DateTime) to use to set this $(D SysTime)'s
- internal std time. As $(D DateTime) has no concept of
- time zone, tz is used as its time zone.
- tz = The $(D TimeZone) to use for this $(D SysTime). If null,
- $(D LocalTime) will be used. The given $(D DateTime) is
- assumed to be in the given time zone.
- +/
- this(in DateTime dateTime, immutable TimeZone tz = null) nothrow
- {
- try
- this(dateTime, FracSec.from!"hnsecs"(0), tz);
- catch(Exception e)
- assert(0, "FracSec's constructor threw when it shouldn't have.");
- }
- version(testStdDateTime) unittest
- {
- static void test(DateTime dt, immutable TimeZone tz, long expected)
- {
- auto sysTime = SysTime(dt, tz);
- _assertPred!"=="(sysTime._stdTime, expected);
- assert(sysTime._timezone is (tz is null ? LocalTime() : tz),
- format("Given DateTime: %s", dt));
- }
- test(DateTime.init, UTC(), 0);
- test(DateTime(1, 1, 1, 12, 30, 33), UTC(), 450_330_000_000L);
- test(DateTime(0, 12, 31, 12, 30, 33), UTC(), -413_670_000_000L);
- test(DateTime(1, 1, 1, 0, 0, 0), UTC(), 0);
- test(DateTime(1, 1, 1, 0, 0, 1), UTC(), 10_000_000L);
- test(DateTime(0, 12, 31, 23, 59, 59), UTC(), -10_000_000L);
- test(DateTime(1, 1, 1, 0, 0, 0), new SimpleTimeZone(-60),
- 36_000_000_000L);
- test(DateTime(1, 1, 1, 0, 0, 0), new SimpleTimeZone(0), 0);
- test(DateTime(1, 1, 1, 0, 0, 0), new SimpleTimeZone(60),
- -36_000_000_000L);
- }
- /++
- Params:
- dateTime = The $(D DateTime) to use to set this $(D SysTime)'s
- internal std time. As $(D DateTime) has no concept of
- time zone, tz is used as its time zone.
- fracSec = The fractional seconds portion of the time.
- tz = The $(D TimeZone) to use for this $(D SysTime). If null,
- $(D LocalTime) will be used. The given $(D DateTime) is
- assumed to be in the given time zone.
- Throws:
- $(D DateTimeException) if $(D fracSec) is negative.
- +/
- this(in DateTime dateTime, in FracSec fracSec, immutable TimeZone tz = null)
- {
- immutable fracHNSecs = fracSec.hnsecs;
- enforce(fracHNSecs >= 0, new DateTimeException("A SysTime cannot have negative fractional seconds."));
- _timezone = tz is null ? LocalTime() : tz;
- try
- {
- immutable dateDiff = (dateTime.date - Date(1, 1, 1)).total!"hnsecs";
- immutable todDiff = (dateTime.timeOfDay - TimeOfDay(0, 0, 0)).total!"hnsecs";
- immutable adjustedTime = dateDiff + todDiff + fracHNSecs;
- immutable standardTime = _timezone.tzToUTC(adjustedTime);
- this(standardTime, _timezone);
- }
- catch(Exception e)
- {
- assert(0, "Date, TimeOfDay, or DateTime's constructor threw when " ~
- "it shouldn't have.");
- }
- }
- version(testStdDateTime) unittest
- {
- static void test(DateTime dt,
- FracSec fracSec,
- immutable TimeZone tz,
- long expected)
- {
- auto sysTime = SysTime(dt, fracSec, tz);
- _assertPred!"=="(sysTime._stdTime, expected);
- assert(sysTime._timezone is (tz is null ? LocalTime() : tz),
- format("Given DateTime: %s, Given FracSec: %s", dt, fracSec));
- }
- test(DateTime.init, FracSec.init, UTC(), 0);
- test(DateTime(1, 1, 1, 12, 30, 33), FracSec.init, UTC(), 450_330_000_000L);
- test(DateTime(0, 12, 31, 12, 30, 33), FracSec.init, UTC(), -413_670_000_000L);
- test(DateTime(1, 1, 1, 0, 0, 0), FracSec.from!"msecs"(1), UTC(), 10_000L);
- test(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"msecs"(999), UTC(), -10_000L);
- test(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(9_999_999), UTC(), -1);
- test(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(1), UTC(), -9_999_999);
- test(DateTime(0, 12, 31, 23, 59, 59), FracSec.from!"hnsecs"(0), UTC(), -10_000_000);
- assertThrown!DateTimeException(SysTime(DateTime.init, FracSec.from!"hnsecs"(-1), UTC()));
- }
- /++
- Params:
- date = The $(D Date) to use to set this $(D SysTime)'s internal std
- time. As $(D Date) has no concept of time zone, tz is used as
- its time zone.
- tz = The $(D TimeZone) to use for this $(D SysTime). If null,
- $(D LocalTime) will be used. The given $(D Date) is assumed
- to be in the given time zone.
- +/
- this(in Date date, immutable TimeZone tz = null) nothrow
- {
- _timezone = tz is null ? LocalTime() : tz;
- try
- {
- immutable adjustedTime = (date - Date(1, 1, 1)).total!"hnsecs";
- immutable standardTime = _timezone.tzToUTC(adjustedTime);
- this(standardTime, _timezone);
- }
- catch(Exception e)
- assert(0, "Date's constructor through when it shouldn't have.");
- }
- version(testStdDateTime) unittest
- {
- static void test(Date d, immutable TimeZone tz, long expected)
- {
- auto sysTime = SysTime(d, tz);
- _assertPred!"=="(sysTime._stdTime, expected);
- assert(sysTime._timezone is (tz is null ? LocalTime() : tz),
- format("Given Date: %s", d));
- }
- test(Date.init, UTC(), 0);
- test(Date(1, 1, 1), UTC(), 0);
- test(Date(1, 1, 2), UTC(), 864000000000);
- test(Date(0, 12, 31), UTC(), -864000000000);
- }
- /++
- Note:
- Whereas the other constructors take in the given date/time, assume
- that it's in the given time zone, and convert it to hnsecs in UTC
- since midnight, January 1st, 1 A.D. UTC - i.e. std time - this
- constructor takes a std time, which is specifically already in UTC,
- so no conversion takes place. Of course, the various getter
- properties and functions will use the given time zone's conversion
- function to convert the results to that time zone, but no conversion
- of the arguments to this constructor takes place.
- Params:
- stdTime = The number of hnsecs since midnight, January 1st, 1 A.D. UTC.
- tz = The $(D TimeZone) to use for this $(D SysTime). If null,
- $(D LocalTime) will be used.
- +/
- this(long stdTime, immutable TimeZone tz = null) pure nothrow
- {
- _stdTime = stdTime;
- _timezone = tz is null ? LocalTime() : tz;
- }
- version(testStdDateTime) unittest
- {
- static void test(long stdTime, immutable TimeZone tz)
- {
- auto sysTime = SysTime(stdTime, tz);
- _assertPred!"=="(sysTime._stdTime, stdTime);
- assert(sysTime._timezone is (tz is null ? LocalTime() : tz),
- format("Given stdTime: %s", stdTime));
- }
- foreach(stdTime; [-1234567890L, -250, 0, 250, 1235657390L])
- {
- foreach(tz; testTZs)
- test(stdTime, tz);
- }
- }
- /++
- Params:
- rhs = The $(D SysTime) to assign to this one.
- +/
- ref SysTime opAssign(const ref SysTime rhs) pure nothrow
- {
- _stdTime = rhs._stdTime;
- _timezone = rhs._timezone;
- return this;
- }
- /++
- Params:
- rhs = The $(D SysTime) to assign to this one.
- +/
- ref SysTime opAssign(SysTime rhs) pure nothrow
- {
- _stdTime = rhs._stdTime;
- _timezone = rhs._timezone;
- return this;
- }
- /++
- Checks for equality between this $(D SysTime) and the given
- $(D SysTime).
- Note that the time zone is ignored. Only the internal
- std times (which are in UTC) are compared.
- +/
- bool opEquals(const ref SysTime rhs) const pure nothrow
- {
- return _stdTime == rhs._stdTime;
- }
- version(testStdDateTime) unittest
- {
- _assertPred!"=="(SysTime(DateTime.init, UTC()), SysTime(0, UTC()));
- _assertPred!"=="(SysTime(DateTime.init, UTC()), SysTime(0));
- _assertPred!"=="(SysTime(Date.init, UTC()), SysTime(0));
- _assertPred!"=="(SysTime(0), SysTime(0));
- static void test(DateTime dt,
- immutable TimeZone tz1,
- immutable TimeZone tz2)
- {
- auto st1 = SysTime(dt);
- st1.timezone = tz1;
- auto st2 = SysTime(dt);
- st2.timezone = tz2;
- _assertPred!"=="(st1, st2);
- }
- foreach(tz1; testTZs)
- {
- foreach(tz2; testTZs)
- {
- foreach(dt; chain(testDateTimesBC, testDateTimesAD))
- test(dt, tz1, tz2);
- }
- }
- auto st = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
- const cst = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
- //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
- static assert(__traits(compiles, st == st));
- static assert(__traits(compiles, st == cst));
- //static assert(__traits(compiles, st == ist));
- static assert(__traits(compiles, cst == st));
- static assert(__traits(compiles, cst == cst));
- //static assert(__traits(compiles, cst == ist));
- //static assert(__traits(compiles, ist == st));
- //static assert(__traits(compiles, ist == cst));
- //static assert(__traits(compiles, ist == ist));
- }
- /++
- Compares this $(D SysTime) with the given $(D SysTime).
- Time zone is irrelevant when comparing $(D SysTime)s.
- Returns:
- $(BOOKTABLE,
- $(TR $(TD this < rhs) $(TD < 0))
- $(TR $(TD this == rhs) $(TD 0))
- $(TR $(TD this > rhs) $(TD > 0))
- )
- +/
- int opCmp(in SysTime rhs) const pure nothrow
- {
- if(_stdTime < rhs._stdTime)
- return -1;
- if(_stdTime > rhs._stdTime)
- return 1;
- return 0;
- }
- version(testStdDateTime) unittest
- {
- _assertPred!("opCmp", "==")(SysTime(DateTime.init, UTC()),
- SysTime(0, UTC()));
- _assertPred!("opCmp", "==")(SysTime(DateTime.init, UTC()), SysTime(0));
- _assertPred!("opCmp", "==")(SysTime(Date.init, UTC()), SysTime(0));
- _assertPred!("opCmp", "==")(SysTime(0), SysTime(0));
- static void testEqual(DateTime dt,
- immutable TimeZone tz1,
- immutable TimeZone tz2)
- {
- auto st1 = SysTime(dt);
- st1.timezone = tz1;
- auto st2 = SysTime(dt);
- st2.timezone = tz2;
- _assertPred!("opCmp", "==")(st1, st2);
- }
- foreach(dt; chain(testDateTimesBC, testDateTimesAD))
- {
- foreach(tz1; testTZs)
- {
- foreach(tz2; testTZs)
- testEqual(dt, tz1, tz2);
- }
- }
- static void testCmp(DateTime dt1,
- immutable TimeZone tz1,
- DateTime dt2,
- immutable TimeZone tz2)
- {
- auto st1 = SysTime(dt1);
- st1.timezone = tz1;
- auto st2 = SysTime(dt2);
- st2.timezone = tz2;
- _assertPred!("opCmp", "<")(st1, st2);
- _assertPred!("opCmp", ">")(st2, st1);
- }
- auto dts = testDateTimesBC ~ testDateTimesAD;
- foreach(tz1; testTZs)
- {
- foreach(tz2; testTZs)
- {
- for(size_t i = 0; i < dts.length; ++i)
- {
- for(size_t j = i + 1; j < dts.length; ++j)
- testCmp(dts[i], tz1, dts[j], tz2);
- }
- }
- }
- auto st = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
- const cst = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
- //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
- static assert(__traits(compiles, st.opCmp(st)));
- static assert(__traits(compiles, st.opCmp(cst)));
- //static assert(__traits(compiles, st.opCmp(ist)));
- static assert(__traits(compiles, cst.opCmp(st)));
- static assert(__traits(compiles, cst.opCmp(cst)));
- //static assert(__traits(compiles, cst.opCmp(ist)));
- //static assert(__traits(compiles, ist.opCmp(st)));
- //static assert(__traits(compiles, ist.opCmp(cst)));
- //static assert(__traits(compiles, ist.opCmp(ist)));
- }
- /++
- Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
- are B.C.
- +/
- @property short year() const nothrow
- {
- return (cast(Date)this).year;
- }
- version(testStdDateTime) unittest
- {
- static void test(SysTime sysTime, long expected, size_t line = __LINE__)
- {
- _assertPred!"=="(sysTime.year, expected,
- format("Value given: %s", sysTime), __FILE__, line);
- }
- test(SysTime(0, UTC()), 1);
- test(SysTime(1, UTC()), 1);
- test(SysTime(-1, UTC()), 0);
- foreach(year; chain(testYearsBC, testYearsAD))
- {
- foreach(md; testMonthDays)
- {
- foreach(tod; testTODs)
- {
- auto dt = DateTime(Date(year, md.month, md.day), tod);
- foreach(tz; testTZs)
- {
- foreach(fs; testFracSecs)
- test(SysTime(dt, fs, tz), year);
- }
- }
- }
- }
- const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
- //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
- static assert(__traits(compiles, cst.year));
- //static assert(__traits(compiles, ist.year));
- }
- /++
- Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
- are B.C.
- Params:
- year = The year to set this $(D SysTime)'s year to.
- Throws:
- $(D DateTimeException) if the new year is not a leap year and the
- resulting date would be on February 29th.
- Examples:
- --------------------
- assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).year == 1999);
- assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).year == 2010);
- assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).year == -7);
- --------------------
- +/
- @property void year(int year)
- {
- auto hnsecs = adjTime;
- auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
- if(hnsecs < 0)
- {
- hnsecs += convert!("hours", "hnsecs")(24);
- --days;
- }
- auto date = Date(cast(int)days);
- date.year = year;
- immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
- adjTime = newDaysHNSecs + hnsecs;
- }
- //Verify Examples.
- version(testStdDateTime) unittest
- {
- assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).year == 1999);
- assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).year == 2010);
- assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).year == -7);
- }
- version(testStdDateTime) unittest
- {
- static void test(SysTime st, int year, in SysTime expected, size_t line = __LINE__)
- {
- st.year = year;
- _assertPred!"=="(st, expected, "", __FILE__, line);
- }
- foreach(st; chain(testSysTimesBC, testSysTimesAD))
- {
- auto dt = cast(DateTime)st;
- foreach(year; chain(testYearsBC, testYearsAD))
- {
- auto e = SysTime(DateTime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second),
- st.fracSec,
- st.timezone);
- test(st, year, e);
- }
- }
- foreach(fs; testFracSecs)
- {
- foreach(tz; testTZs)
- {
- foreach(tod; testTODs)
- {
- test(SysTime(DateTime(Date(1999, 2, 28), tod), fs, tz), 2000,
- SysTime(DateTime(Date(2000, 2, 28), tod), fs, tz));
- test(SysTime(DateTime(Date(2000, 2, 28), tod), fs, tz), 1999,
- SysTime(DateTime(Date(1999, 2, 28), tod), fs, tz));
- }
- foreach(tod; testTODsThrown)
- {
- auto st = SysTime(DateTime(Date(2000, 2, 29), tod), fs, tz);
- assertThrown!DateTimeException(st.year = 1999);
- }
- }
- }
- const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
- //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
- static assert(!__traits(compiles, cst.year = 7));
- //static assert(!__traits(compiles, ist.year = 7));
- }
- /++
- Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
- Throws:
- $(D DateTimeException) if $(D isAD) is true.
- Examples:
- --------------------
- assert(SysTime(DateTime(0, 1, 1, 12, 30, 33)).yearBC == 1);
- assert(SysTime(DateTime(-1, 1, 1, 10, 7, 2)).yearBC == 2);
- assert(SysTime(DateTime(-100, 1, 1, 4, 59, 0)).yearBC == 101);
- --------------------
- +/
- @property ushort yearBC() const
- {
- return (cast(Date)this).yearBC;
- }
- //Verify Examples.
- version(testStdDateTime) unittest
- {
- assert(SysTime(DateTime(0, 1, 1, 12, 30, 33)).yearBC == 1);
- assert(SysTime(DateTime(-1, 1, 1, 10, 7, 2)).yearBC == 2);
- assert(SysTime(DateTime(-100, 1, 1, 4, 59, 0)).yearBC == 101);
- }
- version(testStdDateTime) unittest
- {
- foreach(st; testSysTimesBC)
- {
- auto msg = format("SysTime: %s", st);
- assertNotThrown!DateTimeException(st.yearBC, msg);
- _assertPred!"=="(st.yearBC, (st.year * -1) + 1, msg);
- }
- foreach(st; [testSysTimesAD[0], testSysTimesAD[$/2], testSysTimesAD[$-1]])
- assertThrown!DateTimeException(st.yearBC, format("SysTime: %s", st));
- auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
- const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
- //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
- static assert(__traits(compiles, st.year = 12));
- static assert(!__traits(compiles, cst.year = 12));
- //static assert(!__traits(compiles, ist.year = 12));
- }
- /++
- Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
- Params:
- year = The year B.C. to set this $(D SysTime)'s year to.
- Throws:
- $(D DateTimeException) if a non-positive value is given.
- Examples:
- --------------------
- auto st = SysTime(DateTime(2010, 1, 1, 7, 30, 0));
- st.yearBC = 1;
- assert(st == SysTime(DateTime(0, 1, 1, 7, 30, 0)));
- st.yearBC = 10;
- assert(st == SysTime(DateTime(-9, 1, 1, 7, 30, 0)));
- --------------------
- +/
- @property void yearBC(int year)
- {
- auto hnsecs = adjTime;
- auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
- if(hnsecs < 0)
- {
- hnsecs += convert!("hours", "hnsecs")(24);
- --days;
- }
- auto date = Date(cast(int)days);
- date.yearBC = year;
- immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
- adjTime = newDaysHNSecs + hnsecs;
- }
- //Verify Examples
- version(testStdDateTime) unittest
- {
- auto st = SysTime(DateTime(2010, 1, 1, 7, 30, 0));
- st.yearBC = 1;
- assert(st == SysTime(DateTime(0, 1, 1, 7, 30, 0)));
- st.yearBC = 10;
- assert(st == SysTime(DateTime(-9, 1, 1, 7, 30, 0)));
- }
- version(testStdDateTime) unittest
- {
- static void test(SysTime st, int year, in SysTime expected, size_t line = __LINE__)
- {
- st.yearBC = year;
- _assertPred!"=="(st, expected, format("SysTime: %s", st), __FILE__, line);
- }
- foreach(st; chain(testSysTimesBC, testSysTimesAD))
- {
- auto dt = cast(DateTime)st;
- foreach(year; testYearsBC)
- {
- auto e = SysTime(DateTime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second),
- st.fracSec,
- st.timezone);
- test(st, (year * -1) + 1, e);
- }
- }
- foreach(st; [testSysTimesBC[0], testSysTimesBC[$ - 1],
- testSysTimesAD[0], testSysTimesAD[$ - 1]])
- {
- foreach(year; testYearsBC)
- assertThrown!DateTimeException(st.yearBC = year);
- }
- foreach(fs; testFracSecs)
- {
- foreach(tz; testTZs)
- {
- foreach(tod; testTODs)
- {
- test(SysTime(DateTime(Date(-1999, 2, 28), tod), fs, tz), 2001,
- SysTime(DateTime(Date(-2000, 2, 28), tod), fs, tz));
- test(SysTime(DateTime(Date(-2000, 2, 28), tod), fs, tz), 2000,
- SysTime(DateTime(Date(-1999, 2, 28), tod), fs, tz));
- }
- foreach(tod; testTODsThrown)
- {
- auto st = SysTime(DateTime(Date(-2000, 2, 29), tod), fs, tz);
- assertThrown!DateTimeException(st.year = -1999);
- }
- }
- }
- auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
- const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
- //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
- static assert(__traits(compiles, st.yearBC = 12));
- static assert(!__traits(compiles, cst.yearBC = 12));
- //static assert(!__traits(compiles, ist.yearBC = 12));
- }
- /++
- Month of a Gregorian Year.
- Examples:
- --------------------
- assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).month == 7);
- assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).month == 10);
- assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).month == 4);
- --------------------
- +/
- @property Month month() const nothrow
- {
- return (cast(Date)this).month;
- }
- //Verify Examples.
- version(testStdDateTime) unittest
- {
- assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).month == 7);
- assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).month == 10);
- assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).month == 4);
- }
- version(testStdDateTime) unittest
- {
- static void test(SysTime sysTime, Month expected, size_t line = __LINE__)
- {
- _assertPred!"=="(sysTime.month, expected,
- format("Value given: %s", sysTime), __FILE__, line);
- }
- test(SysTime(0, UTC()), Month.jan);
- test(SysTime(1, UTC()), Month.jan);
- test(SysTime(-1, UTC()), Month.dec);
- foreach(year; chain(testYearsBC, testYearsAD))
- {
- foreach(md; testMonthDays)
- {
- foreach(tod; testTODs)
- {
- auto dt = DateTime(Date(year, md.month, md.day), tod);
- foreach(fs; testFracSecs)
- {
- foreach(tz; testTZs)
- test(SysTime(dt, fs, tz), md.month);
- }
- }
- }
- }
- const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
- //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
- static assert(__traits(compiles, cst.month));
- //static assert(__traits(compiles, ist.month));
- }
- /++
- Month of a Gregorian Year.
- Params:
- month = The month to set this $(D SysTime)'s month to.
- Throws:
- $(D DateTimeException) if the given month is not a valid month.
- +/
- @property void month(Month month)
- {
- auto hnsecs = adjTime;
- auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
- if(hnsecs < 0)
- {
- hnsecs += convert!("hours", "hnsecs")(24);
- --days;
- }
- auto date = Date(cast(int)days);
- date.month = month;
- immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
- adjTime = newDaysHNSecs + hnsecs;
- }
- version(testStdDateTime) unittest
- {
- static void test(SysTime st, Month month, in SysTime expected, size_t line = __LINE__)
- {
- st.month = cast(Month)month;
- _assertPred!"=="(st, expected, "", __FILE__, line);
- }
- foreach(st; chain(testSysTimesBC, testSysTimesAD))
- {
- auto dt = cast(DateTime)st;
- foreach(md; testMonthDays)
- {
- if(st.day > maxDay(dt.year, md.month))
- continue;
- auto e = SysTime(DateTime(dt.year, md.month, dt.day, dt.hour, dt.minute, dt.second),
- st.fracSec,
- st.timezone);
- test(st, md.month, e);
- }
- }
- foreach(fs; testFracSecs)
- {
- foreach(tz; testTZs)
- {
- foreach(tod; testTODs)
- {
- foreach(year; filter!((a){return yearIsLeapYear(a);})
- (chain(testYearsBC, testYearsAD)))
- {
- test(SysTime(DateTime(Date(year, 1, 29), tod), fs, tz),
- Month.feb,
- SysTime(DateTime(Date(year, 2, 29), tod), fs, tz));
- }
- foreach(year; chain(testYearsBC, testYearsAD))
- {
- test(SysTime(DateTime(Date(year, 1, 28), tod), fs, tz),
- Month.feb,
- SysTime(DateTime(Date(year, 2, 28), tod), fs, tz));
- test(SysTime(DateTime(Date(year, 7, 30), tod), fs, tz),
- Month.jun,
- SysTime(DateTime(Date(year, 6, 30), tod), fs, tz));
- }
- }
- }
- }
- foreach(fs; [testFracSecs[0], testFracSecs[$-1]])
- {
- foreach(tz; testTZs)
- {
- foreach(tod; testTODsThrown)
- {
- foreach(year; [testYearsBC[$-3], testYearsBC[$-2],
- testYearsBC[$-2], testYearsAD[0],
- testYearsAD[$-2], testYearsAD[$-1]])
- {
- auto day = yearIsLeapYear(year) ? 30 : 29;
- auto st1 = SysTime(DateTime(Date(year, 1, day), tod), fs, tz);
- assertThrown!DateTimeException(st1.month = Month.feb);
- auto st2 = SysTime(DateTime(Date(year, 7, 31), tod), fs, tz);
- assertThrown!DateTimeException(st2.month = Month.jun);
- }
- }
- }
- }
- const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
- //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
- static assert(!__traits(compiles, cst.month = 12));
- //static assert(!__traits(compiles, ist.month = 12));
- }
- /++
- Day of a Gregorian Month.
- Examples:
- --------------------
- assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).day == 6);
- assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).day == 4);
- assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).day == 5);
- --------------------
- +/
- @property ubyte day() const nothrow
- {
- return (cast(Date)this).day;
- }
- //Verify Examples.
- version(testStdDateTime) unittest
- {
- assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).day == 6);
- assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).day == 4);
- assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).day == 5);
- }
- version(testStdDateTime) unittest
- {
- static void test(SysTime sysTime, int expected, size_t line = __LINE__)
- {
- _assertPred!"=="(sysTime.day, expected,
- format("Value given: %s", sysTime), __FILE__, line);
- }
- test(SysTime(0, UTC()), 1);
- test(SysTime(1, UTC()), 1);
- test(SysTime(-1, UTC()), 31);
- foreach(year; chain(testYearsBC, testYearsAD))
- {
- foreach(md; testMonthDays)
- {
- foreach(tod; testTODs)
- {
- auto dt = DateTime(Date(year, md.month, md.day), tod);
- foreach(tz; testTZs)
- {
- foreach(fs; testFracSecs)
- test(SysTime(dt, fs, tz), md.day);
- }
- }
- }
- }
- const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
- //immutable ist = SysTime(…
Large files files are truncated, but you can click here to view the full file