Component of the Week #30: baltzo_timezoneutil

Summary:
  • Provides utilities for converting times among different time zones.

Working with time zones is a notoriously complex task in software development. The baltzo_timezoneutil component offers a robust solution by providing utility functions for converting time values between different time zones while correctly handling edge cases around daylight saving time transitions, like ambiguous and invalid local time values.

The component is organized in the baltzo::TimeZoneUtil namespace, offering a set of utility functions for time zone conversions, in particular:

  • convertUtcToLocalTime - Convert a UTC time to a local time in a specified time zone

  • convertLocalToUtc - Convert a local time to its UTC equivalent

  • convertLocalToLocalTime - Convert a local time in one time zone to the equivalent local time in another zone

  • initLocalTime - Initialize a local time value based on time zone information

The time zone conversions take advantage of IANA time zone data.

Note

Because working with time zones is a regular source of issues, we recommend converting user supplied local time values to a UTC representation (and back) as close to the user as possible. Doing so ensures most in-process work with time points is performed in an unambiguous UTC representation, and (potentially ambiguous) local times are used only for input and display purposes.

Let’s look at a basic example of converting a local time value (in New York) to UTC and back.

bdlt::Datetime nyTime(2025, 9, 8, 15, 30, 0);

// Convert a local NY time to UTC
bdlt::Datetime utcTime;
int rc = baltzo::TimeZoneUtil::convertLocalToUtc(&utcTime,
                                                 nyTime,
                                                 "America/New_York");
if (0 != rc) {
    bsl::cout << "Data for 'America/New_York' was not found."
              << bsl::endl;
    return -1;
}

// Convert UTC to a local time in NY
bdlt::DatetimeTz roundTripNYTime;
rc = baltzo::TimeZoneUtil::convertUtcToLocalTime(&roundTripNYTime,
                                                 "America/New_York",
                                                 utcTime);

if (0 != rc) {
    bsl::cout << "Data for 'America/New_York' was not found."
              << bsl::endl;
    return -1;
}

// Note that for other starting values, `nyTime` may not equal
// `roundTripNYTime.localDatetime()`!
//
// This may occur when `nyTime` falls during a time zone transition
// where clocks were set back (making the time ambiguous).  See the
// component documentation for information and options to control
// how ambiguous (and invalid) times are handled

As noted in the example, one of the most important features of baltzo::TimeZoneUtil is its handling of the three scenarios that can occur when interpreting local time values:

  1. Valid and unique times - The standard case where a local time unambiguously corresponds to one UTC time

  2. Valid but ambiguous times - During “fall back” transitions when a local time occurs twice

  3. Invalid times - During “spring forward” transitions when some local times are skipped

For more information about how these situations are handled, and options to control behavior, please see the component documentation for baltzo::TimeZoneUtil.

For more details and examples, see: