BDE 4.14.0 Production release
Loading...
Searching...
No Matches
baltzo_timezoneutil

Detailed Description

Outline

Purpose

Provide utilities for converting times among different time zones.

Classes

See also
baltzo_localdatetime, baltzo_zoneinfo, baltzo_defaultzoneinfocache

Description

This component provides a namespace, baltzo::TimeZoneUtil, containing utility functions for converting time values to and from their corresponding local time representations in (possibly) different time zones. The primary methods provided include:

Valid, Ambiguous, and Invalid Local-Time Values

There are intervals around each daylight-saving time transition where a bdlt::Datetime object holding a local time may not describe a valid or unique clock time in the local time zone (see baltzo_localtimevalidity ). When interpreting a local-time value represented using a bdlt::Datetime object with respect to a given time zone, there are three possible scenarios:

  1. The local time is valid and unique: The local time representation is valid, and unique within the time zone (the most likely scenario). For example, in New York at "Aug 31, 2010 12:00AM", DST was in effect and the local-time offset from UTC was -4 hours.
  2. The local time is valid, but ambiguous: The local time representation is valid, but could correctly be interpreted as either of two possible times, as may happen around a daylight-saving time transition where the local-time offset from UTC increases (e.g., in the United States local time "falls back" by an hour in the fall). Thus, a local time within such a transition period occurs twice, and is ambiguous without additional information. For example, in New York, daylight-saving time was in effect until "Nov 7, 2010 2:00AM" when clocks were set back by an hour; therefore, the time "Nov 7, 2010 1:30AM" occurred twice, and that description (as represented in a bdlt::Datetime object) could refer to either of those two times.
  3. The local time is invalid: The local-time representation doesn't correspond to a valid time within the given time zone, as may happen around a daylight-saving time transition where the offset from UTC decreases (e.g., in the United States local time "springs forward" by an hour in the spring). Thus, local times that are skipped during such a transition are invalid. For example, in New York, DST was in effect starting "Mar 14, 2010 2:00AM" when clocks are set forward an hour; therefore, the local time "Mar 14, 2010 2:30AM" never occurs.

Note that the functions provided in this component guarantee a graceful handling of all three scenarios. Ambiguity and invalidity, when they arise, are resolved according to a user-supplied daylight-saving time policy that describes how to interpret the input time values (see baltzo_dstpolicy ).

Daylight-Saving Time (DST) Policies and Disambiguation

The baltzo::TimeZoneUtil methods that take, as input, a bdlt::Datetime object representing a local time (i.e., a local-time value without a UTC offset) also accept an optional baltzo::DstPolicy::Enum. This (optional) argument policy allows clients to specify how they would like the operation to interpret the input value (as such a value may be ambiguous or invalid within the indicated time zone – see above). Clients are, however, encouraged to use the default policy, e_UNSPECIFIED, unless there is some specific reason they require a different option.

Three enumerated baltzo::DstPolicy values are supported:

  1. e_UNSPECIFIED (default)
    • The client does not explicitly indicate whether the associated input time represents a daylight-saving time value, and the operation will determine how to interpret the time solely based on the input itself. If the input value is valid and unique, the operation will use its (unique) corresponding UTC value. If the input is either ambiguous or invalid, the operation will use the later of two potential interpretations of the input (determined, e.g., by applying the standard and daylight-saving time UTC offsets to the input). For invalid times, this choice reflects the assumption that the user most likely forgot to adjust their clock. For ambiguous times, this choice is arbitrary (but is consistent with common implementations of the C standard library).
  2. e_STANDARD
    • Indicates that the operation should treat the associated input time value as a standard time, using the UTC value computed by applying the standard-time UTC offset. Note that the standard-time UTC offset is used even when the input time value is (unambiguously) not a standard time, which would result in a UTC time that does not correspond to a standard time within the time zone.
  3. e_DST
    • Indicates that the operation should treat the associated input time value as a daylight-saving time, using the UTC value computed by applying the daylight-saving time UTC offset. Note that the daylight-saving-time UTC offset is used even when the input time value is (unambiguously) not a daylight-saving time, which would result in a UTC time that does not correspond to a daylight-saving time within the time zone.

