289 changes: 169 additions & 120 deletions std/datetime.d
Original file line number Diff line number Diff line change
Expand Up @@ -107,31 +107,26 @@ module std.datetime;

public import core.time;

import core.exception;
import core.stdc.time;
import core.exception; // AssertError

import std.exception;
import std.range.primitives;
import std.traits;
import std.exception; // assertThrown, enforce
import std.range.primitives; // back, ElementType, empty, front, hasLength,
// hasSlicing, isRandomAccessRange, popFront
import std.traits; // isIntegral, isSafe, isSigned, isSomeString, Unqual
// FIXME
import std.functional; //: unaryFun;

version(Windows)
{
import core.stdc.time; // time_t
import core.sys.windows.windows;
import core.sys.windows.winsock2;
import std.windows.registry;
}
else version(Posix)
{
import core.sys.posix.stdlib;
import core.sys.posix.sys.time;
import core.sys.posix.signal : timespec;
}

version(unittest)
{
import std.stdio;
import core.sys.posix.sys.types; // time_t
}

unittest
Expand Down Expand Up @@ -328,6 +323,7 @@ public:
unittest
{
import std.format : format;
import std.stdio : writefln;
assert(currTime().timezone is LocalTime());
assert(currTime(UTC()).timezone is UTC());

Expand All @@ -337,6 +333,7 @@ public:
// then, but for now, we're just not going to run this test on Windows.
version(Posix)
{
static import core.stdc.time;
static import std.math;
immutable unixTimeD = currTime().toUnixTime();
immutable unixTimeC = core.stdc.time.time(null);
Expand Down Expand Up @@ -402,6 +399,7 @@ public:
}
else version(Posix)
{
static import core.stdc.time;
enum hnsecsToUnixEpoch = unixTimeToStdTime(0);

version(OSX)
Expand All @@ -410,6 +408,7 @@ public:
return unixTimeToStdTime(core.stdc.time.time(null));
else
{
import core.sys.posix.sys.time : gettimeofday, timeval;
timeval tv;
if (gettimeofday(&tv, null) != 0)
throw new TimeException("Call to gettimeofday() failed");
Expand All @@ -424,7 +423,8 @@ public:
return unixTimeToStdTime(core.stdc.time.time(null));
else
{
import core.sys.linux.time;
import core.sys.linux.time : CLOCK_REALTIME_COARSE;
import core.sys.posix.time : clock_gettime, CLOCK_REALTIME;
static if (clockType == ClockType.coarse) alias clockArg = CLOCK_REALTIME_COARSE;
else static if (clockType == ClockType.normal) alias clockArg = CLOCK_REALTIME;
else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
Expand Down Expand Up @@ -458,6 +458,7 @@ public:
return unixTimeToStdTime(core.stdc.time.time(null));
else
{
import core.sys.posix.sys.time : timeval;
timeval tv;
if (gettimeofday(&tv, null) != 0)
throw new TimeException("Call to gettimeofday() failed");
Expand Down Expand Up @@ -492,16 +493,17 @@ public:

unittest
{
import std.math : abs;
import std.format : format;
import std.math : abs;
import std.meta : AliasSeq;
import std.stdio : writefln;
enum limit = convert!("seconds", "hnsecs")(2);

auto norm1 = Clock.currStdTime;
auto norm2 = Clock.currStdTime;
assert(norm1 <= norm2, format("%s %s", norm1, norm2));
assert(abs(norm1 - norm2) <= limit);

import std.meta : AliasSeq;
foreach (ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second))
{
scope(failure) writefln("ClockType.%s", ct);
Expand Down Expand Up @@ -649,6 +651,8 @@ private:
+/
struct SysTime
{
import core.stdc.time : tm;
version(Posix) import core.sys.posix.sys.time : timeval;
import std.typecons : Rebindable;

public:
Expand Down Expand Up @@ -939,7 +943,7 @@ public:

unittest
{
import std.range;
import std.range : chain;
assert(SysTime(DateTime.init, UTC()) == SysTime(0, UTC()));
assert(SysTime(DateTime.init, UTC()) == SysTime(0));
assert(SysTime(Date.init, UTC()) == SysTime(0));
Expand Down Expand Up @@ -1005,7 +1009,9 @@ public:

unittest
{
import std.range;
import std.algorithm.iteration : map;
import std.array : array;
import std.range : chain;
assert(SysTime(DateTime.init, UTC()).opCmp(SysTime(0, UTC())) == 0);
assert(SysTime(DateTime.init, UTC()).opCmp(SysTime(0)) == 0);
assert(SysTime(Date.init, UTC()).opCmp(SysTime(0)) == 0);
Expand Down Expand Up @@ -1073,7 +1079,7 @@ public:

unittest
{
import std.range;
import std.range : chain;
static void test(SysTime sysTime, long expected)
{
import std.format : format;
Expand Down Expand Up @@ -1147,7 +1153,7 @@ public:

unittest
{
import std.range;
import std.range : chain;
static void test(SysTime st, int year, in SysTime expected)
{
st.year = year;
Expand Down Expand Up @@ -1214,6 +1220,7 @@ public:

unittest
{
import std.exception : assertNotThrown;
import std.format : format;
foreach (st; testSysTimesBC)
{
Expand Down Expand Up @@ -1274,7 +1281,7 @@ public:

unittest
{
import std.range;
import std.range : chain;
static void test(SysTime st, int year, in SysTime expected)
{
import std.format : format;
Expand Down Expand Up @@ -1349,7 +1356,7 @@ public:

unittest
{
import std.range;
import std.range : chain;
static void test(SysTime sysTime, Month expected)
{
import std.format : format;
Expand Down Expand Up @@ -1414,7 +1421,8 @@ public:

unittest
{
import std.range;
import std.algorithm.iteration : filter;
import std.range : chain;

static void test(SysTime st, Month month, in SysTime expected)
{
Expand Down Expand Up @@ -1509,7 +1517,7 @@ public:

unittest
{
import std.range;
import std.range : chain;

static void test(SysTime sysTime, int expected)
{
Expand Down Expand Up @@ -1577,7 +1585,8 @@ public:
unittest
{
import std.format : format;
import std.range;
import std.range : chain;
import std.traits : EnumMembers;

foreach (day; chain(testDays))
{
Expand Down Expand Up @@ -1665,8 +1674,8 @@ public:

unittest
{
import std.range;
import std.format : format;
import std.range : chain;

static void test(SysTime sysTime, int expected)
{
Expand Down Expand Up @@ -1742,8 +1751,8 @@ public:

unittest
{
import std.range;
import std.format : format;
import std.range : chain;

foreach (hour; chain(testHours))
{
Expand Down Expand Up @@ -1790,8 +1799,8 @@ public:

unittest
{
import std.range;
import std.format : format;
import std.range : chain;

static void test(SysTime sysTime, int expected)
{
Expand Down Expand Up @@ -1870,8 +1879,8 @@ public:

unittest
{
import std.range;
import std.format : format;
import std.range : chain;

foreach (minute; testMinSecs)
{
Expand Down Expand Up @@ -1919,8 +1928,8 @@ public:

unittest
{
import std.range;
import std.format : format;
import std.range : chain;

static void test(SysTime sysTime, int expected)
{
Expand Down Expand Up @@ -2001,8 +2010,8 @@ public:

unittest
{
import std.range;
import std.format : format;
import std.range : chain;

foreach (second; testMinSecs)
{
Expand Down Expand Up @@ -2057,7 +2066,7 @@ public:

unittest
{
import std.range;
import std.range : chain;

assert(SysTime(0, UTC()).fracSecs == Duration.zero);
assert(SysTime(1, UTC()).fracSecs == hnsecs(1));
Expand Down Expand Up @@ -2147,8 +2156,8 @@ public:

unittest
{
import std.range;
import std.format : format;
import std.range : chain;

foreach (fracSec; testFracSecs)
{
Expand Down Expand Up @@ -2554,8 +2563,8 @@ public:

unittest
{
assert(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime() == 0);
import std.meta : AliasSeq;
assert(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime() == 0);
foreach (units; AliasSeq!("hnsecs", "usecs", "msecs"))
assert(SysTime(DateTime(1970, 1, 1, 0, 0, 0), dur!units(1), UTC()).toUnixTime() == 0);
assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toUnixTime() == 1);
Expand Down Expand Up @@ -8546,10 +8555,10 @@ public:
static SysTime fromISOString(S)(in S isoString, immutable TimeZone tz = null) @safe
if (isSomeString!S)
{
import std.string : strip;
import std.algorithm.searching : startsWith, find;
import std.conv : to;
import std.algorithm : startsWith, find;
import std.format : format;
import std.string : strip;

auto dstr = to!dstring(strip(isoString));
immutable skipFirst = dstr.startsWith('+', '-') != 0;
Expand Down Expand Up @@ -8785,10 +8794,10 @@ public:
static SysTime fromISOExtString(S)(in S isoExtString, immutable TimeZone tz = null) @safe
if (isSomeString!(S))
{
import std.string : strip;
import std.algorithm.searching : countUntil, find;
import std.conv : to;
import std.algorithm : countUntil, find;
import std.format : format;
import std.string : strip;

auto dstr = to!dstring(strip(isoExtString));

Expand Down Expand Up @@ -8998,10 +9007,10 @@ public:
static SysTime fromSimpleString(S)(in S simpleString, immutable TimeZone tz = null) @safe
if (isSomeString!(S))
{
import std.string : strip;
import std.algorithm.searching : countUntil, find;
import std.conv : to;
import std.algorithm : countUntil, find;
import std.format : format;
import std.string : strip;

auto dstr = to!dstring(strip(simpleString));

Expand Down Expand Up @@ -9295,6 +9304,7 @@ public:

unittest
{
import std.exception : assertNotThrown;
assert(Date(1, 1, 1) == Date.init);

static void testDate(in Date date, int year, int month, int day)
Expand Down Expand Up @@ -9483,7 +9493,7 @@ public:

unittest
{
import std.range;
import std.range : chain;

//Test A.D.
foreach (gd; chain(testGregDaysBC, testGregDaysAD))
Expand Down Expand Up @@ -9850,8 +9860,8 @@ public:

unittest
{
import std.range;
import std.format : format;
import std.range : chain;

static void test(Date date, int expected)
{
Expand Down Expand Up @@ -9889,6 +9899,7 @@ public:

unittest
{
import std.exception : assertNotThrown;
static void testDate(Date date, int day)
{
date.day = day;
Expand Down Expand Up @@ -12244,7 +12255,8 @@ public:

unittest
{
import std.range;
import std.algorithm.iteration : filter;
import std.range : chain;

foreach (year; filter!((a){return !yearIsLeapYear(a);})
(chain(testYearsBC, testYearsAD)))
Expand Down Expand Up @@ -12403,7 +12415,7 @@ public:

unittest
{
import std.range;
import std.range : chain;

foreach (gd; chain(testGregDaysBC, testGregDaysAD))
assert(gd.date.dayOfGregorianCal == gd.day);
Expand Down Expand Up @@ -12967,11 +12979,11 @@ public:
static Date fromISOString(S)(in S isoString) @safe pure
if (isSomeString!S)
{
import std.algorithm.searching : all, startsWith;
import std.ascii : isDigit;
import std.string : strip;
import std.conv : to;
import std.algorithm : all, startsWith;
import std.format : format;
import std.string : strip;

auto dstr = to!dstring(strip(isoString));

Expand Down Expand Up @@ -13089,11 +13101,11 @@ public:
static Date fromISOExtString(S)(in S isoExtString) @safe pure
if (isSomeString!(S))
{
import std.algorithm.searching : all, startsWith;
import std.ascii : isDigit;
import std.string : strip;
import std.conv : to;
import std.algorithm : all, startsWith;
import std.format : format;
import std.string : strip;

auto dstr = to!dstring(strip(isoExtString));

Expand Down Expand Up @@ -13216,11 +13228,11 @@ public:
static Date fromSimpleString(S)(in S simpleString) @safe pure
if (isSomeString!(S))
{
import std.algorithm.searching : all, startsWith;
import std.ascii : isDigit;
import std.string : strip;
import std.conv : to;
import std.algorithm : all, startsWith;
import std.format : format;
import std.string : strip;

auto dstr = to!dstring(strip(simpleString));

Expand Down Expand Up @@ -14485,11 +14497,11 @@ public:
static TimeOfDay fromISOString(S)(in S isoString) @safe pure
if (isSomeString!S)
{
import std.algorithm.searching : all;
import std.ascii : isDigit;
import std.string : strip;
import std.conv : to;
import std.algorithm : all;
import std.format : format;
import std.string : strip;

auto dstr = to!dstring(strip(isoString));

Expand Down Expand Up @@ -14593,11 +14605,11 @@ public:
static TimeOfDay fromISOExtString(S)(in S isoExtString) @safe pure
if (isSomeString!S)
{
import std.algorithm.searching : all;
import std.ascii : isDigit;
import std.string : strip;
import std.conv : to;
import std.algorithm : all;
import std.format : format;
import std.string : strip;

auto dstr = to!dstring(strip(isoExtString));

Expand Down Expand Up @@ -15507,8 +15519,8 @@ public:

unittest
{
import std.range;
import std.format : format;
import std.range : chain;

static void test(DateTime dateTime, int expected)
{
Expand Down Expand Up @@ -15548,6 +15560,7 @@ public:

unittest
{
import std.exception : assertNotThrown;
static void testDT(DateTime dt, int day)
{
dt.day = day;
Expand Down Expand Up @@ -17854,10 +17867,10 @@ public:
static DateTime fromISOString(S)(in S isoString) @safe pure
if (isSomeString!S)
{
import std.string : strip;
import std.algorithm.searching : countUntil;
import std.conv : to;
import std.algorithm : countUntil;
import std.format : format;
import std.string : strip;

immutable dstr = to!dstring(strip(isoString));

Expand Down Expand Up @@ -17942,10 +17955,10 @@ public:
static DateTime fromISOExtString(S)(in S isoExtString) @safe pure
if (isSomeString!(S))
{
import std.string : strip;
import std.algorithm.searching : countUntil;
import std.conv : to;
import std.algorithm : countUntil;
import std.format : format;
import std.string : strip;

immutable dstr = to!dstring(strip(isoExtString));

Expand Down Expand Up @@ -18028,10 +18041,10 @@ public:
static DateTime fromSimpleString(S)(in S simpleString) @safe pure
if (isSomeString!(S))
{
import std.string : strip;
import std.algorithm.searching : countUntil;
import std.conv : to;
import std.algorithm : countUntil;
import std.format : format;
import std.string : strip;

immutable dstr = to!dstring(strip(simpleString));

Expand Down Expand Up @@ -26715,6 +26728,8 @@ private:
//Test that IntervalRange satisfies the range predicates that it's supposed to satisfy.
unittest
{
import std.range.primitives : hasAssignableElements, hasSwappableElements,
isBidirectionalRange, isForwardRange, isInfinite, isInputRange;
static assert(isInputRange!(IntervalRange!(Date, Direction.fwd)));
static assert(isForwardRange!(IntervalRange!(Date, Direction.fwd)));

Expand Down Expand Up @@ -26881,6 +26896,7 @@ unittest
//Test IntervalRange's popFront().
unittest
{
import std.range.primitives : walkLength;
//fwd
{
auto emptyRange = Interval!Date(
Expand Down Expand Up @@ -27186,6 +27202,8 @@ private:
//Test that PosInfIntervalRange satisfies the range predicates that it's supposed to satisfy.
unittest
{
import std.range.primitives : hasAssignableElements, hasSwappableElements,
isBidirectionalRange, isForwardRange, isInfinite, isInputRange;
static assert(isInputRange!(PosInfIntervalRange!Date));
static assert(isForwardRange!(PosInfIntervalRange!Date));
static assert(isInfinite!(PosInfIntervalRange!Date));
Expand Down Expand Up @@ -27269,7 +27287,7 @@ unittest
//Test PosInfIntervalRange's popFront().
unittest
{
import std.range;
import std.range : take;
auto range = PosInfInterval!Date(Date(2010, 7, 4)).fwdRange(everyDayOfWeek!Date(DayOfWeek.wed), PopFirst.yes);
auto expected = range.front;

Expand Down Expand Up @@ -27474,6 +27492,8 @@ private:
//Test that NegInfIntervalRange satisfies the range predicates that it's supposed to satisfy.
unittest
{
import std.range.primitives : hasAssignableElements, hasSwappableElements,
isBidirectionalRange, isForwardRange, isInfinite, isInputRange;
static assert(isInputRange!(NegInfIntervalRange!Date));
static assert(isForwardRange!(NegInfIntervalRange!Date));
static assert(isInfinite!(NegInfIntervalRange!Date));
Expand Down Expand Up @@ -27558,7 +27578,7 @@ unittest
//Test NegInfIntervalRange's popFront().
unittest
{
import std.range;
import std.range : take;

auto range = NegInfInterval!Date(
Date(2012, 1, 7)
Expand Down Expand Up @@ -27809,11 +27829,12 @@ public:
//reads a time zone file.
unittest
{
import std.path : chainPath;
import std.file : exists, isFile;
import std.conv : to;
import std.file : exists, isFile;
import std.format : format;

import std.path : chainPath;
import std.stdio : writefln;
import std.typecons : tuple;

version(Posix) scope(exit) clearTZEnvVar();

Expand Down Expand Up @@ -27860,6 +27881,7 @@ public:

static void testTM(in SysTime st)
{
import core.stdc.time : localtime, tm;
time_t unixTime = st.toUnixTime();
tm* osTimeInfo = localtime(&unixTime);
tm ourTimeInfo = st.toTM();
Expand Down Expand Up @@ -28116,8 +28138,8 @@ public:
return PosixTimeZone.getInstalledTZNames(subName);
else version(Windows)
{
import std.array : appender;
import std.algorithm : startsWith, sort;
import std.array : appender;
import std.format : format;

auto windowsNames = WindowsTimeZone.getInstalledTZNames();
Expand All @@ -28129,7 +28151,6 @@ public:

version(unittest)
{
import std.string;
assert(tzName !is null, format("TZName which is missing: %s", winName));
}

Expand All @@ -28144,6 +28165,8 @@ public:

unittest
{
import std.exception : assertNotThrown;
import std.stdio : writefln;
static void testPZSuccess(string tzName)
{
scope(failure) writefln("TZName which threw: %s", tzName);
Expand Down Expand Up @@ -28245,6 +28268,7 @@ public:
{
version(Posix)
{
import core.stdc.time : tzname;
import std.conv : to;
try
return to!string(tzname[0]);
Expand Down Expand Up @@ -28316,6 +28340,7 @@ public:
{
version(Posix)
{
import core.stdc.time : tzname;
import std.conv : to;
try
return to!string(tzname[1]);
Expand Down Expand Up @@ -28451,6 +28476,7 @@ public:
+/
override bool dstInEffect(long stdTime) @trusted const nothrow
{
import core.stdc.time : localtime, tm;
time_t unixTime = stdTimeToUnixTime(stdTime);

version(Posix)
Expand Down Expand Up @@ -28500,6 +28526,7 @@ public:
{
version(Posix)
{
import core.stdc.time : localtime, tm;
time_t unixTime = stdTimeToUnixTime(stdTime);
tm* timeInfo = localtime(&unixTime);

Expand Down Expand Up @@ -28536,6 +28563,7 @@ public:
{
version(Posix)
{
import core.stdc.time : localtime, tm;
time_t unixTime = stdTimeToUnixTime(adjTime);

immutable past = unixTime - cast(time_t)convert!("days", "seconds")(1);
Expand Down Expand Up @@ -28569,6 +28597,7 @@ public:
unittest
{
import std.format : format;
import std.typecons : tuple;

assert(LocalTime().tzToUTC(LocalTime().utcToTZ(0)) == 0);
assert(LocalTime().utcToTZ(LocalTime().tzToUTC(0)) == 0);
Expand Down Expand Up @@ -28721,6 +28750,7 @@ private:
// operation the first time that LocalTime() is called.
static immutable(LocalTime) singleton() @trusted
{
import core.stdc.time : tzset;
import std.concurrency : initOnce;
static instance = new immutable(LocalTime)();
static shared bool guard;
Expand Down Expand Up @@ -29117,9 +29147,9 @@ private:
static immutable(SimpleTimeZone) fromISOString(S)(S isoString) @safe pure
if (isSomeString!S)
{
import std.algorithm.searching : startsWith, countUntil, all;
import std.ascii : isDigit;
import std.conv : to;
import std.algorithm : startsWith, countUntil, all;
import std.format : format;

auto dstr = to!dstring(isoString);
Expand Down Expand Up @@ -29262,9 +29292,9 @@ private:
static immutable(SimpleTimeZone) fromISOExtString(S)(S isoExtString) @safe pure
if (isSomeString!S)
{
import std.algorithm.searching : startsWith, countUntil, all;
import std.ascii : isDigit;
import std.conv : to;
import std.algorithm : startsWith, countUntil, all;
import std.format : format;

auto dstr = to!dstring(isoExtString);
Expand Down Expand Up @@ -29436,11 +29466,12 @@ private:
+/
final class PosixTimeZone : TimeZone
{
import std.stdio : File;
import std.path : extension;
import std.algorithm.searching : countUntil, canFind, startsWith;
import std.file : isDir, isFile, exists, dirEntries, SpanMode, DirEntry;
import std.path : extension;
import std.stdio : File;
import std.string : strip, representation;
import std.algorithm : countUntil, canFind, startsWith;
import std.traits : isArray, isSomeChar;
public:

/++
Expand Down Expand Up @@ -29600,7 +29631,7 @@ public:
// directory.
static immutable(PosixTimeZone) getTimeZone(string name, string tzDatabaseDir = defaultTZDatabaseDir) @trusted
{
import std.algorithm : sort;
import std.algorithm.sorting : sort;
import std.range : retro;
import std.format : format;
import std.path : asNormalizedPath, chainPath;
Expand Down Expand Up @@ -29950,8 +29981,8 @@ public:
+/
static string[] getInstalledTZNames(string subName = "", string tzDatabaseDir = defaultTZDatabaseDir) @trusted
{
import std.algorithm.sorting : sort;
import std.array : appender;
import std.algorithm : sort;
import std.format : format;

version(Posix)
Expand All @@ -29970,7 +30001,8 @@ public:

version(Android)
{
import std.algorithm : copy, filter;
import std.algorithm.iteration : filter;
import std.algorithm.mutation : copy;
tzdataIndex(tzDatabaseDir)
.byKey
.filter!(a => a.startsWith(subName))
Expand Down Expand Up @@ -30004,6 +30036,8 @@ public:

version(Posix) unittest
{
import std.exception : assertNotThrown;
import std.stdio : writefln;
static void testPTZSuccess(string tzName)
{
scope(failure) writefln("TZName which threw: %s", tzName);
Expand Down Expand Up @@ -30158,7 +30192,7 @@ private:
static T readVal(T)(ref File tzFile) @trusted
if ((isIntegral!T || isSomeChar!T) || is(Unqual!T == bool))
{
import std.bitmanip;
import std.bitmanip : bigEndianToNative;
T[1] buff;

_enforceValidTZFile(!tzFile.eof);
Expand Down Expand Up @@ -30474,10 +30508,10 @@ else version(Windows)
{
final class WindowsTimeZone : TimeZone
{
import std.format : format;
import std.conv : to;
import std.algorithm : sort;
import std.algorithm.sorting : sort;
import std.array : appender;
import std.conv : to;
import std.format : format;

public:

Expand Down Expand Up @@ -30568,6 +30602,8 @@ else version(Windows)

unittest
{
import std.exception : assertNotThrown;
import std.stdio : writefln;
static void testWTZSuccess(string tzName)
{
scope(failure) writefln("TZName which threw: %s", tzName);
Expand Down Expand Up @@ -30815,10 +30851,10 @@ else version(Posix)
{
void setTZEnvVar(string tzDatabaseName) @trusted nothrow
{
import core.stdc.time : tzset;
import core.sys.posix.stdlib : setenv;
import std.internal.cstring : tempCString;
import std.path : asNormalizedPath, chainPath;
import core.sys.posix.stdlib : setenv;
import core.sys.posix.time : tzset;

version(Android)
auto value = asNormalizedPath(tzDatabaseName);
Expand All @@ -30831,8 +30867,8 @@ else version(Posix)

void clearTZEnvVar() @trusted nothrow
{
import core.stdc.time : tzset;
import core.sys.posix.stdlib : unsetenv;
import core.sys.posix.time : tzset;

unsetenv("TZ");
tzset();
Expand Down Expand Up @@ -30907,7 +30943,9 @@ TZConversions parseTZConversions(string windowsZonesXMLText) @safe pure
// This is a bit hacky, since it doesn't properly read XML, but it avoids
// needing to pull in std.xml (which we're theoretically replacing at some
// point anyway.
import std.algorithm : find, sort, uniq;
import std.algorithm.iteration : uniq;
import std.algorithm.searching : find;
import std.algorithm.sorting : sort;
import std.array : array, split;
import std.string : lineSplitter;

Expand Down Expand Up @@ -30960,7 +30998,9 @@ TZConversions parseTZConversions(string windowsZonesXMLText) @safe pure

unittest
{
import std.algorithm;
import std.algorithm.comparison : equal;
import std.algorithm.iteration : uniq;
import std.algorithm.sorting : isSorted;

// Reduced text from http://unicode.org/cldr/data/common/supplemental/windowsZones.xml
auto sampleFileText =
Expand Down Expand Up @@ -32103,6 +32143,7 @@ unittest
+/
template isTimePoint(T)
{
import std.traits : FunctionAttribute, functionAttributes;
enum isTimePoint = hasMin &&
hasMax &&
hasOverloadedOpBinaryWithDuration &&
Expand Down Expand Up @@ -32805,12 +32846,14 @@ SysTime parseRFC822DateTime(R)(R value) @safe
if (isRandomAccessRange!R && hasSlicing!R && hasLength!R &&
(is(Unqual!(ElementType!R) == char) || is(Unqual!(ElementType!R) == ubyte)))
{
import std.functional : not;
import std.algorithm.searching : find, all;
import std.ascii : isDigit, isAlpha, isPrintable;
import std.typecons : Rebindable;
import std.string : capitalize, format;
import std.conv : to;
import std.algorithm : find, all;
import std.functional : not;
import std.range.primitives : ElementEncodingType;
import std.string : capitalize, format;
import std.traits : EnumMembers, isArray;
import std.typecons : Rebindable;

void stripAndCheckLen(R valueBefore, size_t minLen, size_t line = __LINE__)
{
Expand Down Expand Up @@ -33019,7 +33062,6 @@ unittest

version(unittest) void testParse822(alias cr)(string str, SysTime expected, size_t line = __LINE__)
{
import std.string;
import std.format : format;
auto value = cr(str);
auto result = parseRFC822DateTime(value);
Expand All @@ -33038,21 +33080,23 @@ version(unittest) void testBadParse822(alias cr)(string str, size_t line = __LIN

unittest
{
import std.algorithm;
import std.ascii;
import std.algorithm.iteration : map;
import std.array : array;
import std.ascii : letters;
import std.format : format;
import std.meta;
import std.range;
import std.string;
import std.typecons;
import std.meta : AliasSeq;
import std.range : chain, iota, take;
import std.stdio : writefln, writeln;
import std.string : representation;

static struct Rand3Letters
{
enum empty = false;
@property auto front() { return _mon; }
void popFront()
{
import std.random;
import std.exception : assumeUnique;
import std.random : rndGen;
_mon = rndGen.map!(a => letters[a % letters.length])().take(3).array().assumeUnique();
}
string _mon;
Expand Down Expand Up @@ -33163,7 +33207,7 @@ unittest
test(format("17 %s 2012 00:05 +0000", mon), SysTime(DateTime(2012, i + 1, 17, 0, 5, 0), UTC()));
}

import std.uni;
import std.uni : toLower, toUpper;
foreach (mon; chain(_monthNames[].map!(a => toLower(a))(),
_monthNames[].map!(a => toUpper(a))(),
["Jam", "Jen", "Fec", "Fdb", "Mas", "Mbr", "Aps", "Aqr", "Mai", "Miy",
Expand Down Expand Up @@ -33307,13 +33351,14 @@ unittest
// Obsolete Format per section 4.3 of RFC 5322.
unittest
{
import std.algorithm;
import std.ascii;
import std.algorithm.iteration : filter, map;
import std.ascii : letters;
import std.exception : collectExceptionMsg;
import std.format : format;
import std.meta;
import std.range;
import std.string;
import std.typecons;
import std.meta : AliasSeq;
import std.range : chain, iota;
import std.stdio : writefln, writeln;
import std.string : representation;

auto std1 = SysTime(DateTime(2012, 12, 21, 13, 14, 15), UTC());
auto std2 = SysTime(DateTime(2012, 12, 21, 13, 14, 0), UTC());
Expand Down Expand Up @@ -33531,7 +33576,7 @@ unittest
+/
bool validTimeUnits(string[] units...) @safe pure nothrow
{
import std.algorithm : canFind;
import std.algorithm.searching : canFind;
foreach (str; units)
{
if (!canFind(timeStrings[], str))
Expand Down Expand Up @@ -33559,8 +33604,8 @@ bool validTimeUnits(string[] units...) @safe pure nothrow
+/
int cmpTimeUnits(string lhs, string rhs) @safe pure
{
import std.algorithm.searching : countUntil;
import std.format : format;
import std.algorithm : countUntil;

auto tstrings = timeStrings;
immutable indexOfLHS = countUntil(tstrings, lhs);
Expand Down Expand Up @@ -33624,7 +33669,7 @@ template CmpTimeUnits(string lhs, string rhs)
+/
private int cmpTimeUnitsCTFE(string lhs, string rhs) @safe pure nothrow
{
import std.algorithm : countUntil;
import std.algorithm.searching : countUntil;
auto tstrings = timeStrings;
immutable indexOfLHS = countUntil(tstrings, lhs);
immutable indexOfRHS = countUntil(tstrings, rhs);
Expand All @@ -33640,9 +33685,7 @@ private int cmpTimeUnitsCTFE(string lhs, string rhs) @safe pure nothrow
unittest
{
import std.format : format;
import std.meta;
import std.string;
import std.typecons;
import std.meta : AliasSeq;

static string genTest(size_t index)
{
Expand Down Expand Up @@ -34474,6 +34517,8 @@ Month monthFromString(string monthStr) @safe pure

unittest
{
import std.stdio : writeln;
import std.traits : EnumMembers;
foreach (badStr; ["Ja", "Janu", "Januar", "Januarys", "JJanuary", "JANUARY",
"JAN", "january", "jaNuary", "jaN", "jaNuaRy", "jAn"])
{
Expand All @@ -34496,7 +34541,7 @@ template nextSmallerTimeUnits(string units)
if (validTimeUnits(units) &&
timeStrings.front != units)
{
import std.algorithm : countUntil;
import std.algorithm.searching : countUntil;
enum nextSmallerTimeUnits = timeStrings[countUntil(timeStrings, units) - 1];
}

Expand All @@ -34522,7 +34567,7 @@ template nextLargerTimeUnits(string units)
if (validTimeUnits(units) &&
timeStrings.back != units)
{
import std.algorithm : countUntil;
import std.algorithm.searching : countUntil;
enum nextLargerTimeUnits = timeStrings[countUntil(timeStrings, units) + 1];
}

Expand All @@ -34547,6 +34592,7 @@ unittest
static string fracSecsToISOString(int hnsecs) @safe pure nothrow
{
import std.format : format;
import std.range.primitives : popBack;
assert(hnsecs >= 0);

try
Expand Down Expand Up @@ -34600,10 +34646,10 @@ unittest
static Duration fracSecsFromISOString(S)(in S isoString) @trusted pure
if (isSomeString!S)
{
import std.algorithm.searching : all;
import std.ascii : isDigit;
import std.string : representation;
import std.conv : to;
import std.algorithm : all;
import std.string : representation;

if (isoString.empty)
return Duration.zero;
Expand Down Expand Up @@ -34767,10 +34813,11 @@ R _stripCFWS(R)(R range)

unittest
{
import std.algorithm;
import std.meta;
import std.string;
import std.typecons;
import std.algorithm.comparison : equal;
import std.algorithm.iteration : map;
import std.meta : AliasSeq;
import std.stdio : writeln;
import std.string : representation;

foreach (cr; AliasSeq!(function(string a){return cast(ubyte[])a;},
function(string a){return map!(b => cast(char)b)(a.representation);}))
Expand Down Expand Up @@ -34889,7 +34936,8 @@ T _convDigits(T, R)(R str)
unittest
{
import std.conv : to;
import std.range;
import std.range : chain, iota;
import std.stdio : writeln;
foreach (i; chain(iota(0, 101), [250, 999, 1000, 1001, 2345, 9999]))
{
scope(failure) writeln(i);
Expand All @@ -34905,8 +34953,6 @@ unittest

version(unittest)
{
import std.typecons;
import std.algorithm;
//Variables to help in testing.
Duration currLocalDiffFromUTC;
immutable (TimeZone)[] testTZs;
Expand Down Expand Up @@ -35182,6 +35228,8 @@ version(unittest)

void initializeTests()
{
import std.algorithm.sorting : sort;
import std.typecons : Rebindable;
immutable lt = LocalTime().utcToTZ(0);
currLocalDiffFromUTC = dur!"hnsecs"(lt);

Expand Down Expand Up @@ -35246,6 +35294,7 @@ version(unittest)

unittest
{
import std.traits : hasUnsharedAliasing;
/* Issue 6642 */
static assert(!hasUnsharedAliasing!Date);
static assert(!hasUnsharedAliasing!TimeOfDay);
Expand Down