// baltzo_timezoneutil.h -*-C++-*- #ifndef INCLUDED_BALTZO_TIMEZONEUTIL #define INCLUDED_BALTZO_TIMEZONEUTIL #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide utilities for converting times among different time zones. // //@CLASSES: // baltzo::TimeZoneUtil: utilities for converting local time values // //@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: //: o 'convertLocalToLocalTime' and 'convertUtcToLocalTime', for converting a //: time to the corresponding local-time value in some time zone; //: o 'convertLocalToUtc', for converting a local-time value into the //: corresponding UTC time value; //: o 'initLocalTime', for initializing a local-time value. // Additionally, the 'loadLocalTimePeriod' and 'loadLocalTimePeriodForUtc' // methods enable clients to obtain information about a time value, such as // whether the provided time is a daylight-saving time value. Finally note // that, all of the functions in this utility component make use of a // process-wide cache of time-zone information (see // {'baltzo_defaultzoneinfocache'}). // ///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) //: o 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' //: o 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' //: o 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] | | | // `--------------------------------------------------------------------------' //.. // //: 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: //.. // baltzo::LocalDatetime newYorkTime; //.. // Now, we call the 'convertUtcToLocalTime' function in 'baltzo::TimeZoneUtil': //.. // int status = baltzo::TimeZoneUtil::convertUtcToLocalTime(&newYorkTime, // "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 // } //.. // 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()); //.. // ///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: //.. // baltzo::LocalDatetime romeTime; // int status = baltzo::TimeZoneUtil::convertLocalToLocalTime( // &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 // } //.. // 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}): //.. // baltzo::LocalDatetime localTime; // baltzo::LocalTimeValidity::Enum validity; // int status = baltzo::TimeZoneUtil::initLocalTime(&localTime, // &validity, // uniqueTime, // "America/New_York"); // if (0 != status) { // return 1; // } //.. // 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()); //.. // 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): //.. // assert(baltzo::LocalTimeValidity::e_VALID_UNIQUE == validity); //.. // 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); // status = baltzo::TimeZoneUtil::initLocalTime(&localTime, // &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': //.. // assert(baltzo::LocalTimeValidity::e_INVALID == validity); //.. // ///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"); //.. // 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. //.. // baltzo::LocalTimePeriod period; // 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 // } //.. // 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()); //.. #include <balscm_version.h> #include <baltzo_defaultzoneinfocache.h> #include <baltzo_dstpolicy.h> #include <baltzo_localtimevalidity.h> #include <baltzo_timezoneutilimp.h> #include <baltzo_localdatetime.h> #include <bdlt_currenttime.h> #include <bdlt_datetime.h> #include <bdlt_datetimetz.h> #include <bsls_assert.h> #include <bsls_review.h> #include <bsls_timeinterval.h> #include <bsl_iosfwd.h> namespace BloombergLP { namespace baltzo { class LocalTimePeriod; class ZoneinfoCache; // =================== // struct TimeZoneUtil // =================== struct TimeZoneUtil { // This 'struct' provides a namespace for utility functions that convert // time values to, from, and between, their corresponding local time // representations in (possibly) different time zones. // // These utility functions are: //: o *alias-safe* //: o *exception-neutral* (agnostic) //: o *thread-safe* // For terminology see {'bsldoc_glossary'}. // CLASS METHODS static int addInterval(LocalDatetime *result, const LocalDatetime& originalTime, const bsls::TimeInterval& interval); // Load, into the specified 'result', the local time value that is the // specified 'interval' in the future of the specified 'originalTime' // (in the time zone 'originalTime.timeZoneId()'). Return 0 on // success, and a non-zero value with no effect otherwise. A return // value of 'ErrorCode::k_UNSUPPORTED_ID' indicates that // 'targetTimeZoneId' was not recognized, and a return value of // 'ErrorCode::k_OUT_OF_RANGE' indicates that the result of the // operation would have been outside the range of values representable // by the 'result' type. The resulting local-time is equivalent to // adding 'interval' to 'originalTime.datetimeTz().utcDatetime()' and // converting the result into the local time of // 'originalTime.timeZoneId()'. static int convertUtcToLocalTime(LocalDatetime *result, const char *targetTimeZoneId, const bdlt::Datetime& utcTime); static int convertUtcToLocalTime(bdlt::DatetimeTz *result, const char *targetTimeZoneId, const bdlt::Datetime& utcTime); // Load, into the specified 'result', the local date-time value (in the // time zone indicated by the specified 'targetTimeZoneId') // corresponding to the specified 'utcTime'. The offset from UTC of // the time zone is rounded down to minute precision. Return 0 on // success, and a non-zero value with no effect otherwise. A return // value of 'ErrorCode::k_UNSUPPORTED_ID' indicates that // 'targetTimeZoneId' was not recognized, and a return value of // 'ErrorCode::k_OUT_OF_RANGE' indicates that the result of the // operation would have been outside the range of values representable // by the 'result' type. static int convertLocalToLocalTime(LocalDatetime *result, const char *targetTimeZoneId, const LocalDatetime& srcTime); static int convertLocalToLocalTime( LocalDatetime *result, const char *targetTimeZoneId, const bdlt::DatetimeTz& srcTime); static int convertLocalToLocalTime(bdlt::DatetimeTz *result, const char *targetTimeZoneId, const LocalDatetime& srcTime); static int convertLocalToLocalTime( bdlt::DatetimeTz *result, const char *targetTimeZoneId, const bdlt::DatetimeTz& srcTime); // Load, into the specified 'result', the local date-time value (in the // time zone indicated by the specified 'targetTimeZoneId') // corresponding to the local time indicated by the specified // 'srcTime'. The offset from UTC of both time zones is rounded down // to minute precision. Return 0 on success, and a non-zero value with // no effect otherwise. A return value of // 'ErrorCode::k_UNSUPPORTED_ID' indicates that 'targetTimeZoneId' was // not recognized, and a return value of 'ErrorCode::k_OUT_OF_RANGE' // indicates that the result of the operation would have been outside // the range of values representable by the 'result' type. static int convertLocalToLocalTime(LocalDatetime *result, const char *targetTimeZoneId, const bdlt::Datetime& srcTime, const char *srcTimeZoneId, DstPolicy::Enum dstPolicy = DstPolicy::e_UNSPECIFIED); static int convertLocalToLocalTime(bdlt::DatetimeTz *result, const char *targetTimeZoneId, const bdlt::Datetime& srcTime, const char *srcTimeZoneId, DstPolicy::Enum dstPolicy = DstPolicy::e_UNSPECIFIED); // Load, into the specified 'result', the local date-time value (in the // time zone indicated by the specified 'targetTimeZoneId') // corresponding to the local time indicated by the specified 'srcTime' // (in the time zone indicated by the specified 'srcTimeZoneId'). // Optionally specify a 'dstPolicy' indicating whether or not 'srcTime' // represents a daylight-saving time value. If 'dstPolicy' is // unspecified and 'srcTime' is a unique and valid time in the source // time zone, then perform the conversion using that uniquely described // time; if 'dstPolicy' is unspecified and 'srcTime' is either // ambiguous or invalid, then use the later of the two possible // interpretations of 'srcTime'. The offset from UTC of both time // zones is rounded down to minute precision. Return 0 on success, and // a non-zero value with no effect otherwise. A return value of // 'ErrorCode::k_UNSUPPORTED_ID' indicates that either // 'targetTimeZoneId' or 'srcTimeZoneId' was not recognized. static int initLocalTime(bdlt::DatetimeTz *result, const bdlt::Datetime& localTime, const char *timeZoneId, DstPolicy::Enum dstPolicy = DstPolicy::e_UNSPECIFIED); static int initLocalTime(LocalDatetime *result, const bdlt::Datetime& localTime, const char *timeZoneId, DstPolicy::Enum dstPolicy = DstPolicy::e_UNSPECIFIED); static int initLocalTime(bdlt::DatetimeTz *result, LocalTimeValidity::Enum *resultValidity, const bdlt::Datetime& localTime, const char *timeZoneId, DstPolicy::Enum dstPolicy = DstPolicy::e_UNSPECIFIED); static int initLocalTime(LocalDatetime *result, LocalTimeValidity::Enum *resultValidity, const bdlt::Datetime& localTime, const char *timeZoneId, DstPolicy::Enum dstPolicy = DstPolicy::e_UNSPECIFIED); // Load, into the specified 'result', the local date-time value -- // including the local date, time, and resolved UTC offset -- indicated // by the specified 'localTime' in the time zone indicated by the // specified 'timeZoneId'. Optionally specify 'resultValidity' in // which to load the validity of 'localTime' as being unique, ambiguous // but valid, or invalid. Optionally specify a 'dstPolicy' indicating // whether or not 'localTime' represents a daylight-saving time value. // If 'dstPolicy' is unspecified and 'localTime' is a unique and valid // time in the source time zone, then perform the conversion using that // uniquely described time; if 'dstPolicy' is unspecified and // 'localTime' is either ambiguous or invalid, then use the later of // the two possible interpretations of 'localTime'. The offset from // UTC of the time zone is rounded down to minute precision. Return 0 // on success, and a non-zero value with no effect otherwise. A return // value of 'ErrorCode::k_UNSUPPORTED_ID' indicates that 'timeZoneId' // was not recognized. static int convertLocalToUtc(bdlt::Datetime *result, const bdlt::Datetime& localTime, const char *timeZoneId, DstPolicy::Enum dstPolicy = DstPolicy::e_UNSPECIFIED); static int convertLocalToUtc(LocalDatetime *result, const bdlt::Datetime& localTime, const char *timeZoneId, DstPolicy::Enum dstPolicy = DstPolicy::e_UNSPECIFIED); // Load, into the specified 'result', the UTC time value that // corresponds to the specified 'localTime' in the time zone indicated // by the specified 'timeZoneId'. Optionally specify a 'dstPolicy' // indicating whether or not 'localTime' represents a daylight-saving // time value. If 'dstPolicy' is unspecified and 'localTime' is a // unique and valid time in the source time zone, then perform the // conversion using that uniquely described time; if 'dstPolicy' is // unspecified and 'localTime' is either ambiguous or invalid, then use // the later of the two possible interpretations of 'localTime'. The // offset from UTC of the time zone is rounded down to minute // precision. Return 0 on success, and a non-zero value with no effect // otherwise. A return value of 'ErrorCode::k_UNSUPPORTED_ID' // indicates that 'timeZoneId' was not recognized. static int loadLocalTimePeriod(LocalTimePeriod *result, const LocalDatetime& localTime); // Load, into the specified 'result', attributes characterizing the // specified 'localTime' (i.e., the offset from UTC, whether // daylight-saving time is in effect and the description of the time // zone), as well as the time interval over which those attributes // apply. Return 0 on success, and a non-zero value with no effect // otherwise. A return value of 'ErrorCode::k_UNSUPPORTED_ID' // indicates that 'localTime.timeZoneId()' was not recognized. static int loadLocalTimePeriod(LocalTimePeriod *result, const bdlt::DatetimeTz& localTime, const char *timeZoneId); // Load, into the specified 'result', attributes characterizing the // specified 'localTime' in the time zone indicated by the specified // 'timeZoneId' (i.e., the offset from UTC, whether daylight-saving // time is in effect and the description of the time zone), as well as // the time interval over which those attributes apply. Return 0 on // success, and a non-zero value with no effect otherwise. A return // value of 'ErrorCode::k_UNSUPPORTED_ID' indicates that 'timeZoneId' // was not recognized. static int loadLocalTimePeriodForUtc(LocalTimePeriod *result, const char *timeZoneId, const bdlt::Datetime& utcTime); // Load, into the specified 'result', attributes characterizing local // time at the specified 'utcTime' in the time zone indicated by the // specified 'timeZoneId' (i.e., the offset from UTC, whether // daylight-saving time is in effect and the description of the time // zone), as well as the time interval over which those attributes // apply. Return 0 on success, and a non-zero value with no effect // otherwise. A return value of 'ErrorCode::k_UNSUPPORTED_ID' // indicates that 'timeZoneId' was not recognized. static int now(bdlt::DatetimeTz *result, const char *timeZoneId); static int now(LocalDatetime *result, const char *timeZoneId); // Load, into the specified 'result', the current local time value // in the time zone indicated by the specified 'timeZoneId'. Return 0 // on success, and a non-zero value with no effect otherwise. A // return value of 'ErrorCode::k_UNSUPPORTED_ID' indicates // that 'timeZoneid' is not recognized. static int validateLocalTime(bool *result, const bdlt::DatetimeTz& localTime, const char *timeZoneId); // Load, into the specified 'result', 'true' if the offset from UTC of // the specified 'localTime' (i.e., 'localTime.offset()') is consistent // with the actual local time offset, as indicated by time zone data, // at the UTC time 'localTime.utcDatetime()' in the time zone indicated // by the specified 'timeZoneId', and 'false' otherwise. Return 0 on // success, and a non-zero value with 'false' loaded into 'result' // otherwise. A return value of 'ErrorCode::k_UNSUPPORTED_ID' // indicates that 'timeZoneId' is not recognized. Note that this // operation verifies that the properties of the provided local time // are consistent with the time zone data. static int validateLocalTime(bool *result, const LocalDatetime& localTime); // Load, into the specified 'result', 'true' if the time zone // identifier of the specified 'localTime' (i.e., // 'localTime.timeZoneId()') is a valid identifier, and the offset from // UTC of 'localTime' (i.e., 'localTime.datetimeTz().offset()') is // consistent with the actual local time offset, as indicated by time // zone data, at the UTC time 'localTime.datetimeTz().utcDatetime()' in // the time zone indicated by 'localTime.timeZoneId()', and 'false' // otherwise. Return 0 on success, and a non-zero value with 'false' // loaded into 'result' otherwise. A return value of // 'ErrorCode::k_UNSUPPORTED_ID' indicates that 'timeZoneId' is not // recognized. Note that this operation verifies that the properties // of the provided local time are consistent with the time zone data. }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ------------------- // struct TimeZoneUtil // ------------------- // CLASS METHODS inline int TimeZoneUtil::convertUtcToLocalTime( bdlt::DatetimeTz *result, const char *targetTimeZoneId, const bdlt::Datetime& utcTime) { BSLS_ASSERT(result); BSLS_ASSERT(targetTimeZoneId); return TimeZoneUtilImp::convertUtcToLocalTime( result, targetTimeZoneId, utcTime, DefaultZoneinfoCache::defaultCache()); } inline int TimeZoneUtil::convertLocalToLocalTime( LocalDatetime *result, const char *targetTimeZoneId, const LocalDatetime& srcTime) { BSLS_ASSERT(result); BSLS_ASSERT(targetTimeZoneId); return convertUtcToLocalTime(result, targetTimeZoneId, srcTime.datetimeTz().utcDatetime()); } inline int TimeZoneUtil::convertLocalToLocalTime( LocalDatetime *result, const char *targetTimeZoneId, const bdlt::DatetimeTz& srcTime) { BSLS_ASSERT(result); BSLS_ASSERT(targetTimeZoneId); return convertUtcToLocalTime(result, targetTimeZoneId, srcTime.utcDatetime()); } inline int TimeZoneUtil::convertLocalToLocalTime( bdlt::DatetimeTz *result, const char *targetTimeZoneId, const LocalDatetime& srcTime) { BSLS_ASSERT(result); BSLS_ASSERT(targetTimeZoneId); return convertUtcToLocalTime(result, targetTimeZoneId, srcTime.datetimeTz().utcDatetime()); } inline int TimeZoneUtil::convertLocalToLocalTime( bdlt::DatetimeTz *result, const char *targetTimeZoneId, const bdlt::DatetimeTz& srcTime) { BSLS_ASSERT(result); BSLS_ASSERT(targetTimeZoneId); return convertUtcToLocalTime(result, targetTimeZoneId, srcTime.utcDatetime()); } inline int TimeZoneUtil::initLocalTime(bdlt::DatetimeTz *result, LocalTimeValidity::Enum *resultValidity, const bdlt::Datetime& localTime, const char *timeZoneId, DstPolicy::Enum dstPolicy) { BSLS_ASSERT(result); BSLS_ASSERT(resultValidity); BSLS_ASSERT(timeZoneId); return TimeZoneUtilImp::initLocalTime( result, resultValidity, localTime, timeZoneId, dstPolicy, DefaultZoneinfoCache::defaultCache()); } inline int TimeZoneUtil::initLocalTime(bdlt::DatetimeTz *result, const bdlt::Datetime& localTime, const char *timeZoneId, DstPolicy::Enum dstPolicy) { BSLS_ASSERT(result); BSLS_ASSERT(timeZoneId); LocalTimeValidity::Enum validityStatus; return initLocalTime(result, &validityStatus, localTime, timeZoneId, dstPolicy); } inline int TimeZoneUtil::loadLocalTimePeriod(LocalTimePeriod *result, const LocalDatetime& localTime) { BSLS_ASSERT(result); return loadLocalTimePeriod(result, localTime.datetimeTz(), localTime.timeZoneId().c_str()); } inline int TimeZoneUtil::loadLocalTimePeriod(LocalTimePeriod *result, const bdlt::DatetimeTz& localTime, const char *timeZoneId) { BSLS_ASSERT(result); BSLS_ASSERT(timeZoneId); return loadLocalTimePeriodForUtc(result, timeZoneId, localTime.utcDatetime()); } inline int TimeZoneUtil::now(bdlt::DatetimeTz *result, const char *timeZoneId) { BSLS_ASSERT(result); BSLS_ASSERT(timeZoneId); bdlt::Datetime utcNow = bdlt::CurrentTime::utc(); return convertUtcToLocalTime(result, timeZoneId, utcNow); } inline int TimeZoneUtil::now(LocalDatetime *result, const char *timeZoneId) { BSLS_ASSERT(result); BSLS_ASSERT(timeZoneId); bdlt::Datetime utcNow = bdlt::CurrentTime::utc(); return convertUtcToLocalTime(result, timeZoneId, utcNow); } inline int TimeZoneUtil::validateLocalTime(bool *result, const LocalDatetime& localTime) { BSLS_ASSERT(result); return validateLocalTime(result, localTime.datetimeTz(), localTime.timeZoneId().c_str()); } } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2018 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------