Note that these policies are intended to reflect the behavior of the C standard library function mktime and its interpretation of the tm_isdst value of the supplied tm structure. The behavior for the "unspecified" policy, however, is not strictly defined by either the ISO or POSIX standards, and varies among implementations.

Result of convertLocalToUtc for Various baltzo::DstPolicy Values

The following table summarizes the effect that the different baltzo::DstPolicy values have on a call to convertLocalToUtc for several possible time values in New York. Note that standard local time in New York is UTC-5:00, and daylight-saving local time there is UTC-4:00.

Result format: UTC 'bdlt::Time' & corresponding local 'bdlt::TimeTz'.
,--------------------------------------------------------------------------.
| Input in New York | 'baltzo::DstPolicy::Enum' |
| Local Time |-----------------------------------------------------|
| (bdlt::Datetime) | *_UNSPECIFIED | *_STANDARD | *_DST |
|==========================================================================|
| Jan 1, 2010 01:30 | 06:30:00 UTC | 06:30:00 UTC | 05:30:00 UTC |
| (standard time) | (01:30:00-5:00) | (01:30:00-5:00) | (00:30:00-5:00) |
| | | [1] | [2] |
|--------------------|-----------------------------------------------------|
| Mar 14, 2010 02:30 | 07:30:00 UTC | 07:30:00 UTC | 06:30:00 UTC |
| (invalid) | (03:30:00-4:00) | (03:30:00-4:00) | (01:30:00-5:00) |
| | [3] | [4] | [5] |
|--------------------|-----------------------------------------------------|
| Apr 1, 2010 01:30 | 05:30:00 UTC | 06:30:00 UTC | 05:30:00 UTC |
| (daylight-saving) | (01:30:00-4:00) | (02:30:00-4:00) | (01:30:00-4:00) |
| | | [6] | [7] |
|--------------------|-----------------------------------------------------|
| Nov 7, 2010 01:30 | 06:30:00 UTC | 06:30:00 UTC | 05:30:00 UTC |
| (ambiguous) | (01:30:00-5:00) | (01:30:00-5:00) | (01:30:00-4:00) |
| | [8] | | |
`--------------------------------------------------------------------------'
Definition bdlt_datetime.h:331
  1. "Jan 1, 2010 01:30" is unambiguously a standard time value. The result is simply the corresponding UTC time "Jan 1, 2010 06:30 UTC".
  2. "Jan 1, 2010 01:30" is unambiguously a standard time value, so the supplied policy, e_DST, contradicts the actual occurrence of daylight-saving time in New York. The input time is adjusted by the UTC offset for daylight-saving time in New York (-4:00) resulting in a UTC time 05:30. Note that the result, "Jan 1, 2010 05:30 UTC", corresponds to the New York time "Jan 1, 2010 00:30:00-5:00" (a standard time).
  3. "Mar 14, 2010 02:30" is not a valid local time in New York (a correctly administered clock would have been set ahead an hour at 2:00AM). The operation will use the later of two potential values, determined by applying the standard and daylight-saving time UTC offsets to the input (07:30 UTC and 06:30 UTC, respectively). Note that the selection of the later time reflects an assumption that the user forgot to adjust the clock.
  4. The input time is adjusted by the UTC offset for standard time in New York (-5:00) resulting in the UTC time 07:30. Note that "Mar 14, 2010 07:30 UTC" corresponds to the New York time "Mar 14, 2010 03:30-4:00" (a daylight-saving time).
  5. The input time is adjusted by the UTC offset for daylight-saving time in New York (-4:00) resulting in the UTC time 06:30. Note that "Mar 14, 2010. 06:30 UTC" corresponds to the New York time "Mar 14, 2010 01:30-5:00" (a standard time).
  6. "Apr 1, 2010 01:30" is unambiguously a daylight-saving time value, so the supplied policy e_STANDARD contradicts the actual occurrence of daylight-saving time in New York. The input time is adjusted by the UTC offset for standard time in New York (-5:00) resulting in a UTC time 06:30. Note that "Apr 1, 2010 06:30 UTC" corresponds to the New York time "Apr 1, 2010 02:30:00-4:00" (a daylight-saving time).
  7. "Apr 1, 2010 01:30" is unambiguously a daylight-saving time value. The result is simply the corresponding UTC time "Apr 1, 2010 06:30 UTC".
  8. "Nov 7, 2010 01:30" is a valid, but ambiguous, local time in New York (clocks are set back by an hour at 2:00AM, so 1:30AM occurs twice). The operation will use the later of two potential values determined by applying the standard and daylight-saving time UTC offsets to the input (06:30 UTC and 05:30 UTC, respectively). Note that the selection of the later time is arbitrary, but is consistent with common implementations of the C standard library.

Thread Safety

The functions provided by baltzo::TimeZoneUtil are thread-safe, meaning they can be safely executed concurrently.

Usage

The following usage examples demonstrate how to use various functions provided by baltzo::TimeZoneUtil to perform conversions on various time representations.

Example 1: Converting a UTC time to a Local Time

In this usage example, we illustrate how to convert a UTC time to its corresponding local time in a given time zone. We start by creating a bdlt::Datetime object holding the UTC time "July 31, 2010 15:00:00":

bdlt::Datetime utcTime(2010, 7, 31, 15, 0, 0);

Then, we create a baltzo::LocalDatetime object to hold the result of the conversion operation:

Definition baltzo_localdatetime.h:172

Now, we call the convertUtcToLocalTime function in baltzo::TimeZoneUtil:

"America/New_York",
utcTime);
if (0 != status) {
// A non-zero 'status' indicates there was an error in the conversion
// (e.g., the time zone id was not valid or the environment has not
// been correctly configured).
return 1; // RETURN
}
static int convertUtcToLocalTime(LocalDatetime *result, const char *targetTimeZoneId, const bdlt::Datetime &utcTime)

Finally, we observe that the result in newYorkTime is "July 31, 2010 11:00:00" and that the offset from UTC applied was -4 hours:

const bdlt::Datetime test = newYorkTime.datetimeTz().localDatetime();
assert(2010 == test.year()); assert(11 == test.hour());
assert( 7 == test.month()); assert( 0 == test.minute());
assert( 31 == test.day()); assert( 0 == test.second());
assert( -4 * 60 == newYorkTime.datetimeTz().offset());
const bdlt::DatetimeTz & datetimeTz() const
Definition baltzo_localdatetime.h:556
Datetime localDatetime() const
Definition bdlt_datetimetz.h:660
int offset() const
Definition bdlt_datetimetz.h:666
int year() const
Return the value of the year attribute of this object.
Definition bdlt_datetime.h:2289
int hour() const
Return the value of the hour attribute of this object.
Definition bdlt_datetime.h:2223
int minute() const
Return the value of the minute attribute of this object.
Definition bdlt_datetime.h:2249
int second() const
Return the value of the second attribute of this object.
Definition bdlt_datetime.h:2265
int month() const
Return the value of the month attribute of this object.
Definition bdlt_datetime.h:2259
int day() const
Definition bdlt_datetime.h:2172

Example 2: Converting a Local Time in One Time Zone to Another Time Zone

In this example we illustrate how to convert a local time in a given time zone directly to its corresponding local time in another time zone. In particular, we want to convert the time "July 31, 2010 15:00:00" in New York to its corresponding time in Rome, Italy.

First, we create a bdlt::Datetime object representing the time "July 31, 2010 15:00:00" in New York:

bdlt::Datetime newYorkTime(2010, 7, 31, 15, 0, 0);

Now, let's apply the conversion operation to obtain a baltzo::LocalDatetime object representing the corresponding local time in Italy:

&romeTime,
"Europe/Rome",
newYorkTime,
"America/New_York");
if (0 != status) {
// A non-zero 'status' indicates there was an error in the conversion
// (e.g., the time zone id was not valid or the environment has not
// been correctly configured).
return 1; // RETURN
}
static int convertLocalToLocalTime(LocalDatetime *result, const char *targetTimeZoneId, const LocalDatetime &srcTime)
Definition baltzo_timezoneutil.h:756

Notice that we did not specify the optional dstPolicy argument to convertLocalToLocalTime. The default value should be appropriate for most users.

Finally, we verify that the value of romeTime is "July 31, 2010 21:00:00", which is the time in Italy corresponding to "July 31, 2010 15:00:00" in New York:

const bdlt::Datetime test = romeTime.datetimeTz().localDatetime();
assert(2010 == test.year()); assert(21 == test.hour());
assert( 7 == test.month()); assert( 0 == test.minute());
assert( 31 == test.day()); assert( 0 == test.second());
assert( 2 * 60 == romeTime.datetimeTz().offset());

Example 3: Initializing a Local Time

In this example we illustrate how to create a baltzo::LocalDatetime from a bdlt::Datetime, which may not represent a unique (or valid) clock time.

First, we create a bdlt::Datetime object for the New York local time "Jul 31, 2010 15:00:00". Note that this local date-time occurs during a DST transition and is an invalid date-time.

bdlt::Datetime uniqueTime(2010, 7, 31, 15, 0, 0);

Then, we call initLocalTime, which returns a baltzo::LocalDatetime object. initLocalTime also optionally returns baltzo::LocalTimeValidity::Enum, indicating whether the provided input was a valid and unique clock time. Note that invalid or ambiguous times are resolved using the optionally provided baltzo::DstPolicy::Enum (see the section {Daylight-Saving Time (DST) Policies and Disambiguation}):

int status = baltzo::TimeZoneUtil::initLocalTime(&localTime,
&validity,
uniqueTime,
"America/New_York");
if (0 != status) {
return 1;
}
Enum
Definition baltzo_localtimevalidity.h:149
static int initLocalTime(bdlt::DatetimeTz *result, const bdlt::Datetime &localTime, const char *timeZoneId, DstPolicy::Enum dstPolicy=DstPolicy::e_UNSPECIFIED)
Definition baltzo_timezoneutil.h:832

Now, we verify the value of localTime is "Jul 31, 2010 15:00:00" with an offset of -4:00 from UTC, in the time zone "America/New_York".

const bdlt::Datetime invalidTest = localTime.datetimeTz().localDatetime();
assert(2010 == invalidTest.year()); assert(15 == invalidTest.hour());
assert( 7 == invalidTest.month()); assert( 0 == invalidTest.minute());
assert( 31 == invalidTest.day()); assert( 0 == invalidTest.second());
assert( -4 * 60 == localTime.datetimeTz().offset());
assert("America/New_York" == localTime.timeZoneId());
const bsl::string & timeZoneId() const
Definition baltzo_localdatetime.h:562

In addition, the time provided represents a unique and valid clock time in New York (because it does not fall near a daylight-saving time transition):

@ e_VALID_UNIQUE
Definition baltzo_localtimevalidity.h:150

By contrast, if we call initLocalTime for a time value that falls during a during a daylight-saving time transition, the returned baltzo::LocalTimeValidity::Enum will indicate if the supplied time either does not represent a valid clock time in the time zone (as may occur when clocks are set forward), or does not represent a unique clock time (as may occur when clocks are set back).

For example, suppose we call initLocalTime for "Mar 14, 2010 02:30"; this clock time does not occurs in New York, as clocks are set forward by an hour at 2am local time:

bdlt::Datetime invalidTime(2010, 3, 14, 2, 30, 0);
&validity,
invalidTime,
"America/New_York");
if (0 != status) {
return 1;
}

Now, we verify the value of localTime represents a valid and unique time of "Mar 14, 2010 03:30:00-04:00" in the "America/New_York" time zone.

const bdlt::Datetime test = localTime.datetimeTz().localDatetime();
assert(2010 == test.year()); assert( 3 == test.hour());
assert( 3 == test.month()); assert(30 == test.minute());
assert( 14 == test.day()); assert( 0 == test.second());
assert("America/New_York" == localTime.timeZoneId());
assert( -4 * 60 == localTime.datetimeTz().offset());

Finally, we verify that the validity status returned for invalidTime is e_INVALID:

@ e_INVALID
Definition baltzo_localtimevalidity.h:152

Example 4: Obtaining Information About a Time Value

In this example we illustrate how to obtain additional information about a local time in a given time zone using the loadLocalTimePeriod method. Using loadLocalTimePeriod a client can determine, for a point in time, the attributes that characterize local time in a given time zone (e.g., the offset from UTC, whether it is daylight-saving time) as well as the interval over which those attributes apply (see baltzo_localtimeperiod ).

First, we create a baltzo::LocalDatetime object for the New York local time "Jul 31, 2010 15:00:00-04:00". Note that this baltzo::LocalDatetime may also be created as in example 3.

bdlt::DatetimeTz localTimeTz(bdlt::Datetime(2010, 7, 31, 15, 0, 0),
-4 * 60);
baltzo::LocalDatetime localTime(localTimeTz, "America/New_York");
Definition bdlt_datetimetz.h:308

Then, we call loadLocalTimePeriod, which returns a baltzo::LocalTimePeriod object that is loaded with attributes characterizing local time in New York on "Mar 14, 2010 03:30:00", and the interval over which those attributes are in effect.

int status = baltzo::TimeZoneUtil::loadLocalTimePeriod(&period, localTime);
if (0 != status) {
// A non-zero 'status' indicates there was an error in the conversion
// (e.g., the time zone id was not valid or the environment has not
// been correctly configured).
return 1; // RETURN
}
Definition baltzo_localtimeperiod.h:211
static int loadLocalTimePeriod(LocalTimePeriod *result, const LocalDatetime &localTime)
Definition baltzo_timezoneutil.h:849

Now we examine the returned properties. "Mar 14, 2010 03:30:00" is during daylight-saving time, which is -4:00 UTC, and the type of local time is sometimes abbreviated "EDT" for "Eastern Daylight Time". "Eastern Daylight Time" is in effect from "Mar 14, 2010 7am UTC" to "Nov 7, 2010 6am UTC". Note that the abbreviation provided ("EDT") is not canonical or localized. In general the provided abbreviations should not be displayed to users (they are intended for development and debugging only):

assert(true == period.descriptor().dstInEffectFlag());
assert(-4 * 60 * 60 == period.descriptor().utcOffsetInSeconds());
assert("EDT" == period.descriptor().description());
assert(bdlt::Datetime(2010, 3, 14, 7, 0, 0) == period.utcStartTime());
assert(bdlt::Datetime(2010, 11, 7, 6, 0, 0) == period.utcEndTime());
const bsl::string & description() const
Definition baltzo_localtimedescriptor.h:542
bool dstInEffectFlag() const
Definition baltzo_localtimedescriptor.h:548
int utcOffsetInSeconds() const
Definition baltzo_localtimedescriptor.h:554
const bdlt::Datetime & utcStartTime() const
Definition baltzo_localtimeperiod.h:562
const bdlt::Datetime & utcEndTime() const
Definition baltzo_localtimeperiod.h:556
const LocalTimeDescriptor & descriptor() const
Definition baltzo_localtimeperiod.h:544