System.TimeZoneInfo: Working with Ambiguous and Invalid Points in Time [Josh Free]

System.TimeZoneInfo (currently available as part of .NET Framework 3.5 Beta 1) contains methods for checking if a DateTime instance represents an ambiguous or invalid time in a specific time zone. These methods are particularly useful for validating user-supplied points in time.

Background Information

Time zones that adjust their time for Daylight Saving Time (in most cases by moving the clock time back or forward by 1 hour) have gaps and repeats in the timeline — wherever the clock time was moved forward or back by the adjustment. Let’s use Pacific Standard Time as an example. In 2007 Pacific Standard Time (PST) changes to Pacific Daylight Time (PDT) at 02:00AM (“spring forward”) on the second Sunday in March and then returns at 02:00AM (“fall back”) on the first Sunday in November:

Ambiguous Time

Pacific Daylight Time (PDT) to Pacific Standard Time (PST)2007 Transition

Sunday, November 3, 2007 (first Sunday in November)

This day has 25 hours because of the repeated hour

00:00

PDT

01:00

PDT

01:59:59.9999999

PDT

01:00

PST <REPEAT in clock time>

01:59:59.9999999

PST <REPEAT in clock time>

02:00

PST

03:00

PST

The repeated time period is referred to as an ambiguous time range. The term Ambiguous Time is used because when only given a clock time, such as “01:30AM November, 3, 2007”, it is impossible to tell from that context alone if it is in Pacific Standard Time (PST) or Pacific Daylight Time (PDT).

Checking for Ambiguous Time with TimeZoneInfo

The TimeZoneInfo.IsAmbiguousTime instance method is used to determine if a DateTime represents an ambiguous time in the given time zone:

public Boolean IsAmbiguousTime(

    DateTime dateTime

)

It is completely legitimate to pass ‘Ambiguous Time’ DateTime instances to methods. However, application code may want to detect input that falls in an ambiguous time period and then prompt the user for clarification. For such a case, the TimeZoneInfo.GetAmbiguousTimeOffsets() method can be used to retrieve a TimeSpan array of UTC offsets that could apply to that DateTime.

public TimeSpan[] GetAmbiguousTimeOffsets(

    DateTime dateTime

)

Invalid Time

Pacific Standard Time (PST) to Pacific Daylight Time (PDT)2007 Transition

Sunday, March 10, 2007 (second Sunday in March)This day has 23 hours because of the gap in clock time

00:00

PST

01:00

PST

01:59:59.9999999

PST

<GAP in clock time>

03:00

PDT

The gap or “hole in time” is referred to as an invalid time range. The term Invalid Time is used because it is impossible for the clock time to ever be in that range.  Let me repeat that — invalid time is impossible to reach — the only way to get an invalid time in a DateTime is to accept bad user input or to write (bad) code that does not respect time zones.

Checking for Invalid Time with TimeZoneInfo

The TimeZoneInfo.IsInvalidTime instance method is used to determine if a DateTime represents an invalid time in the given time zone:

public Boolean IsInvalidTime(

    DateTime dateTime

)

Since ‘Invalid Time’ DateTime instances represent a time that does not exist, TimeZoneInfo APIs do not accept them as valid input.

‘Invalid Time’ DateTime Parameters Cause Exceptions

The only way an invalid time can be created is through parsing user supplied input or by having logic bugs in an application under development.  Because of this, APIs such as TimeZoneInfo.ConvertTime throw ArgumentException when the DateTime parameter is an invalid time.  When working with user supplied input, it is best to first verify the input with TimeZoneInfo.IsInvalidTime() before calling TimeZoneInfo.ConvertTime():

public static DateTime ConvertTime(

    DateTime dateTime,

    TimeZoneInfo sourceTimeZone,

    TimeZoneInfo destinationTimeZone

)

 

// An ArgumentException is thrown from ConvertTime when dateTime represents

// an invalid time in sourceTimeZone. When working with user-supplied input

// it is best to first validate the input with IsInvalidTime() before calling

// ConvertTime()

 

ArgumentException("The supplied DateTime represents an invalid time. For example, when the clock is adjusted forward, any time in the period that is skipped is invalid.", "dateTime")