BDE 4.39.x Production Release
Loading...
Searching...
No Matches
baltzo_timezoneutil.h
Go to the documentation of this file.
1/// @file baltzo_timezoneutil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// baltzo_timezoneutil.h -*-C++-*-
8#ifndef INCLUDED_BALTZO_TIMEZONEUTIL
9#define INCLUDED_BALTZO_TIMEZONEUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup baltzo_timezoneutil baltzo_timezoneutil
15/// @brief Provide utilities for converting times among different time zones.
16/// @addtogroup bal
17/// @{
18/// @addtogroup baltzo
19/// @{
20/// @addtogroup baltzo_timezoneutil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#baltzo_timezoneutil-purpose"> Purpose</a>
25/// * <a href="#baltzo_timezoneutil-classes"> Classes </a>
26/// * <a href="#baltzo_timezoneutil-description"> Description </a>
27/// * <a href="#baltzo_timezoneutil-valid-ambiguous-and-invalid-local-time-values"> Valid, Ambiguous, and Invalid Local-Time Values </a>
28/// * <a href="#baltzo_timezoneutil-daylight-saving-time-policies-and-disambiguation"> Daylight-Saving Time (DST) Policies and Disambiguation </a>
29/// * <a href="#baltzo_timezoneutil-result-of-convertlocaltoutc-for-various-baltzo-dstpolicy-values"> Result of convertLocalToUtc for Various baltzo::DstPolicy Values </a>
30/// * <a href="#baltzo_timezoneutil-thread-safety"> Thread Safety </a>
31/// * <a href="#baltzo_timezoneutil-usage"> Usage </a>
32/// * <a href="#baltzo_timezoneutil-example-1-converting-a-utc-time-to-a-local-time"> Example 1: Converting a UTC time to a Local Time </a>
33/// * <a href="#baltzo_timezoneutil-example-2-converting-a-local-time-in-one-time-zone-to-another-time-zone"> Example 2: Converting a Local Time in One Time Zone to Another Time Zone </a>
34/// * <a href="#baltzo_timezoneutil-example-3-initializing-a-local-time"> Example 3: Initializing a Local Time </a>
35/// * <a href="#baltzo_timezoneutil-example-4-obtaining-information-about-a-time-value"> Example 4: Obtaining Information About a Time Value </a>
36///
37/// # Purpose {#baltzo_timezoneutil-purpose}
38/// Provide utilities for converting times among different time zones.
39///
40/// # Classes {#baltzo_timezoneutil-classes}
41///
42/// - baltzo::TimeZoneUtil: utilities for converting local time values
43///
44/// @see baltzo_localdatetime, baltzo_zoneinfo, baltzo_defaultzoneinfocache
45///
46/// # Description {#baltzo_timezoneutil-description}
47/// This component provides a namespace, `baltzo::TimeZoneUtil`,
48/// containing utility functions for converting time values to and from their
49/// corresponding local time representations in (possibly) different time zones.
50/// The primary methods provided include:
51/// * `convertLocalToLocalTime` and `convertUtcToLocalTime`, for converting a
52/// time to the corresponding local-time value in some time zone;
53/// * `convertLocalToUtc`, for converting a local-time value into the
54/// corresponding UTC time value;
55/// * `initLocalTime`, for initializing a local-time value.
56/// Additionally, the `loadLocalTimePeriod` and `loadLocalTimePeriodForUtc`
57/// methods enable clients to obtain information about a time value, such as
58/// whether the provided time is a daylight-saving time value. Finally note
59/// that, all of the functions in this utility component make use of a
60/// process-wide cache of time-zone information (see
61/// @ref baltzo_defaultzoneinfocache ).
62///
63/// ## Valid, Ambiguous, and Invalid Local-Time Values {#baltzo_timezoneutil-valid-ambiguous-and-invalid-local-time-values}
64///
65///
66/// There are intervals around each daylight-saving time transition where a
67/// `bdlt::Datetime` object holding a local time may not describe a valid or
68/// unique clock time in the local time zone (see @ref baltzo_localtimevalidity ).
69/// When interpreting a local-time value represented using a `bdlt::Datetime`
70/// object with respect to a given time zone, there are three possible
71/// scenarios:
72///
73/// 1. The local time is *valid* and *unique*: The local time representation is
74/// valid, and unique within the time zone (the most likely scenario). For
75/// example, in New York at "Aug 31, 2010 12:00AM", DST was in effect and the
76/// local-time offset from UTC was -4 hours.
77/// 2. The local time is *valid*, but *ambiguous*: The local time representation
78/// is valid, but could correctly be interpreted as either of two possible
79/// times, as may happen around a daylight-saving time transition where the
80/// local-time offset from UTC increases (e.g., in the United States local
81/// time "falls back" by an hour in the fall). Thus, a local time within
82/// such a transition period occurs twice, and is ambiguous without
83/// additional information. For example, in New York, daylight-saving time
84/// was in effect until "Nov 7, 2010 2:00AM" when clocks were set back by an
85/// hour; therefore, the time "Nov 7, 2010 1:30AM" occurred twice, and that
86/// description (as represented in a `bdlt::Datetime` object) could refer to
87/// either of those two times.
88/// 3. The local time is **invalid**: The local-time representation doesn't
89/// correspond to a valid time within the given time zone, as may happen
90/// around a daylight-saving time transition where the offset from UTC
91/// decreases (e.g., in the United States local time "springs forward" by an
92/// hour in the spring). Thus, local times that are skipped during such a
93/// transition are invalid. For example, in New York, DST was in effect
94/// starting "Mar 14, 2010 2:00AM" when clocks are set forward an hour;
95/// therefore, the local time "Mar 14, 2010 2:30AM" never occurs.
96///
97/// Note that the functions provided in this component guarantee a graceful
98/// handling of all three scenarios. Ambiguity and invalidity, when they arise,
99/// are resolved according to a user-supplied daylight-saving time policy that
100/// describes how to interpret the input time values (see @ref baltzo_dstpolicy ).
101///
102/// ### Daylight-Saving Time (DST) Policies and Disambiguation {#baltzo_timezoneutil-daylight-saving-time-policies-and-disambiguation}
103///
104///
105/// The `baltzo::TimeZoneUtil` methods that take, as input, a `bdlt::Datetime`
106/// object representing a local time (i.e., a local-time value without a UTC
107/// offset) also accept an optional `baltzo::DstPolicy::Enum`. This (optional)
108/// argument policy allows clients to specify how they would like the operation
109/// to interpret the input value (as such a value may be ambiguous or invalid
110/// within the indicated time zone -- see above). Clients are, however,
111/// encouraged to use the default policy, `e_UNSPECIFIED`, unless there is some
112/// specific reason they require a different option.
113///
114/// Three enumerated `baltzo::DstPolicy` values are supported:
115///
116/// 1. `e_UNSPECIFIED` (default)
117/// - The client does not explicitly indicate whether the associated input
118/// time represents a daylight-saving time value, and the operation will
119/// determine how to interpret the time solely based on the input itself.
120/// If the input value is *valid* and *unique*, the operation will use its
121/// (unique) corresponding UTC value. If the input is either *ambiguous*
122/// or *invalid*, the operation will use the later of two potential
123/// interpretations of the input (determined, e.g., by applying the
124/// standard and daylight-saving time UTC offsets to the input). For
125/// *invalid* times, this choice reflects the assumption that the user most
126/// likely forgot to adjust their clock. For *ambiguous* times, this
127/// choice is arbitrary (but is consistent with common implementations of
128/// the C standard library).
129/// 2. `e_STANDARD`
130/// - Indicates that the operation should treat the associated input time
131/// value as a standard time, using the UTC value computed by applying the
132/// standard-time UTC offset. Note that the standard-time UTC offset is
133/// used even when the input time value is (unambiguously) *not* a standard
134/// time, which would result in a UTC time that does not correspond to a
135/// standard time within the time zone.
136/// 3. `e_DST`
137/// - Indicates that the operation should treat the associated input time
138/// value as a daylight-saving time, using the UTC value computed by
139/// applying the daylight-saving time UTC offset. Note that the
140/// daylight-saving-time UTC offset is used even when the input time value
141/// is (unambiguously) *not* a daylight-saving time, which would result in
142/// a UTC time that does not correspond to a daylight-saving time within
143/// the time zone.
144///
145/// Note that these policies are intended to reflect the behavior of the C
146/// standard library function `mktime` and its interpretation of the `tm_isdst`
147/// value of the supplied `tm` structure. The behavior for the "unspecified"
148/// policy, however, is not strictly defined by either the ISO or POSIX
149/// standards, and varies among implementations.
150///
151/// ### Result of convertLocalToUtc for Various baltzo::DstPolicy Values {#baltzo_timezoneutil-result-of-convertlocaltoutc-for-various-baltzo-dstpolicy-values}
152///
153///
154/// The following table summarizes the effect that the different
155/// `baltzo::DstPolicy` values have on a call to `convertLocalToUtc` for several
156/// possible time values in New York. Note that standard local time in New York
157/// is UTC-5:00, and daylight-saving local time there is UTC-4:00.
158/// @code
159/// Result format: UTC 'bdlt::Time' & corresponding local 'bdlt::TimeTz'.
160/// ,--------------------------------------------------------------------------.
161/// | Input in New York | 'baltzo::DstPolicy::Enum' |
162/// | Local Time |-----------------------------------------------------|
163/// | (bdlt::Datetime) | *_UNSPECIFIED | *_STANDARD | *_DST |
164/// |==========================================================================|
165/// | Jan 1, 2010 01:30 | 06:30:00 UTC | 06:30:00 UTC | 05:30:00 UTC |
166/// | (standard time) | (01:30:00-5:00) | (01:30:00-5:00) | (00:30:00-5:00) |
167/// | | | [1] | [2] |
168/// |--------------------|-----------------------------------------------------|
169/// | Mar 14, 2010 02:30 | 07:30:00 UTC | 07:30:00 UTC | 06:30:00 UTC |
170/// | (invalid) | (03:30:00-4:00) | (03:30:00-4:00) | (01:30:00-5:00) |
171/// | | [3] | [4] | [5] |
172/// |--------------------|-----------------------------------------------------|
173/// | Apr 1, 2010 01:30 | 05:30:00 UTC | 06:30:00 UTC | 05:30:00 UTC |
174/// | (daylight-saving) | (01:30:00-4:00) | (02:30:00-4:00) | (01:30:00-4:00) |
175/// | | | [6] | [7] |
176/// |--------------------|-----------------------------------------------------|
177/// | Nov 7, 2010 01:30 | 06:30:00 UTC | 06:30:00 UTC | 05:30:00 UTC |
178/// | (ambiguous) | (01:30:00-5:00) | (01:30:00-5:00) | (01:30:00-4:00) |
179/// | | [8] | | |
180/// `--------------------------------------------------------------------------'
181/// @endcode
182///
183/// 1. "Jan 1, 2010 01:30" is unambiguously a standard time value. The result
184/// is simply the corresponding UTC time "Jan 1, 2010 06:30 UTC".
185/// 2. "Jan 1, 2010 01:30" is unambiguously a standard time value, so the
186/// supplied policy, `e_DST`, contradicts the actual occurrence of
187/// daylight-saving time in New York. The input time is adjusted by the UTC
188/// offset for daylight-saving time in New York (-4:00) resulting in a UTC
189/// time 05:30. Note that the result, "Jan 1, 2010 05:30 UTC", corresponds
190/// to the New York time "Jan 1, 2010 00:30:00-5:00" (a standard time).
191/// 3. "Mar 14, 2010 02:30" is not a valid local time in New York (a correctly
192/// administered clock would have been set ahead an hour at 2:00AM). The
193/// operation will use the later of two potential values, determined by
194/// applying the standard and daylight-saving time UTC offsets to the input
195/// (07:30 UTC and 06:30 UTC, respectively). Note that the selection of the
196/// later time reflects an assumption that the user forgot to adjust the
197/// clock.
198/// 4. The input time is adjusted by the UTC offset for standard time in New
199/// York (-5:00) resulting in the UTC time 07:30. Note that "Mar 14, 2010
200/// 07:30 UTC" corresponds to the New York time "Mar 14, 2010 03:30-4:00" (a
201/// daylight-saving time).
202///
203/// 5. The input time is adjusted by the UTC offset for daylight-saving time in
204/// New York (-4:00) resulting in the UTC time 06:30. Note that "Mar 14,
205/// 2010. 06:30 UTC" corresponds to the New York time "Mar 14, 2010
206/// 01:30-5:00" (a standard time).
207///
208/// 6. "Apr 1, 2010 01:30" is unambiguously a daylight-saving time value, so the
209/// supplied policy `e_STANDARD` contradicts the actual occurrence of
210/// daylight-saving time in New York. The input time is adjusted by the UTC
211/// offset for standard time in New York (-5:00) resulting in a UTC time
212/// 06:30. Note that "Apr 1, 2010 06:30 UTC" corresponds to the New York
213/// time "Apr 1, 2010 02:30:00-4:00" (a daylight-saving time).
214///
215/// 7. "Apr 1, 2010 01:30" is unambiguously a daylight-saving time value. The
216/// result is simply the corresponding UTC time "Apr 1, 2010 06:30 UTC".
217/// 8. "Nov 7, 2010 01:30" is a valid, but ambiguous, local time in New York
218/// (clocks are set back by an hour at 2:00AM, so 1:30AM occurs twice). The
219/// operation will use the later of two potential values determined by
220/// applying the standard and daylight-saving time UTC offsets to the input
221/// (06:30 UTC and 05:30 UTC, respectively). Note that the selection of the
222/// later time is arbitrary, but is consistent with common implementations of
223/// the C standard library.
224///
225/// ## Thread Safety {#baltzo_timezoneutil-thread-safety}
226///
227///
228/// The functions provided by `baltzo::TimeZoneUtil` are *thread-safe*, meaning
229/// they can be safely executed concurrently.
230///
231/// ## Usage {#baltzo_timezoneutil-usage}
232///
233///
234/// The following usage examples demonstrate how to use various functions
235/// provided by `baltzo::TimeZoneUtil` to perform conversions on various time
236/// representations.
237///
238/// ### Example 1: Converting a UTC time to a Local Time {#baltzo_timezoneutil-example-1-converting-a-utc-time-to-a-local-time}
239///
240///
241/// In this usage example, we illustrate how to convert a UTC time to its
242/// corresponding local time in a given time zone. We start by creating a
243/// `bdlt::Datetime` object holding the UTC time "July 31, 2010 15:00:00":
244/// @code
245/// bdlt::Datetime utcTime(2010, 7, 31, 15, 0, 0);
246/// @endcode
247/// Then, we create a `baltzo::LocalDatetime` object to hold the result of the
248/// conversion operation:
249/// @code
250/// baltzo::LocalDatetime newYorkTime;
251/// @endcode
252/// Now, we call the `convertUtcToLocalTime` function in `baltzo::TimeZoneUtil`:
253/// @code
254/// int status = baltzo::TimeZoneUtil::convertUtcToLocalTime(&newYorkTime,
255/// "America/New_York",
256/// utcTime);
257/// if (0 != status) {
258/// // A non-zero 'status' indicates there was an error in the conversion
259/// // (e.g., the time zone id was not valid or the environment has not
260/// // been correctly configured).
261///
262/// return 1; // RETURN
263/// }
264/// @endcode
265/// Finally, we observe that the result in `newYorkTime` is "July 31, 2010
266/// 11:00:00" and that the offset from UTC applied was -4 hours:
267/// @code
268/// const bdlt::Datetime test = newYorkTime.datetimeTz().localDatetime();
269/// assert(2010 == test.year()); assert(11 == test.hour());
270/// assert( 7 == test.month()); assert( 0 == test.minute());
271/// assert( 31 == test.day()); assert( 0 == test.second());
272///
273/// assert( -4 * 60 == newYorkTime.datetimeTz().offset());
274/// @endcode
275///
276/// ### Example 2: Converting a Local Time in One Time Zone to Another Time Zone {#baltzo_timezoneutil-example-2-converting-a-local-time-in-one-time-zone-to-another-time-zone}
277///
278///
279/// In this example we illustrate how to convert a local time in a given time
280/// zone directly to its corresponding local time in another time zone. In
281/// particular, we want to convert the time "July 31, 2010 15:00:00" in New York
282/// to its corresponding time in Rome, Italy.
283///
284/// First, we create a `bdlt::Datetime` object representing the time "July 31,
285/// 2010 15:00:00" in New York:
286/// @code
287/// bdlt::Datetime newYorkTime(2010, 7, 31, 15, 0, 0);
288/// @endcode
289/// Now, let's apply the conversion operation to obtain a
290/// `baltzo::LocalDatetime` object representing the corresponding local time in
291/// Italy:
292/// @code
293/// baltzo::LocalDatetime romeTime;
294/// int status = baltzo::TimeZoneUtil::convertLocalToLocalTime(
295/// &romeTime,
296/// "Europe/Rome",
297/// newYorkTime,
298/// "America/New_York");
299/// if (0 != status) {
300/// // A non-zero 'status' indicates there was an error in the conversion
301/// // (e.g., the time zone id was not valid or the environment has not
302/// // been correctly configured).
303///
304/// return 1; // RETURN
305/// }
306/// @endcode
307/// Notice that we did not specify the optional `dstPolicy` argument to
308/// `convertLocalToLocalTime`. The default value should be appropriate for most
309/// users.
310///
311/// Finally, we verify that the value of `romeTime` is "July 31, 2010 21:00:00",
312/// which is the time in Italy corresponding to "July 31, 2010 15:00:00" in New
313/// York:
314/// @code
315/// const bdlt::Datetime test = romeTime.datetimeTz().localDatetime();
316/// assert(2010 == test.year()); assert(21 == test.hour());
317/// assert( 7 == test.month()); assert( 0 == test.minute());
318/// assert( 31 == test.day()); assert( 0 == test.second());
319///
320/// assert( 2 * 60 == romeTime.datetimeTz().offset());
321/// @endcode
322///
323/// ### Example 3: Initializing a Local Time {#baltzo_timezoneutil-example-3-initializing-a-local-time}
324///
325///
326/// In this example we illustrate how to create a `baltzo::LocalDatetime` from a
327/// `bdlt::Datetime`, which may not represent a unique (or valid) clock time.
328///
329/// First, we create a `bdlt::Datetime` object for the New York local time "Jul
330/// 31, 2010 15:00:00". Note that this local date-time occurs during a DST
331/// transition and is an invalid date-time.
332/// @code
333/// bdlt::Datetime uniqueTime(2010, 7, 31, 15, 0, 0);
334/// @endcode
335/// Then, we call `initLocalTime`, which returns a `baltzo::LocalDatetime`
336/// object. `initLocalTime` also optionally returns
337/// `baltzo::LocalTimeValidity::Enum`, indicating whether the provided input was
338/// a valid and unique clock time. Note that invalid or ambiguous times are
339/// resolved using the optionally provided `baltzo::DstPolicy::Enum` (see the
340/// section {Daylight-Saving Time (DST) Policies and Disambiguation}):
341/// @code
342/// baltzo::LocalDatetime localTime;
343/// baltzo::LocalTimeValidity::Enum validity;
344/// int status = baltzo::TimeZoneUtil::initLocalTime(&localTime,
345/// &validity,
346/// uniqueTime,
347/// "America/New_York");
348/// if (0 != status) {
349/// return 1;
350/// }
351/// @endcode
352/// Now, we verify the value of `localTime` is "Jul 31, 2010 15:00:00" with an
353/// offset of -4:00 from UTC, in the time zone "America/New_York".
354/// @code
355/// const bdlt::Datetime invalidTest = localTime.datetimeTz().localDatetime();
356/// assert(2010 == invalidTest.year()); assert(15 == invalidTest.hour());
357/// assert( 7 == invalidTest.month()); assert( 0 == invalidTest.minute());
358/// assert( 31 == invalidTest.day()); assert( 0 == invalidTest.second());
359///
360/// assert( -4 * 60 == localTime.datetimeTz().offset());
361/// assert("America/New_York" == localTime.timeZoneId());
362/// @endcode
363/// In addition, the time provided represents a unique and valid clock time in
364/// New York (because it does not fall near a daylight-saving time transition):
365/// @code
366/// assert(baltzo::LocalTimeValidity::e_VALID_UNIQUE == validity);
367/// @endcode
368/// By contrast, if we call `initLocalTime` for a time value that falls during a
369/// during a daylight-saving time transition, the returned
370/// `baltzo::LocalTimeValidity::Enum` will indicate if the supplied time either
371/// does not represent a valid clock time in the time zone (as may occur when
372/// clocks are set forward), or does not represent a unique clock time (as may
373/// occur when clocks are set back).
374///
375/// For example, suppose we call `initLocalTime` for "Mar 14, 2010 02:30"; this
376/// clock time does not occurs in New York, as clocks are set forward by an hour
377/// at 2am local time:
378/// @code
379/// bdlt::Datetime invalidTime(2010, 3, 14, 2, 30, 0);
380/// status = baltzo::TimeZoneUtil::initLocalTime(&localTime,
381/// &validity,
382/// invalidTime,
383/// "America/New_York");
384/// if (0 != status) {
385/// return 1;
386/// }
387/// @endcode
388/// Now, we verify the value of `localTime` represents a valid and unique time
389/// of "Mar 14, 2010 03:30:00-04:00" in the "America/New_York" time zone.
390/// @code
391/// const bdlt::Datetime test = localTime.datetimeTz().localDatetime();
392/// assert(2010 == test.year()); assert( 3 == test.hour());
393/// assert( 3 == test.month()); assert(30 == test.minute());
394/// assert( 14 == test.day()); assert( 0 == test.second());
395///
396/// assert("America/New_York" == localTime.timeZoneId());
397/// assert( -4 * 60 == localTime.datetimeTz().offset());
398/// @endcode
399/// Finally, we verify that the validity status returned for `invalidTime` is
400/// `e_INVALID`:
401/// @code
402/// assert(baltzo::LocalTimeValidity::e_INVALID == validity);
403/// @endcode
404///
405/// ### Example 4: Obtaining Information About a Time Value {#baltzo_timezoneutil-example-4-obtaining-information-about-a-time-value}
406///
407///
408/// In this example we illustrate how to obtain additional information about a
409/// local time in a given time zone using the `loadLocalTimePeriod` method.
410/// Using `loadLocalTimePeriod` a client can determine, for a point in time, the
411/// attributes that characterize local time in a given time zone (e.g., the
412/// offset from UTC, whether it is daylight-saving time) as well as the interval
413/// over which those attributes apply (see @ref baltzo_localtimeperiod ).
414///
415/// First, we create a `baltzo::LocalDatetime` object for the New York local
416/// time "Jul 31, 2010 15:00:00-04:00". Note that this `baltzo::LocalDatetime`
417/// may also be created as in example 3.
418/// @code
419/// bdlt::DatetimeTz localTimeTz(bdlt::Datetime(2010, 7, 31, 15, 0, 0),
420/// -4 * 60);
421/// baltzo::LocalDatetime localTime(localTimeTz, "America/New_York");
422/// @endcode
423/// Then, we call `loadLocalTimePeriod`, which returns a
424/// `baltzo::LocalTimePeriod` object that is loaded with attributes
425/// characterizing local time in New York on "Mar 14, 2010 03:30:00", and the
426/// interval over which those attributes are in effect.
427/// @code
428/// baltzo::LocalTimePeriod period;
429/// int status = baltzo::TimeZoneUtil::loadLocalTimePeriod(&period, localTime);
430/// if (0 != status) {
431/// // A non-zero 'status' indicates there was an error in the conversion
432/// // (e.g., the time zone id was not valid or the environment has not
433/// // been correctly configured).
434///
435/// return 1; // RETURN
436/// }
437/// @endcode
438/// Now we examine the returned properties. "Mar 14, 2010 03:30:00" is during
439/// daylight-saving time, which is -4:00 UTC, and the type of local time is
440/// sometimes abbreviated "EDT" for "Eastern Daylight Time". "Eastern Daylight
441/// Time" is in effect from "Mar 14, 2010 7am UTC" to "Nov 7, 2010 6am UTC".
442/// Note that the abbreviation provided ("EDT") is not canonical or localized.
443/// In general the provided abbreviations should not be displayed to users (they
444/// are intended for development and debugging only):
445/// @code
446/// assert(true == period.descriptor().dstInEffectFlag());
447/// assert(-4 * 60 * 60 == period.descriptor().utcOffsetInSeconds());
448/// assert("EDT" == period.descriptor().description());
449/// assert(bdlt::Datetime(2010, 3, 14, 7, 0, 0) == period.utcStartTime());
450/// assert(bdlt::Datetime(2010, 11, 7, 6, 0, 0) == period.utcEndTime());
451/// @endcode
452/// @}
453/** @} */
454/** @} */
455
456/** @addtogroup bal
457 * @{
458 */
459/** @addtogroup baltzo
460 * @{
461 */
462/** @addtogroup baltzo_timezoneutil
463 * @{
464 */
465
466#include <balscm_version.h>
467
469#include <baltzo_dstpolicy.h>
472#include <baltzo_localdatetime.h>
473
474#include <bdlt_currenttime.h>
475#include <bdlt_datetime.h>
476#include <bdlt_datetimetz.h>
477
478#include <bsls_assert.h>
479#include <bsls_review.h>
480#include <bsls_timeinterval.h>
481
482#include <bsl_iosfwd.h>
483
484
485namespace baltzo {
486
487class LocalTimePeriod;
488class ZoneinfoCache;
489
490 // ===================
491 // struct TimeZoneUtil
492 // ===================
493
494/// This `struct` provides a namespace for utility functions that convert
495/// time values to, from, and between, their corresponding local time
496/// representations in (possibly) different time zones.
497///
498/// These utility functions are:
499/// * *alias-safe*
500/// * *exception-neutral* (agnostic)
501/// * *thread-safe*
502/// For terminology see @ref bsldoc_glossary .
503///
504/// See @ref baltzo_timezoneutil
506
507 // CLASS METHODS
508
509 /// Load, into the specified `result`, the local time value that is the
510 /// specified `interval` in the future of the specified `originalTime`
511 /// (in the time zone `originalTime.timeZoneId()`). Return 0 on
512 /// success, and a non-zero value with no effect otherwise. A return
513 /// value of `ErrorCode::k_UNSUPPORTED_ID` indicates that
514 /// `targetTimeZoneId` was not recognized, and a return value of
515 /// `ErrorCode::k_OUT_OF_RANGE` indicates that the result of the
516 /// operation would have been outside the range of values representable
517 /// by the `result` type. The resulting local-time is equivalent to
518 /// adding `interval` to `originalTime.datetimeTz().utcDatetime()` and
519 /// converting the result into the local time of
520 /// `originalTime.timeZoneId()`.
521 static int addInterval(LocalDatetime *result,
522 const LocalDatetime& originalTime,
523 const bsls::TimeInterval& interval);
524
525 /// Load, into the specified `result`, the local date-time value (in the
526 /// time zone indicated by the specified `targetTimeZoneId`)
527 /// corresponding to the specified `utcTime`. The offset from UTC of
528 /// the time zone is rounded down to minute precision. Return 0 on
529 /// success, and a non-zero value with no effect otherwise. A return
530 /// value of `ErrorCode::k_UNSUPPORTED_ID` indicates that
531 /// `targetTimeZoneId` was not recognized, and a return value of
532 /// `ErrorCode::k_OUT_OF_RANGE` indicates that the result of the
533 /// operation would have been outside the range of values representable
534 /// by the `result` type.
536 const char *targetTimeZoneId,
537 const bdlt::Datetime& utcTime);
538 static int convertUtcToLocalTime(bdlt::DatetimeTz *result,
539 const char *targetTimeZoneId,
540 const bdlt::Datetime& utcTime);
541
542 /// Load, into the specified `result`, the local date-time value (in the
543 /// time zone indicated by the specified `targetTimeZoneId`)
544 /// corresponding to the local time indicated by the specified
545 /// `srcTime`. The offset from UTC of both time zones is rounded down
546 /// to minute precision. Return 0 on success, and a non-zero value with
547 /// no effect otherwise. A return value of
548 /// `ErrorCode::k_UNSUPPORTED_ID` indicates that `targetTimeZoneId` was
549 /// not recognized, and a return value of `ErrorCode::k_OUT_OF_RANGE`
550 /// indicates that the result of the operation would have been outside
551 /// the range of values representable by the `result` type.
552 static int convertLocalToLocalTime(LocalDatetime *result,
553 const char *targetTimeZoneId,
554 const LocalDatetime& srcTime);
555 static int convertLocalToLocalTime(
556 LocalDatetime *result,
557 const char *targetTimeZoneId,
558 const bdlt::DatetimeTz& srcTime);
559 static int convertLocalToLocalTime(bdlt::DatetimeTz *result,
560 const char *targetTimeZoneId,
561 const LocalDatetime& srcTime);
562 static int convertLocalToLocalTime(
563 bdlt::DatetimeTz *result,
564 const char *targetTimeZoneId,
565 const bdlt::DatetimeTz& srcTime);
566
567 /// Load, into the specified `result`, the local date-time value (in the
568 /// time zone indicated by the specified `targetTimeZoneId`)
569 /// corresponding to the local time indicated by the specified `srcTime`
570 /// (in the time zone indicated by the specified `srcTimeZoneId`).
571 /// Optionally specify a `dstPolicy` indicating whether or not `srcTime`
572 /// represents a daylight-saving time value. If `dstPolicy` is
573 /// unspecified and `srcTime` is a unique and valid time in the source
574 /// time zone, then perform the conversion using that uniquely described
575 /// time; if `dstPolicy` is unspecified and `srcTime` is either
576 /// ambiguous or invalid, then use the later of the two possible
577 /// interpretations of `srcTime`. The offset from UTC of both time
578 /// zones is rounded down to minute precision. Return 0 on success, and
579 /// a non-zero value with no effect otherwise. A return value of
580 /// `ErrorCode::k_UNSUPPORTED_ID` indicates that either
581 /// `targetTimeZoneId` or `srcTimeZoneId` was not recognized.
583 const char *targetTimeZoneId,
584 const bdlt::Datetime& srcTime,
585 const char *srcTimeZoneId,
586 DstPolicy::Enum dstPolicy =
589 const char *targetTimeZoneId,
590 const bdlt::Datetime& srcTime,
591 const char *srcTimeZoneId,
592 DstPolicy::Enum dstPolicy =
594
595 /// Load, into the specified `result`, the local date-time value --
596 /// including the local date, time, and resolved UTC offset -- indicated
597 /// by the specified `localTime` in the time zone indicated by the
598 /// specified `timeZoneId`. Optionally specify `resultValidity` in
599 /// which to load the validity of `localTime` as being unique, ambiguous
600 /// but valid, or invalid. Optionally specify a `dstPolicy` indicating
601 /// whether or not `localTime` represents a daylight-saving time value.
602 /// If `dstPolicy` is unspecified and `localTime` is a unique and valid
603 /// time in the source time zone, then perform the conversion using that
604 /// uniquely described time; if `dstPolicy` is unspecified and
605 /// `localTime` is either ambiguous or invalid, then use the later of
606 /// the two possible interpretations of `localTime`. The offset from
607 /// UTC of the time zone is rounded down to minute precision. Return 0
608 /// on success, and a non-zero value with no effect otherwise. A return
609 /// value of `ErrorCode::k_UNSUPPORTED_ID` indicates that `timeZoneId` was not recognized.
610 ///
611 /// \pre The behavior is undefined unless the result of
612 /// the initialization falls within the supported epoch.
613 static int initLocalTime(bdlt::DatetimeTz *result,
614 const bdlt::Datetime& localTime,
615 const char *timeZoneId,
616 DstPolicy::Enum dstPolicy =
618 static int initLocalTime(LocalDatetime *result,
619 const bdlt::Datetime& localTime,
620 const char *timeZoneId,
621 DstPolicy::Enum dstPolicy =
623 static int initLocalTime(bdlt::DatetimeTz *result,
624 LocalTimeValidity::Enum *resultValidity,
625 const bdlt::Datetime& localTime,
626 const char *timeZoneId,
627 DstPolicy::Enum dstPolicy =
629 static int initLocalTime(LocalDatetime *result,
630 LocalTimeValidity::Enum *resultValidity,
631 const bdlt::Datetime& localTime,
632 const char *timeZoneId,
633 DstPolicy::Enum dstPolicy =
635
636 /// Load, into the specified `result`, the UTC time value that
637 /// corresponds to the specified `localTime` in the time zone indicated
638 /// by the specified `timeZoneId`. Optionally specify a `dstPolicy`
639 /// indicating whether or not `localTime` represents a daylight-saving
640 /// time value. If `dstPolicy` is unspecified and `localTime` is a
641 /// unique and valid time in the source time zone, then perform the
642 /// conversion using that uniquely described time; if `dstPolicy` is
643 /// unspecified and `localTime` is either ambiguous or invalid, then use
644 /// the later of the two possible interpretations of `localTime`. The
645 /// offset from UTC of the time zone is rounded down to minute
646 /// precision. Return 0 on success, and a non-zero value with no effect
647 /// otherwise. A return value of `ErrorCode::k_UNSUPPORTED_ID`
648 /// indicates that `timeZoneId` was not recognized.
649 ///
650 /// \pre The behavior is undefined unless the result of the conversion falls within the
651 /// supported epoch.
653 const bdlt::Datetime& localTime,
654 const char *timeZoneId,
655 DstPolicy::Enum dstPolicy =
658 const bdlt::Datetime& localTime,
659 const char *timeZoneId,
660 DstPolicy::Enum dstPolicy =
662
663 /// Load, into the specified `result`, attributes characterizing the
664 /// specified `localTime` (i.e., the offset from UTC, whether
665 /// daylight-saving time is in effect and the description of the time
666 /// zone), as well as the time interval over which those attributes
667 /// apply. Return 0 on success, and a non-zero value with no effect
668 /// otherwise. A return value of `ErrorCode::k_UNSUPPORTED_ID`
669 /// indicates that `localTime.timeZoneId()` was not recognized.
670 static int loadLocalTimePeriod(LocalTimePeriod *result,
671 const LocalDatetime& localTime);
672
673 /// Load, into the specified `result`, attributes characterizing the
674 /// specified `localTime` in the time zone indicated by the specified
675 /// `timeZoneId` (i.e., the offset from UTC, whether daylight-saving
676 /// time is in effect and the description of the time zone), as well as
677 /// the time interval over which those attributes apply. Return 0 on
678 /// success, and a non-zero value with no effect otherwise. A return
679 /// value of `ErrorCode::k_UNSUPPORTED_ID` indicates that `timeZoneId`
680 /// was not recognized.
681 static int loadLocalTimePeriod(LocalTimePeriod *result,
682 const bdlt::DatetimeTz& localTime,
683 const char *timeZoneId);
684
685 /// Load, into the specified `result`, attributes characterizing local
686 /// time at the specified `utcTime` in the time zone indicated by the
687 /// specified `timeZoneId` (i.e., the offset from UTC, whether
688 /// daylight-saving time is in effect and the description of the time
689 /// zone), as well as the time interval over which those attributes
690 /// apply. Return 0 on success, and a non-zero value with no effect
691 /// otherwise. A return value of `ErrorCode::k_UNSUPPORTED_ID`
692 /// indicates that `timeZoneId` was not recognized.
694 const char *timeZoneId,
695 const bdlt::Datetime& utcTime);
696
697 /// Load, into the specified `result`, the current local time value
698 /// in the time zone indicated by the specified `timeZoneId`. Return 0
699 /// on success, and a non-zero value with no effect otherwise. A
700 /// return value of `ErrorCode::k_UNSUPPORTED_ID` indicates
701 /// that `timeZoneid` is not recognized.
702 static int now(bdlt::DatetimeTz *result, const char *timeZoneId);
703 static int now(LocalDatetime *result, const char *timeZoneId);
704
705 /// Load, into the specified `result`, `true` if the offset from UTC of
706 /// the specified `localTime` (i.e., `localTime.offset()`) is consistent
707 /// with the actual local time offset, as indicated by time zone data,
708 /// at the UTC time `localTime.utcDatetime()` in the time zone indicated
709 /// by the specified `timeZoneId`, and `false` otherwise. Return 0 on
710 /// success, and a non-zero value with `false` loaded into `result`
711 /// otherwise. A return value of `ErrorCode::k_UNSUPPORTED_ID` indicates that `timeZoneId` is not recognized.
712 ///
713 /// \note Note that this
714 /// operation verifies that the properties of the provided local time
715 /// are consistent with the time zone data.
716 static int validateLocalTime(bool *result,
717 const bdlt::DatetimeTz& localTime,
718 const char *timeZoneId);
719
720 /// Load, into the specified `result`, `true` if the time zone
721 /// identifier of the specified `localTime` (i.e.,
722 /// `localTime.timeZoneId()`) is a valid identifier, and the offset from
723 /// UTC of `localTime` (i.e., `localTime.datetimeTz().offset()`) is
724 /// consistent with the actual local time offset, as indicated by time
725 /// zone data, at the UTC time `localTime.datetimeTz().utcDatetime()` in
726 /// the time zone indicated by `localTime.timeZoneId()`, and `false`
727 /// otherwise. Return 0 on success, and a non-zero value with `false`
728 /// loaded into `result` otherwise. A return value of
729 /// `ErrorCode::k_UNSUPPORTED_ID` indicates that `timeZoneId` is not recognized.
730 ///
731 /// \note Note that this operation verifies that the properties
732 /// of the provided local time are consistent with the time zone data.
733 static int validateLocalTime(bool *result, const LocalDatetime& localTime);
734};
735
736// ============================================================================
737// INLINE DEFINITIONS
738// ============================================================================
739
740 // -------------------
741 // struct TimeZoneUtil
742 // -------------------
743
744// CLASS METHODS
745inline
747 bdlt::DatetimeTz *result,
748 const char *targetTimeZoneId,
749 const bdlt::Datetime& utcTime)
750{
751 BSLS_ASSERT(result);
752 BSLS_ASSERT(targetTimeZoneId);
753
755 result,
756 targetTimeZoneId,
757 utcTime,
759}
760
761inline
763 LocalDatetime *result,
764 const char *targetTimeZoneId,
765 const LocalDatetime& srcTime)
766{
767 BSLS_ASSERT(result);
768 BSLS_ASSERT(targetTimeZoneId);
769
770 return convertUtcToLocalTime(result,
771 targetTimeZoneId,
772 srcTime.datetimeTz().utcDatetime());
773}
774
775inline
777 LocalDatetime *result,
778 const char *targetTimeZoneId,
779 const bdlt::DatetimeTz& srcTime)
780{
781 BSLS_ASSERT(result);
782 BSLS_ASSERT(targetTimeZoneId);
783
784 return convertUtcToLocalTime(result,
785 targetTimeZoneId,
786 srcTime.utcDatetime());
787}
788
789inline
791 bdlt::DatetimeTz *result,
792 const char *targetTimeZoneId,
793 const LocalDatetime& srcTime)
794{
795 BSLS_ASSERT(result);
796 BSLS_ASSERT(targetTimeZoneId);
797
798 return convertUtcToLocalTime(result,
799 targetTimeZoneId,
800 srcTime.datetimeTz().utcDatetime());
801}
802
803inline
805 bdlt::DatetimeTz *result,
806 const char *targetTimeZoneId,
807 const bdlt::DatetimeTz& srcTime)
808{
809 BSLS_ASSERT(result);
810 BSLS_ASSERT(targetTimeZoneId);
811
812 return convertUtcToLocalTime(result,
813 targetTimeZoneId,
814 srcTime.utcDatetime());
815}
816
817inline
819 LocalTimeValidity::Enum *resultValidity,
820 const bdlt::Datetime& localTime,
821 const char *timeZoneId,
822 DstPolicy::Enum dstPolicy)
823{
824 BSLS_ASSERT(result);
825 BSLS_ASSERT(resultValidity);
826 BSLS_ASSERT(timeZoneId);
827
829 result,
830 resultValidity,
831 localTime,
832 timeZoneId,
833 dstPolicy,
835}
836
837inline
839 const bdlt::Datetime& localTime,
840 const char *timeZoneId,
841 DstPolicy::Enum dstPolicy)
842{
843 BSLS_ASSERT(result);
844 BSLS_ASSERT(timeZoneId);
845
846 LocalTimeValidity::Enum validityStatus;
847 return initLocalTime(result,
848 &validityStatus,
849 localTime,
850 timeZoneId,
851 dstPolicy);
852}
853
854inline
856 const LocalDatetime& localTime)
857{
858 BSLS_ASSERT(result);
859
860 return loadLocalTimePeriod(result,
861 localTime.datetimeTz(),
862 localTime.timeZoneId().c_str());
863}
864
865inline
867 const bdlt::DatetimeTz& localTime,
868 const char *timeZoneId)
869{
870 BSLS_ASSERT(result);
871 BSLS_ASSERT(timeZoneId);
872
873 return loadLocalTimePeriodForUtc(result,
874 timeZoneId,
875 localTime.utcDatetime());
876}
877
878inline
879int TimeZoneUtil::now(bdlt::DatetimeTz *result, const char *timeZoneId)
880{
881 BSLS_ASSERT(result);
882 BSLS_ASSERT(timeZoneId);
883
885 return convertUtcToLocalTime(result, timeZoneId, utcNow);
886}
887
888inline
889int TimeZoneUtil::now(LocalDatetime *result, const char *timeZoneId)
890{
891 BSLS_ASSERT(result);
892 BSLS_ASSERT(timeZoneId);
893
895 return convertUtcToLocalTime(result, timeZoneId, utcNow);
896}
897
898inline
900 const LocalDatetime& localTime)
901{
902 BSLS_ASSERT(result);
903
904 return validateLocalTime(result,
905 localTime.datetimeTz(),
906 localTime.timeZoneId().c_str());
907}
908
909} // close package namespace
910
911
912#endif
913
914// ----------------------------------------------------------------------------
915// Copyright 2018 Bloomberg Finance L.P.
916//
917// Licensed under the Apache License, Version 2.0 (the "License");
918// you may not use this file except in compliance with the License.
919// You may obtain a copy of the License at
920//
921// http://www.apache.org/licenses/LICENSE-2.0
922//
923// Unless required by applicable law or agreed to in writing, software
924// distributed under the License is distributed on an "AS IS" BASIS,
925// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
926// See the License for the specific language governing permissions and
927// limitations under the License.
928// ----------------------------- END-OF-FILE ----------------------------------
929
930/** @} */
931/** @} */
932/** @} */
Definition baltzo_localdatetime.h:166
const bsl::string & timeZoneId() const
Definition baltzo_localdatetime.h:563
const bdlt::DatetimeTz & datetimeTz() const
Definition baltzo_localdatetime.h:557
Definition baltzo_localtimeperiod.h:208
Definition bdlt_datetimetz.h:308
Datetime utcDatetime() const
Definition bdlt_datetimetz.h:695
Definition bdlt_datetime.h:330
const CHAR_TYPE * c_str() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:7405
Definition bsls_timeinterval.h:307
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition baltzo_datafileloader.h:259
static ZoneinfoCache * defaultCache(ZoneinfoCache *cache=0)
Definition baltzo_defaultzoneinfocache.h:389
Enum
Definition baltzo_dstpolicy.h:137
@ e_UNSPECIFIED
Definition baltzo_dstpolicy.h:143
Enum
Definition baltzo_localtimevalidity.h:151
static int initLocalTime(bdlt::DatetimeTz *result, LocalTimeValidity::Enum *resultValidity, const bdlt::Datetime &localTime, const char *timeZoneId, DstPolicy::Enum dstPolicy, ZoneinfoCache *cache)
static int convertUtcToLocalTime(bdlt::DatetimeTz *result, const char *resultTimeZoneId, const bdlt::Datetime &utcTime, ZoneinfoCache *cache)
Definition baltzo_timezoneutil.h:505
static int loadLocalTimePeriod(LocalTimePeriod *result, const LocalDatetime &localTime)
Definition baltzo_timezoneutil.h:855
static int addInterval(LocalDatetime *result, const LocalDatetime &originalTime, const bsls::TimeInterval &interval)
static int initLocalTime(bdlt::DatetimeTz *result, const bdlt::Datetime &localTime, const char *timeZoneId, DstPolicy::Enum dstPolicy=DstPolicy::e_UNSPECIFIED)
Definition baltzo_timezoneutil.h:838
static int now(bdlt::DatetimeTz *result, const char *timeZoneId)
Definition baltzo_timezoneutil.h:879
static int convertLocalToLocalTime(bdlt::DatetimeTz *result, const char *targetTimeZoneId, const bdlt::Datetime &srcTime, const char *srcTimeZoneId, 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)
static int convertUtcToLocalTime(LocalDatetime *result, const char *targetTimeZoneId, const bdlt::Datetime &utcTime)
static int loadLocalTimePeriodForUtc(LocalTimePeriod *result, const char *timeZoneId, const bdlt::Datetime &utcTime)
static int initLocalTime(LocalDatetime *result, const bdlt::Datetime &localTime, const char *timeZoneId, DstPolicy::Enum dstPolicy=DstPolicy::e_UNSPECIFIED)
static int convertLocalToLocalTime(LocalDatetime *result, const char *targetTimeZoneId, const bdlt::Datetime &srcTime, const char *srcTimeZoneId, DstPolicy::Enum dstPolicy=DstPolicy::e_UNSPECIFIED)
static int convertLocalToUtc(bdlt::Datetime *result, const bdlt::Datetime &localTime, const char *timeZoneId, DstPolicy::Enum dstPolicy=DstPolicy::e_UNSPECIFIED)
static int validateLocalTime(bool *result, const bdlt::DatetimeTz &localTime, const char *timeZoneId)
static int convertLocalToLocalTime(LocalDatetime *result, const char *targetTimeZoneId, const LocalDatetime &srcTime)
Definition baltzo_timezoneutil.h:762
static int convertLocalToUtc(LocalDatetime *result, const bdlt::Datetime &localTime, const char *timeZoneId, DstPolicy::Enum dstPolicy=DstPolicy::e_UNSPECIFIED)
static Datetime utc()
Definition bdlt_currenttime.h:304