Introduction to std.datetime - D Programming Language

D Programming Language
Report a bug If you spot a problem with this page, click here to create a Bugzilla issue. Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone.

# Introduction to std.datetime

by Jonathan M Davis

## Introduction

In dmd 2.052, the module std.datetime was introduced. It will be replacing std.date entirely. As such, std.date is currently scheduled for deprecation. At a later date it will be deprecated (at which point, you'll have to compile with -d for it to work rather than simply having the compiler complain when you use it), and eventually it will be fully removed from Phobos. What this means is that all new code should be written to use std.datetime and that any code which currently uses std.date is going to need to be refactored to use std.datetime (unless you want to copy std.date to your own code and continue to use it as a non-Phobos module). This article attempts to familiarize you with std.datetime as well as give some advice on how to migrate code from std.date to std.datetime for those who have been using std.date.

std.date is essentially a C-based solution for dates and times. It uses d_time to hold time where d_time is a 64-bit integral value holding the number of milliseconds which have passed since midnight, January 1st, 1970 A.D. in UTC. C, on the other hand, uses time_t to hold time where time_t is an integral value holding the number of seconds which have passed since midnight, January 1st, 1970 A.D. in UTC. Its size varies from architecture to architecture (typically 32 bits on a 32-bit machine and 64 bits on a 64-bit machine, but it varies with the OS and compiler). The exact set of functions that std.date provides for using with d_time aren't the same as what C provides for using with time_t, but their representation of time is virtually the same.

std.datetime, on the other hand, is very much an object-oriented solution, and it's not C-based at all. Rather, its API is based on Boost's types for handling dates and times (though they're far from identical). So, it's a bit of a paradigm shift to move from std.date to std.datetime. Don't expect much to be the same between the two. However, std.datetime is not plagued with the same bugs that std.date is plagued with (std.date being quite buggy in general), and it provides much more functionality than std.date does. So, in the long run at least, dealing with std.datetime should be much more pleasant - though migration is likely to present a bit of a hurdle in the short term.

## Basic Concepts of std.datetime

Most things in std.datetime are based on and/or use three concepts:

- Duration: A duration of time with units. e.g. 4 days or 72 seconds.
- Time Point: A specific point in time. e.g. 21:00 or May 7th, 2013.
- Time Interval: A fixed period of time. e.g. [02:44 - 12:22) or [February 4th, 1922 - January 17th, 1955).

### Durations

The duration types can actually be found in core.time. They are Duration and TickDuration. TickDuration is intended for precision timing and is used primarily with StopWatch and the benchmarking functions found in std.datetime - such as benchmark - and you're unlikely to use it outside of using them. Duration, on the other hand, you're likely to use quite a bit.

Duration holds its time internally as hecto-nanoseconds (100 ns), so that's its maximum precision. It has property functions for both returning the duration of time truncated to a particular unit (such as the days and seconds property functions) as well as a function for returning the total number of a particular unit in that Duration (the total function).

Generally, a Duration is created in one of two ways: by subtracting two time points or with the core.time.dur function. So, for instance, if you subtracted a time point which represented 17:02 from a time point which represented 6:07, you'd get a Duration which represented 10 hours and 55 minutes. Or, if you wanted to create a Duration directly, then you'd use the dur function and make a call like dur!"hours"(17) or dur!"seconds"(234).

    auto duration = TimeOfDay(17, 2) - TimeOfDay(6, 7);
    assert(duration == dur!"hours"(10) + dur!"minutes"(55));
    assert(duration.hours == 10);
    assert(duration.minutes == 55);
    assert(duration.total!"hours"() == 10);
    assert(duration.total!"minutes"() == 655);
    assert(duration.total!"hnsecs"() == 393_000_000_000);

Like any number, Durations can be added together or subtracted from. However, unlike a naked number, they have units associated with them and will handle the appropriate conversions. Also, it should be noted that the various functions in druntime and Phobos which take a duration of time take an actual Duration rather than a naked number (most currently take both, though the versions which take a naked number are going to be deprecated). For instance, core.thread.sleep takes a Duration, as does receiveTimeout. So, durations are used outside of just interacting with core.time and std.datetime.

One particular thing to note here is how both dur and total take a string representing the units of time to be used. This is an idiom used throughout core.time and std.datetime. The possible units are "years", "months", "weeks", "days", "hours", "minutes", "seconds", "msecs", "usecs", "hnsecs", and "nsecs". It should be noted however that very few functions take "nsecs", because nothing in std.datetime, and very little in core.time, has precision greater than hnsecs (100 ns). Also, a number of functions (such as core.time.dur) do not take "years" or "months", because it is not possible to convert between years or months and smaller units without a specific date. So, while you can add a Duration to a time point, if you want to add years or months to one, you must use a separate function (such as add) to do that - and those will take "years" and "months".

### Time Points

std.datetime has 4 types which represent time points.

- Date
- TimeOfDay
- DateTime
- SysTime

A Date represents a date and holds its year, month, and day as separate values internally. A TimeOfDay represents a time of day, 00:00:00 - 23:59:59, and holds its hour, minute, and second as separate values internally. A DateTime represents a date and time and holds its values as a Date and TimeOfDay internally. None of these types have any concept of time zone. They represent generic dates and/or times and are best-suited for cases where you need a date and/or time but don't care about time zone. Also, because they hold their values separated internally, those values don't have to be calculated every time that you ask for them.

    auto date = Date(1992, 12, 27);
    auto tod = TimeOfDay(7, 0, 22);
    auto dateTime = DateTime(1992, 12, 27, 7, 0, 22);
    assert(date == dateTime.date);
    assert(tod == dateTime.timeOfDay);

A SysTime, however, is an entirely different beast. It represents a date and time - similar to DateTime - but it goes to hnsec precision instead of only second precision, and it incorporates the concept of time zone. Its time is held internally as a 64-bit integral value which holds the number of hnsecs which have passed since midnight, January 1st, 1 A.D. in UTC. It also has a TimeZone object which it uses to polymorphically adjust its UTC value to the appropriate time zone when querying for values such as its year or hour.

SysTime is the type which is used to interface with the system's clock. When you ask for the current time, you get a SysTime. And because it always holds its internal value in UTC, it never has problems with DST or time zone changes. It has most of the functions that DateTime has as well as a number of functions specific to it. It can be cast to the other 3 time point types as well as be constructed from them, but you do risk problems with DST when creating a SysTime from the other 3 time points unless you specifically create the SysTime with a TimeZone which doesn't have DST (such as UTC), since when a time zone has DST, one hour of the year does not exist, and another exists twice. You can also convert to and from unix time, which is what you're dealing with in C with time_t.

The one other related type which I should mention at this point is core.time.FracSec. It holds fractional seconds, and it is what you get from a Duration or SysTime when you specifically ask for the fractional portion of the time.

    auto st1 = Clock.currTime(); //Current time in local time.
    auto st2 = Clock.currTime(UTC()); //Current time in UTC.
    auto st3 = SysTime(DateTime(1992, 12, 27, 7, 0, 22), FracSec.from!"usecs"(5));
    assert((cast(Date)st3) == Date(1992, 12, 27));
    assert((cast(TimeOfDay)st3) == TimeOfDay(7, 0, 22));
    assert((cast(DateTime)st3) == DateTime(1992, 12, 27, 7, 0, 22));
    assert(st3.fracSec == FracSec.from!"hnsecs"(50));

### Time Intervals

std.date has nothing to correspond to time intervals, so I won't go over them in great detail. Essentially, they're constructed from either two time points or a time point and a duration. Interval is a finite time interval with two end points, whereas PosInfInterval is an infinite time interval starting at a specific time point and going to positive infinity, and NegInfInterval is an infinite time interval starting at negative infinity and going to a specific time point. They have various operations for dealing with intersections and the like. It is also possible to create ranges over them if you want to operate on a range of time points. Take a look at the documentation for more details.

## Interfacing with C

Hopefully, you can do everything that you need to do using the types in core.time and std.datetime, but if you do need to interface with C code, then you can. C's time_t uses "unix time" (seconds since midnight, January 1st, 1970 A.D. in UTC), whereas SysTime uses what it calls "std time" (hnsecs since midnight January 1st, 1 A.D. in UTC). Translating between the two is fairly straightforward. To get a time_t from a SysTime, simply call toUnixTime on the SysTime. To convert the other way around, you first need to convert a time_t to std time, then pass that value to SysTime's constructor. And if you ever simply need a SysTime's std time for any reason, then use its stdTime property.

    time_t unixTime = core.stdc.time.time(null);
    auto stdTime = unixTimeToStdTime(unixTime);
    auto st = SysTime(stdTime);
    assert(unixTime == st.toUnixTime());
    assert(stdTime == st.stdTime);

Hecto-nanoseconds were chosen as the internal representation of Duration and SysTime, because that is the highest precision that you can use with a 64-bit integer and still cover a reasonable amount of time (SysTime covers from around 29,000 B.C. to around 29,000 A.D.). It also happens to be the same internal representation that C# uses, so if you need to interface with C# for any reason, converting between its representation of time and std.datetime's representation is extremely easy, since no conversion is necessary. C#'s DateTime uses both the same units and epoch for its internal representation (which it calls Ticks) as SysTime, though unlike SysTime, it doesn't work with negative values (which would be B.C.) and doesn't go past the end of 9,999 A.D. Most programs are unlikely to care about values outside that range however. Regardless, hnsecs make the most sense for std.datetime, which tries to have the highest precision that it reasonably can, so that's why they were picked.

## Recommendations on Using std.datetime

Whether Date, TimeOfDay, DateTime, or SysTime is more appropriate in a particular situation depends very much on that situation. Date, TimeOfDay, and DateTime generally make the most sense when you're dealing with generic dates and times that have nothing to do with time zones, but if you're dealing with time zones at all or are dealing with anything which needs to worry about DST, you should use SysTime. Because it keeps its time internally in UTC, it avoids problems with DST. And while it does have a time zone component, it defaults to LocalTime (which is the time zone type for the local time of the system), so you don't generally have to deal directly with time zones if you don't want to.

If you do want to deal with time zones, then the time zone types in std.datetime are LocalTime, UTC, SimpleTimeZone, PosixTimeZone, and WindowsTimeZone - or if for some reason, they don't do what you need, you can always create your own time zone class derived from TimeZone. That's unlikely to be necessary, however (and if you think that you have come up with such a class which would be generally useful, please bring it up in the digitalmars.D newsgroup, since if it's truly generally useful, we may want some version of it in std.datetime). Read their documentation for more details. Most applications shouldn't have to worry about time zones though, beyond perhaps using UTC instead of LocalTime in some cases.

When it comes to saving a time point to disk or a database or something similar, I would generally recommend using the toISOString or toISOExtString functions, since both are standard ISO formats for date-time strings (toISOExtString is likely better in the general case, since it's more humanly readable, but they're both standard). You can then use fromISOString or fromISOExtString to recreate the appropriate time type later. toString uses the toSimpleString function, which is an invention of Boost and is somewhat more humanly readable, but it isn't standard, so you probably shouldn't use it for saving time point values.

    auto dateTime = DateTime(1997, 5, 4, 12, 22, 3);
    assert(dateTime.toISOString() == "19970504T122203");
    assert(dateTime.toISOExtString() == "1997-05-04T12:22:03");
    assert(dateTime.toSimpleString() == "1997-May-04 12:22:03");
    auto restored = DateTime.fromISOExtString(dateTime.toISOExtString());
    assert(dateTime == restored);

One area with saving times as strings which gets a bit awkward is time zones. The time zone is included in the string as part of the ISO standard, but all it contains is the total offset from UTC at that particular date and time, so you can't generally use an ISO string (extended or otherwise) to get the exact time zone which the SysTime originally had. Rather, it will be restored with a SimpleTimeZone with the given offset from UTC (except in the case of UTC, where it can restore UTC). On the other hand, if you're using LocalTime, then the time zone is not part of the string (per the ISO standard), and restoring the SysTime will restore it to whatever the current time zone is on the box, regardless of what the original time zone was. However, because in all cases, except for LocalTime, the UTC offset is included in the string, it is generally possible to get the exact UTC time that the SysTime was for. But you can't usually restore the original time zone from just the ISO string.

    auto local = SysTime(629_983_705_230_000_035);
    auto utc = local.toUTC();
    auto other = local.toOtherTZ(TimeZone.getTimeZone("America/New_York"));

    //This assumes that you're in "America/Los_Angeles". You'd get a different
    //time if you're in a different time zone.
    assert(local.toISOExtString() == "1997-05-04T12:22:03.0000035");

    assert(utc.toISOExtString() == "1997-05-04T19:22:03.0000035Z");
    assert(other.toISOExtString() == "1997-05-04T15:22:03.0000035-04:00");

    auto restLocal = SysTime.fromISOExtString(local.toISOExtString());
    auto restUTC = SysTime.fromISOExtString(utc.toISOExtString());
    auto restOther = SysTime.fromISOExtString(other.toISOExtString());

    //Only guaranteed because it's on the same machine.
    assert(restLocal == local);

    //Guaranteed regardless of machine. Their internal values could differ however.
    assert(cast(DateTime)restLocal == cast(DateTime)local);

    //Time zone is UTC for both.
    assert(restUTC == utc);

    //Time zone for restOther is SimpleTimeZone(-4 * 60), not "America/New_York".
    assert(restOther == other);

To summarize, UTC and SimpleTimeZone can be restored exactly using an ISO or ISO extended string. However, none of the other TimeZones can be. LocalTime is restored with the same date and time but in the local time zone of the computer it's restored on, so its std time may differ. Other time zones end up with the restored SysTime having the same std time as the original, but the new time zone is a SimpleTimeZone with the same total UTC offset which the original time zone had at the given std time, but you don't get the original time zone back. That works just fine if you don't ever need to change the value of that SysTime or need to know the name of the original time zone, but it is inadequate if you need to do either of those, since the rules for the new time zone won't match those of the original.

So, if you don't care about the time zone or if the restored SysTime has the same std time as the original, then LocalTime is fine. However, if you want the std time to be consistent, then avoid LocalTime. In most cases, I'd advise simply using UTC as the time zone when saving the time. And if you want to restore the time zone such that it's the same time zone with the same rules as it was prior to saving the time, then you're going to need to save that information yourself. With a PosixTimeZone or a WindowsTimeZone, all you have to do is save the time zone's name (which for them is the TZ database name and the Windows time zone name of that time zone respectively). That can be used to restore the time zone. If it's a SimpleTimeZone or UTC, then you don't have to do anything, because the ISO string will be enough. If you're using LocalTime, however, you're in a bit of a bind.

The restored time zone will be LocalTime, so if you want it to be whatever the local time of the computer you're doing the restoring on is, then you're fine. But if you want to be able to have the same actual time zone restored regardless of the local time of the computer restoring the time, you'll need to figure out what the time zone's TZ database name or Windows time zone name is on the original computer so that you can use it to get its corresponding PosixTimeZone or WindowsTimeZone on the computer that's doing the restoring. But it's actually really hard to accurately determine the TZ database name or Windows time zone name of the local time zone on any OS other than on Windows, so std.datetime doesn't currently provide a way to do that. I expect that such a requirement would be quite rare however. In most cases, you'll care about LocalTime and/or UTC, and even if you're using PosixTimeZone or WindowsTimeZone, odds are that restoring the time with the correct std time value and correct UTC offset will be enough (and if it's not, you can always save the time zone's name to restore the correct PosixTimeZone or WindowsTimeZone). It's just LocalTime that has the problem. However, if a function to accurately determine the TZ database name of the local time zone on Posix systems is ever devised, then it will be added to std.datetime.

The other, more compact, option for saving a SysTime is to just save its std time as a 64-bit integer. It's not really humanly readable like an ISO or ISO extended string would be, but it takes up less space if saved as an actual number rather than a string. However, you do then have to worry about the time zone yourself entirely if you wish to be able to restore it. But if you save the current UTC offset (meaning the UTC offset with the DST offset applied - such as an ISO string would include), that would be enough to correctly give what the time would have been in the original time zone even if you can't restore that time zone.

Well, that's probably more than enough on time zones. In most cases, you shouldn't need to care about them (SysTime is designed to make it so that you shouldn't have to worry about them if you don't want to), but std.datetime strives to give the best tools possible for handling time zones when you actually want to. Regardless, by far the biggest gain that SysTime gives you is that its internal time is always in UTC, so regardless of whether you try and do anything with time zones explicitly, you won't have any problems with DST changes when dealing with SysTime.

One last suggestion on using SysTime would be that if you need to query it for more than one of its properties (e.g. day or hour), or if you need to do it many times in a row, and the SysTime isn't going to change, then you should probably cast it to another time point type (probably DateTime) and query it for those values. The reason for this is that every time that you call a property function on a SysTime, it has to convert its internal std time to the value of the property that you're asking for, whereas if you convert it to a DateTime, the DateTime holds those values separately, and you only have to do the calculations once - when you do the conversion from the SysTime to a DateTime. If what you're doing doesn't need that extra boost of efficiency, then you might as well not bother, but it is good to be aware that it's less efficient to query each of SysTime's properties individually rather than converting it to a DateTime and then querying it.

    auto st = Clock.currTime();

    //Each value must be individually calculated.
    {
        auto year = st.year;
        auto month = st.month;
        auto day = st.day;
        auto hour = st.hour;
        auto minute = st.minute;
        auto second = st.second;
        auto fracSec = st.fracSec;
    }

    /+
        You do the calculations only twice if you convert to a DateTime
        (twice instead of once, because you're still asking for FracSec
        separately, though that particular calculation is fairly cheap).
     +/
    auto dateTime = cast(DateTime)st;
    {
        auto year = dateTime.year;
        auto month = dateTime.month;
        auto day = dateTime.day;
        auto hour = dateTime.hour;
        auto minute = dateTime.minute;
        auto second = dateTime.second;
        auto fracSec = st.fracSec;
    }

## Migrating to std.datetime

Okay, hopefully you have a fair idea of the basics of std.datetime at this point (though there's plenty more which is covered in the documentation), but the big question for many is how best to handle converting your code from using std.date to using std.datetime. When using std.date, you would have been using d_time, and if you had to worry about time zones, you were probably either using C functions to deal with conversions or just doing them yourself, since the functionality in std.date which relates to time zones is rather broken. As a result, most of what you would have done would likely be in UTC.

SysTime holds its time internally in UTC in a manner similar to d_time (albeit with different units and a different epoch), and it is the type intended for dealing with the time from the system's clock, so SysTime is generally what d_time should be replaced with. Functions in Phobos which previously took or returned a d_time now take or return a SysTime or are scheduled to be deprecated and have replacement functions which take or return a SysTime. Generally, in the case where a function took a d_time, that function is now overloaded with a version which takes a SysTime, but in cases where a function could not be overloaded (such as when it simply returned a d_time), a new function has been added to replace the old one (so as to avoid breaking existing code). The module that this impacts the most is std.file. For example,

    d_time dTime = "myfile.txt".lastModified();
    SysTime sysTime = "myfile.txt".timeLastModified();

    setTimes("yourfile.txt", dTime, dTime + 5);
    setTimes("yourfile.txt", sysTime, sysTime + dur!"msecs"(5));

With all such functions, it's simply a matter of changing the type of the argument that you're passing to the function or assigning its return value to and possibly changing the function name that you're calling so that it's the version that returns a SysTime. Those changes are quite straightforward and not particularly disruptive. Of greater concern are the formats that times are printed or saved in and how time zones are dealt with.

If you were saving the integral d_time value anywhere, then you're either going to have to switch to saving a value that SysTime would use as discussed previously (such as its std time or its ISO string), or you're going to have be converting between d_time and SysTime. At present, the functions sysTimeToDTime and dTimeToSysTime will do those conversions for you. So, converting between the two formats is easy. However, because d_time is going away, those functions will be going away. That means that you either need to refactor your code so that those functions aren't necessary, or you need to copy them to your own code to continue to use them.

As for formatted strings, std.datetime currently only supports ISO strings, ISO extended strings, and Boost's simple string. Eventually, it should have functions for custom strings, but a well-designed function for creating custom strings based on format strings is not easy to design, and it hasn't been done for std.datetime yet (it's on my todo list, but it could be a while before I get to it). So, in general, you're either going to have to switch to using one of the string formats that std.datetime supports, or you're going to have to generate and parse the string format that you want yourself. In some cases, you should be able to adjust the string that core.stdc.time.ctime gives you, and in others, you may be able to use toISOExtString and adjust what it gives you, but there's a decent chance that you're going to have to just create and parse the strings yourself using the various properties on SysTime. One major difference between the string functions in std.date and those in std.datetime to note is that unlike std.date, aside from Boost's simple strings, nothing in std.datetime prints the names of months or weekdays, because that poses a localization issue. So, unless you're using core.stdc.time.ctime to get those values, you're going to have to create the names yourself.

Now, if you were doing anything with time zones with std.date, odds are that you were doing all of those conversions yourself (since that's one of the areas where std.date is buggy). That being the case, you probably have the offset from UTC and the offset adjustment for DST for whatever time zone you're dealing with. What is likely the best way to handle that is to create a SimpleTimeZone using those values. Simply calculate the total UTC offset (so add in the DST offset if it applies for the date in question) in minutes and create a SimpleTimeZone with that. Note that std.datetime treats west of UTC as negative (for some reason, some systems - particularly Posix stuff - use a positive offset from UTC when west of UTC, in spite of the fact that when talking about time zones, negative is always used for west of UTC, and that's what the ISO standard strings do). So, you may have to adjust your values accordingly. Regardless, be very careful to make sure that you understand what the values you've been using represent in units of time and whether you need to be adding or subtracting them to convert them to what SimpleTimeZone expects for its offset from UTC: the minutes to add to the time in UTC to get the time in the target time zone.

    //These are the same offsets as America/Los_Angeles.
    auto utcOffset = -8 * 60;
    auto dstOffset = 60;

    immutable tzWithDST = new SimpleTimeZone(utcOffset + dstOffset);
    immutable tzWithoutDST = new SimpleTimeZone(utcOffset);

The last thing that I have to note is some differences in numerical values between std.date and std.datetime. Date's weekday property gives Sunday a value of 1, but weekDay gives Sunday a value of 0. DayOfWeek gives Sunday a value of 0. So, depending on which part of std.date you're dealing with it, it may or may not match what std.datetime is doing for the numerical values of weekdays. Months have a similar problem. Date's month property gives January a value of 1 - which matches what Month does - but monthFromTime gives January a value of 0. So, just as with the days of the week, you have to be careful with the numerical values of the months. Whether std.datetime matches what std.date is doing depends on which part of std.date you're using. And as you'll notice, it's not even consistent as to whether Date or the free function in std.date is the one which matches std.datetime. So, you should be very careful when converting code which uses numerical values for either the days of the week or the months of the year.

### std.date symbols and their std.datetime counterparts

std.date | std.datetime Equivalent
d_time | The closest would be SysTime.
d_time_nan | There is no equivalent. SysTime.init, which has a null TimeZone object, would be the closest, but once CTFE advances to the point that you can new up class objects with it, SysTime.init's timezone will be LocalTime, so don't rely on SysTime.init being invalid. std.datetime in general tries to avoid having any invalid states for any of its types. It's intended that creating such values be impossible.
Date | SysTime
Date.year | SysTime.year
Date.month | SysTime.month
Date.day | SysTime.day
Date.hour | SysTime.hour
Date.minute | SysTime.minute
Date.second | SysTime.second
Date.ms | SysTime.fracSec.msecs
Date.weekday | SysTime.dayOfWeek - but note that the values are off by 1.
Date.tzcorrection |
    immutable tz = sysTime.timezone;
    auto diff = tz.utcToTZ(sysTime.stdTime) - sysTime.stdTime;
    auto tzcorrection = convert!("hnsecs", "minutes")(diff);
However, it looks like tzcorrection is broken, so you're probably not using it in your code anyway.
Date.parse | SysTime.fromISOString, SysTime.fromISOExtString, and SysTime.fromSimpleString, but the formats of the strings differ from what Date.parse accepts.
ticksPerSecond | There is no equivalent. It's only relevant to d_time.
toISO8601YearWeek | SysTime.isoWeek
hourFromTime | SysTime.hour
minFromTime | SysTime.minute
secFromTime | SysTime.second
daysInYear | sysTime.isLeapYear ? 366 : 365
dayFromYear | (sysTime - SysTime(Date(1970, 1, 1), UTC())).total!"days"()
yearFromTime | SysTime.year
inLeapYear | SysTime.isLeapYear
monthFromTime | SysTime.month - but note that the values are off by 1.
dateFromTime | SysTime.day
weekDay | SysTime.dayOfWeek
UTCtoLocalTime | SysTime.toUTC
dateFromNthWeekdayOfMonth |
    //There is no equivalent. This is a possible implementation.
    int dateFromNthWeekdayOfMonth(int year, Month month,
                                  DayOfWeek dow, int n)
    {
        auto first = Date(year, month, 1);
        auto target = first;
        immutable targetDOTW = target.dayOfWeek;

        if (targetDOTW != dow)
        {
            if (targetDOTW < dow)
                target += dur!"days"(dow - targetDOTW);
            else
            {
                target += dur!"days"((DayOfWeek.sat - targetDOTW) +
                                     dow + 1);
            }
        }

        target += dur!"weeks"(n - 1);

        if (target.month != first.month)
            target -= dur!"weeks"(1);

        return cast(int)((target - first).total!"days"()) + 1;
    }
daysInMonth | SysTime.endOfMonthDay; Actually, this name is overly easy to confuse with endOfMonth - which returns a SysTime of the last day of the month. I will probably rename this to daysInMonth. But if I do, it won't be until the next release (2.054), and this name will be around until it's gone through the full deprecation cycle.
UTCtoString | There is no equivalent. You could probably parse and recombine core.stdc.time.ctime and SysTime.toISOExtString to create it though. However, this function appears to be fairly buggy in the first place, so odds are that your code isn't using it anyway.
toUTCString | There is no equivalent. You could probably parse and recombine core.stdc.time.ctime and SysTime.toISOExtString to create it though.
toDateString | There is no equivalent. You could probably parse and recombine core.stdc.time.ctime and SysTime.toISOExtString to create it though. However, this function appears to be fairly buggy in the first place, so odds are that your code isn't using it anyway.
toTimeString | There is no equivalent. You could probably parse and recombine core.stdc.time.ctime and SysTime.toISOExtString to create it though. However, this function appears to be fairly buggy in the first place, so odds are that your code isn't using it anyway.
parse.parse | SysTime.fromISOString, SysTime.fromISOExtString, and SysTime.fromSimpleString, but the formats of the strings differ from what parse accepts.
getUTCtime | Clock.currTime(UTC()) if you want the SysTime to have its time zone be UTC. More likely though, you'll just use Clock.currTime(). Its internal time is in UTC regardless.
DosFileTime | DosFileTime
toDtime | DosFileTimeToSysTime
toDosFileTime | SysTimeToDosFileTime
benchmark | benchmark

Note that I'm not an expert on what does and doesn't work in std.date, so while I have noted some of the functions that I know to be broken, just because a function isn't labeled as broken in the above table does not mean that it works correctly. And any function which doesn't work correctly is obviously not going to give the same results as the std.datetime equivalent, since it's almost certain that the std.datetime version isn't buggy, let alone buggy in the same way (if it is buggy, the bug is almost certainly going to be far more subtle than any bug in std.date, since std.datetime is quite thoroughly unit tested).

## Conclusion

Hopefully this article has improved your understanding of std.datetime and will get you well on your way to being able to migrate your code from std.date to std.datetime. If you have any further questions, please ask them on the digitalmars.D.learn newsgroup. And if there's a major use case of std.date which is not easy to convert over to std.datetime which I missed in this article and you think should be in it, please feel free to bring it up on the digitalmars.D newsgroup, and if need be, I'll update this article with the relevant information.

Copyright © 1999-2015 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc on DateTime