Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Time Handling

Note: The time system was changed after version 0.99.3. If you are using Tango version 0.99.3 or earlier, please see the original documentation

Units of time are as important to humankind as the bits and bytes are to computers. By them, we live, organize, and operate our daily lives. For that reason, the tango.time package collects all the niceties of time and date particulars into a handful of convenient modules, carefully abstracting away all platform details.

TimeSpan

The basic representation of a span of time within Tango is in tango.time.TimeSpan. This structure represents a length of time capable of representing a +/- 10,000 year period, in increments of 100 nano-seconds (called ticks). The TimeSpan structure should be treated as a basic type, as it provides all the useful operator overloads, as well as convenience properties to convert the TimeSpan to common measurements such as seconds and milliseconds.

TimeSpan contains constructors for most lengths of time, named after the measurements that they represent:

// create a time span that represents 5 seconds
TimeSpan t = TimeSpan.seconds(5);

TimeSpans also contains numerous constants to help manipulate values that represent ticks. You should always use these constants in case some future version of Tango has a different resolution for a tick. These constants are named TimeSpan.TicksPerX, where X is Second, Millisecond, etc.

// create a time span that represents 5 seconds
TimeSpan t = TimeSpan(TimeSpan.TicksPerSecond * 5);

To convert a TimeSpan to a certain measurement, use the property named after the measurement:

// get the number of seconds that the TimeSpan t represents
long s = t.seconds;

Note that this performs integer division and will truncate any partial seconds.

Time and TimeOfDay

The basic representation of a point in time within Tango is in tango.time.Time. This structure allows representations of points of time ranging from 10,000 BC to 10,000 AD. The discrete unit of time in Time is also 100 nano-seconds. Time uses TimeSpan to return differences between two Time values, and to add or subtract a length of time from a Time. It also is used by the Clock classes and Calendar classes to provide localized points of time.

The TimeOfDay structure in tango.time.TimeSpan is used to represent the time of a given day without the date. For example, 12:42:05. This structure is somewhat like TimeSpan except it's properties return the components of a time instead of the total time converted to that measurement. For example, TimeOfDay.seconds will always return a value in the range of 0 - 59. The TimeOfDay can be accessed from a given Time by using the time property. For example:

import tango.io.Stdout;
import tango.time.WallClock;

void main()
{
        TimeOfDay tod = WallClock.now.time;
        Stdout.format ("time is {}:{:d02}:{:d02}",
                       tod.hours, tod.minutes, tod.seconds).newline;
}

Clock, WallClock, and DateTime

tango.time.Clock and WallClock modules represent UTC and local wall time respectively. WallClock performs the equivalent function to Clock, but adjusts for local time zone and daylight savings (DST).

The intent of a Clock is threefold:

  • Abstract away OS-level time functions.
  • Expose a simple, flexible, consistent expression of time in both UTC and local representations.
  • Initialize user accessible time fields with native time information, so that each time component is easy to access independently.

The current value of a clock is retrieved via the now method, which returns a Time value. This value may be split into fields representing time components, or manipulated using TimeSpan structures.

import tango.time.Clock;

void main()
{
         Time time = Clock.now;
}

Much of using the clocks revolves around accessing time "fields" to get or set the time properties with which we need to work. To initialize our time fields we use either Clock.toDate or WallClock.toDate to populate a DateTime structure with either UTC or local time:

import tango.time.Clock;

void main()
{
         auto fields = Clock.toDate;
}

Here we set up the datetime fields with the current UTC time. We could have made a similar call to WallClock.toDate instead, in which case all field values would have been prepared with local time instead. Sometimes it becomes necessary to convert our current field time values back to an atomic form (a single Time value). fromDate is a method for that purpose. It returns a Time value that contains the representation of the current field contents.

Now that the field variables are initialized with the time values, we can go ahead and make good use of them.

import tango.io.Stdout;
import tango.time.WallClock;

void main()
{
	auto fields = WallClock.toDate;

	Stdout.formatln ("{} {} {}, {} {:D2}:{:D2}:{:D2}",
                         fields.date.asDay,
                         fields.date.asMonth,
                         fields.date.day,
                         fields.date.year,
                         fields.time.hours,
                         fields.time.minutes,
                         fields.time.seconds);
}

These fields provide us with convenient access to all aspects of the current time. Property asDay returns a string naming the current day of week, and asMonth returns a string referring to the month name. Attributes day, year, hours, minutes, and seconds supply the integer values of their parts. It is possible to get the current millisecond value of the time with a reference to the millis field.

WallClock also allows us to acquire timezone information using the zone method. A call to this method retrieves a TimeSpan that represents the local timezone relative to Greenwich Mean Time, where negative values represent west of GMT.

StopWatch

Need to time a section of code, a 'net request, or some other reasonably short duration? The StopWatch module is your friend, exposing a simple start/stop api. Very high precision on Win32.

Calendars

The Time value is calendar agnostic. All calendars that are based on traditional seconds and hours have the same notion of time of day. However, there are differences when it comes to years, months, and days of the month. A variety of calendars provide the ability to convert date and time components into a Time value, or give accessors for the date components of a Time structure. For example:

import tango.time.chrono.Gregorian;
import tango.time.WallClock;
import tango.io.Stdout;

void main()
{
        auto n = WallClock.now;
        auto t = n.time;
        auto d = Gregorian.generic.toDate(n);
        Stdout.format ("date/time is {}/{}/{} {}:{:d02}:{:d02}",
                       d.day, d.month, d.year,
                       t.hours, t.minutes, t.seconds).newline;
}

To construct a Time structure from a given Date and time, use the getTime method:

        Time arbitraryTime = cal.getTime(2006, 11, 18, 10, 52, 33, 0);

For convenience, there is a module in tango.time.chrono called DefaultCalendar. This module contains a single Calendar instance called DefaultCalendar. This instance is used by any library code that needs a calendar but does not have a reference to one. By default it is a Gregorian calendar, but you may change it to any calendar you prefer.

Daylight Savings

All timezone and daylight savings calculations are isolated within WallClock, and conversion between UTC and wall-time is performed in accordance with appropriate OS facilities. There are some potential issues with this dependence, specifically, Win32 systems behave differently to Posix when calculating daylight-savings time. Win32 calculates with respect to the time of the api call, whereas a Posix system calculates DST based upon a provided point in time. We hope to change this at some future point such that Win32 will behave in a similar manner to Posix. This obviously will not affect requests to WallClock.now, since the point in time is actually the current time.