BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlt_timetz.h
Go to the documentation of this file.
1/// @file bdlt_timetz.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlt_timetz.h -*-C++-*-
8#ifndef INCLUDED_BDLT_TIMETZ
9#define INCLUDED_BDLT_TIMETZ
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlt_timetz bdlt_timetz
15/// @brief Provide a representation of a time with time zone offset.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlt
19/// @{
20/// @addtogroup bdlt_timetz
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlt_timetz-purpose"> Purpose</a>
25/// * <a href="#bdlt_timetz-classes"> Classes </a>
26/// * <a href="#bdlt_timetz-description"> Description </a>
27/// * <a href="#bdlt_timetz-attributes"> Attributes </a>
28/// * <a href="#bdlt_timetz-caveats-on-time-zone-support"> Caveats on Time Zone Support </a>
29/// * <a href="#bdlt_timetz-iso-standard-text-representation"> ISO Standard Text Representation </a>
30/// * <a href="#bdlt_timetz-usage"> Usage </a>
31/// * <a href="#bdlt_timetz-example-1-comparing-times-from-multiple-time-zones"> Example 1: Comparing Times from Multiple Time Zones </a>
32///
33/// # Purpose {#bdlt_timetz-purpose}
34/// Provide a representation of a time with time zone offset.
35///
36/// # Classes {#bdlt_timetz-classes}
37///
38/// - bdlt::TimeTz: local-time value with time zone offset from UTC
39///
40/// @see bdlt_time, bdlt_datetimetz
41///
42/// # Description {#bdlt_timetz-description}
43/// This component provides a single, simply constrained
44/// value-semantic class, `bdlt::TimeTz`, that represents a time value in a
45/// particular time zone. Each `bdlt::TimeTz` object contains a time zone
46/// offset from UTC (in minutes) and a `bdlt::Time` value in that time zone.
47/// For logical consistency, the time value and offset should correspond to a
48/// geographically valid time zone, but such consistency is the user's
49/// responsibility. This component does not enforce logical constraints on any
50/// values.
51///
52/// The `localTime` and `utcTime` methods return `bdlt::Time` values
53/// corresponding to the local time and UTC time represented by the object,
54/// respectively. In addition, the `offset` method returns the time zone offset
55/// in minutes from UTC (i.e., `UTC + offset` equals local time).
56///
57/// ## Attributes {#bdlt_timetz-attributes}
58///
59///
60/// @code
61/// Name Type Default Simple Constraints
62/// ------------------ ----------- -------------- ------------------
63/// localTime bdlt::Time '24:00:00.000' none
64/// offset int 0 ( -1440 .. 1440 )
65/// @endcode
66/// * `localTime`: local time in the timezone described by `offset`.
67/// * `offset`: offset from UTC (in minutes) of the time zone in which
68/// `localTime` occurs.
69///
70/// ## Caveats on Time Zone Support {#bdlt_timetz-caveats-on-time-zone-support}
71///
72///
73/// A `bdlt::TimeTz` value is intended to be interpreted as a value in a local
74/// time zone, along with the offset of that value from UTC. However, there are
75/// some problems with this simple interpretation. First of all, the offset
76/// value may not correspond to any time zone that has ever existed. For
77/// example, the offset value could be set to one minute, or to 1,234 minutes.
78/// The meaning of the resulting "local time" value is always clear, but the
79/// local time might not correspond to any geographical or historical time zone.
80///
81/// For these reasons (and others), this component cannot and does not perform
82/// any validation relating to time zones or offsets. The user must take care
83/// to honor the "local time" contract of this component.
84///
85/// ## ISO Standard Text Representation {#bdlt_timetz-iso-standard-text-representation}
86///
87///
88/// A common standard text representation of a date and time value is described
89/// by ISO 8601. BDE provides the @ref bdlt_iso8601util component for conversion
90/// to and from the standard ISO8601 format.
91///
92/// ## Usage {#bdlt_timetz-usage}
93///
94///
95/// This section illustrates intended use of this component.
96///
97/// ### Example 1: Comparing Times from Multiple Time Zones {#bdlt_timetz-example-1-comparing-times-from-multiple-time-zones}
98///
99///
100/// Some legacy systems may represent points in time as a combination of a local
101/// time-of-day plus an offset from UTC, with an underlying assumption that the
102/// dates on which points in time occur can be inferred from context. Assuming
103/// that we know that two such times fall on the same (local) calendar date, we
104/// can determine whether or not the two times coincide by comparing their
105/// `bdlt::TimeTz` representations.
106///
107/// First, we define three `bdlt::TimeTz` objects representing the time in three
108/// different time zones on the same (local) date:
109/// @code
110/// bdlt::TimeTz newYorkTime(bdlt::Time(9, 30, 0, 0.0),
111/// -5 * bdlt::TimeUnitRatio::k_MINUTES_PER_HOUR);
112/// bdlt::TimeTz chicagoTime(bdlt::Time(8, 30, 0, 0.0),
113/// -6 * bdlt::TimeUnitRatio::k_MINUTES_PER_HOUR);
114/// bdlt::TimeTz phoenixTime(bdlt::Time(6, 30, 0, 0.0),
115/// -7 * bdlt::TimeUnitRatio::k_MINUTES_PER_HOUR);
116/// @endcode
117/// Then, we observe that the local times are distinct:
118/// @code
119/// assert(newYorkTime.localTime() != chicagoTime.localTime());
120/// assert(chicagoTime.localTime() != phoenixTime.localTime());
121/// assert(phoenixTime.localTime() != newYorkTime.localTime());
122/// @endcode
123/// Next, we observe that `newYorkTime` and `chicagoTime` actually represent the
124/// same point in time:
125/// @code
126/// assert(newYorkTime.utcTime() == chicagoTime.utcTime());
127/// @endcode
128/// Finally, we observe that `phoenixTime` is one hour earlier than
129/// `newYorkTime`:
130/// @code
131/// bdlt::DatetimeInterval delta =
132/// newYorkTime.utcTime() - phoenixTime.utcTime();
133///
134/// assert(0 == delta.days());
135/// assert(1 == delta.hours());
136/// assert(0 == delta.minutes());
137/// assert(0 == delta.seconds());
138/// assert(0 == delta.milliseconds());
139/// @endcode
140/// @}
141/** @} */
142/** @} */
143
144/** @addtogroup bdl
145 * @{
146 */
147/** @addtogroup bdlt
148 * @{
149 */
150/** @addtogroup bdlt_timetz
151 * @{
152 */
153
154#include <bdlscm_version.h>
155
156#include <bdlt_time.h>
157
158#include <bslh_hash.h>
159
162
163#include <bsls_annotation.h>
164#include <bsls_assert.h>
165#include <bsls_review.h>
166
167#include <bsl_iosfwd.h>
168
169
170
171namespace bdlt {
172
173 // ============
174 // class TimeTz
175 // ============
176
177/// This value-semantic class describes a time value in a particular time
178/// zone, which is indicated using an offset from UTC (in minutes). The
179/// offset is available via the `offset` method, and is defined by the
180/// relationship: `localTime() - offset() == utcTime`. The time and offset
181/// values are logically assumed to correspond to geographically valid
182/// values, however, this constraint is not enforced.
183///
184/// This class:
185/// * supports a complete set of *value-semantic* operations
186/// * supports BDEX streaming
187/// For terminology see @ref bsldoc_glossary .
188///
189/// See @ref bdlt_timetz
190class TimeTz {
191
192 // PRIVATE TYPES
193
194 /// This enumeration specifies the minimum and maximum time zone offset
195 /// values.
196 enum ValidOffsetRange {
197
198 k_MAX_OFFSET = 1440,
199 k_MIN_OFFSET = -1440
200 };
201
202 // DATA
203 Time d_localTime; // time value in timezone specified by 'd_offset'
204 int d_offset; // offset from UTC (in minutes)
205
206 public:
207 // CLASS METHODS
208
209 /// Return `true` if the specified `localTime` and the specified time
210 /// zone `offset` represent a valid `TimeTz` value, and `false`
211 /// otherwise. A `localTime` and `offset` represent a valid `TimeTz`
212 /// value if `offset` is in the range `( -1440 .. 1440 )`, and `offset`
213 /// is 0 if `localTime` has the value `24:00:00.000`. Note that a
214 /// `true` result from this function does not guarantee that `offset`
215 /// corresponds to any geographical or historical time zone. Also note
216 /// that a `true` result from this function does not guarantee that
217 /// `localTime` itself is a valid `Time` object.
218 static bool isValid(const Time& localTime, int offset);
219
220 // BDEX Streaming
221
222 /// Return the maximum valid BDEX format version, as indicated by the
223 /// specified `versionSelector`, to be passed to the `bdexStreamOut`
224 /// method. Note that it is highly recommended that `versionSelector`
225 /// be formatted as "YYYYMMDD", a date representation. Also note that
226 /// `versionSelector` should be a *compile*-time-chosen value that
227 /// selects a format version supported by both externalizer and
228 /// unexternalizer. See the `bslx` package-level documentation for more
229 /// information on BDEX streaming of value-semantic types and
230 /// containers.
231 static int maxSupportedBdexVersion(int versionSelector);
232
233 // CREATORS
234
235 /// Create a `TimeTz` object having the (default) attribute values.
236 TimeTz();
237
238 /// Create a `TimeTz` object whose local time and offset attributes have
239 /// the specified `localTime` and `offset` values respectively. The
240 /// behavior is undefined unless `offset` is in the range
241 /// `( -1440 .. 1440 )`, and `offset` is 0 if `localTime` has the value
242 /// `24:00:00.000`. Note that this method provides no validation, and
243 /// it is the user's responsibility to ensure that `offset` represents a
244 /// valid time zone and that `localTime` represents a valid time in that
245 /// time zone.
246 TimeTz(const Time& localTime, int offset);
247
248 /// Construct a `TimeTz` object having the same value as the specified
249 /// `original` `TimeTz` object.
250 TimeTz(const TimeTz& original);
251
252 /// Destroy this object.
253 ~TimeTz();
254
255 // MANIPULATORS
256
257 /// Assign to this object the value of the specified `rhs` object, and
258 /// return a reference providing modifiable access to this object.
259 TimeTz& operator=(const TimeTz& rhs);
260
261 /// Set the local time and time zone offset attributes of this object to
262 /// the specified `localTime` and `offset` values respectively. The
263 /// behavior is undefined unless `offset` is in the range
264 /// `( -1440 .. 1440 )`. Note that this method provides no validation,
265 /// and it is the user's responsibility to assure the consistency of the
266 /// resulting value.
267 void setTimeTz(const Time& localTime, int offset);
268
269 /// Set the local time and the time zone offset of this object to the
270 /// specified `localTime` and `offset` values respectively if
271 /// `localTime` and `offset` represent a valid `TimeTz` value, and leave
272 /// the object unmodified otherwise. Return 0 on success, and a
273 /// non-zero value otherwise.
274 int setTimeTzIfValid(const Time& localTime, int offset);
275
276 // Aspects
277
278 /// Assign to this object the value read from the specified input
279 /// `stream` using the specified `version` format, and return a
280 /// reference to `stream`. If `stream` is initially invalid, this
281 /// operation has no effect. If `version` is not supported, this object
282 /// is unaltered and `stream` is invalidated, but otherwise unmodified.
283 /// If `version` is supported but `stream` becomes invalid during this
284 /// operation, this object has an undefined, but valid, state. Note
285 /// that no version is read from `stream`. See the `bslx` package-level
286 /// documentation for more information on BDEX streaming of
287 /// value-semantic types and containers.
288 template <class STREAM>
289 STREAM& bdexStreamIn(STREAM& stream, int version);
290
291 // ACCESSORS
292
293 /// Return a `Time` object having the value of the local time attribute
294 /// of this object. Note that the `Time` value returned is the value
295 /// stored in this object, and may be different from the local time of
296 /// the system.
297 Time localTime() const;
298
299 /// Return the time zone offset of this object in minutes from UTC.
300 int offset() const;
301
302 /// Return a `Time` object having the value of the UTC time represented
303 /// by this object. Note that the returned value is equal to
304 /// `localTime() - offset()` minutes.
305 Time utcTime() const;
306
307 // Aspects
308
309 /// Write the value of this object, using the specified `version`
310 /// format, to the specified output `stream`, and return a reference to
311 /// `stream`. If `stream` is initially invalid, this operation has no
312 /// effect. If `version` is not supported, `stream` is invalidated, but
313 /// otherwise unmodified. Note that `version` is not written to
314 /// `stream`. See the `bslx` package-level documentation for more
315 /// information on BDEX streaming of value-semantic types and
316 /// containers.
317 template <class STREAM>
318 STREAM& bdexStreamOut(STREAM& stream, int version) const;
319
320 /// Write the value of this object to the specified output `stream` in a
321 /// human-readable format, and return a reference to `stream`.
322 /// Optionally specify an initial indentation `level`, whose absolute
323 /// value is incremented recursively for nested objects. If `level` is
324 /// specified, optionally specify `spacesPerLevel`, whose absolute value
325 /// indicates the number of spaces per indentation level for this and
326 /// all of its nested objects. If `level` is negative, suppress
327 /// indentation of the first line. If `spacesPerLevel` is negative,
328 /// format the entire output on one line, suppressing all but the
329 /// initial indentation (as governed by `level`). If `stream` is not
330 /// valid on entry, this operation has no effect. Note that the format
331 /// is not fully specified, and can change without notice.
332 bsl::ostream& print(bsl::ostream& stream,
333 int level = 0,
334 int spacesPerLevel = 4) const;
335
336#ifndef BDE_OPENSOURCE_PUBLICATION // pending deprecation
337
338 // DEPRECATED
339
340 /// @deprecated replaced by `utcTime`.
341 ///
342 /// Return a `Time` object having the value of the UTC time represented
343 /// by this object. Note that the returned value is equal to
344 /// `localTime() - offset()` minutes.
345 Time gmtTime() const;
346
347 /// @deprecated Use @ref maxSupportedBdexVersion(int) instead.
348 ///
349 /// Return the most current BDEX streaming version number supported by
350 /// this class.
351 static int maxSupportedBdexVersion();
352
353 /// @deprecated replaced by `setTimeTzIfValid`.
354 ///
355 /// Set the local time and the time zone offset of this object to the
356 /// specified `localTime` and `offset` values respectively if
357 /// `localTime` and `offset` represent a valid `TimeTz` value. Return 0
358 /// on success, and a non-zero value with no effect on this object
359 /// otherwise.
360 int validateAndSetTimeTz(const Time& localTime, int offset);
361
362#endif // BDE_OPENSOURCE_PUBLICATION -- pending deprecation
363};
364
365// FREE OPERATORS
366
367/// Return `true` if the specified `lhs` and `rhs` objects have the same
368/// value, and `false` otherwise. Two `TimeTz` objects have the same value
369/// if their corresponding `localTime` and `offset` attributes have the same
370/// values.
371bool operator==(const TimeTz& lhs, const TimeTz& rhs);
372
373/// Return `true` if the specified `lhs` and `rhs` objects do not have the
374/// same value, and `false` otherwise. Two `TimeTz` objects do not have the
375/// same value if any of their corresponding `localTime` and `offset`
376/// attributes have different values.
377bool operator!=(const TimeTz& lhs, const TimeTz& rhs);
378
379/// Write the value of the specified `object` to the specified output
380/// `stream` in a single-line format, and return a reference providing
381/// modifiable access to `stream`. If `stream` is not valid on entry, this
382/// operation has no effect. Note that this human-readable format is not
383/// fully specified and can change without notice. Also note that this
384/// method has the same behavior as `object.print(stream, 0, -1)`, but with
385/// the attribute names elided.
386bsl::ostream& operator<<(bsl::ostream& stream, const TimeTz& object);
387
388// FREE FUNCTIONS
389
390/// Pass the specified `object` to the specified `hashAlg`. This function
391/// integrates with the `bslh` modular hashing system and effectively
392/// provides a `bsl::hash` specialization for `TimeTz`. Note that two
393/// objects which represent the same UTC time but have different offsets
394/// will not (necessarily) hash to the same value.
395template <class HASHALG>
396void hashAppend(HASHALG& hashAlg, const TimeTz& object);
397
398// ============================================================================
399// INLINE DEFINITIONS
400// ============================================================================
401
402 // ------------
403 // class TimeTz
404 // ------------
405
406// CLASS METHODS
407inline
408bool TimeTz::isValid(const Time& localTime, int offset)
409{
410 return offset > k_MIN_OFFSET
411 && offset < k_MAX_OFFSET
412 && (bdlt::Time() != localTime || 0 == offset);
413}
414
415 // Aspects
416
417inline
418int TimeTz::maxSupportedBdexVersion(int versionSelector)
419{
420 if (versionSelector >= 20170401) {
421 return 2; // RETURN
422 }
423 return 1;
424}
425
426// CREATORS
427inline
429: d_localTime()
430, d_offset(0)
431{
432}
433
434inline
435TimeTz::TimeTz(const Time& localTime, int offset)
436: d_localTime(localTime)
437, d_offset(offset)
438{
440}
441
442inline
443TimeTz::TimeTz(const TimeTz& original)
444: d_localTime(original.d_localTime)
445, d_offset(original.d_offset)
446{
447}
448
449inline
451{
452 BSLS_REVIEW(isValid(d_localTime, d_offset));
453}
454
455// MANIPULATORS
456inline
458{
459 d_localTime = rhs.d_localTime;
460 d_offset = rhs.d_offset;
461
462 return *this;
463}
464
465inline
466void TimeTz::setTimeTz(const Time& localTime, int offset)
467{
469
470 d_localTime = localTime;
471 d_offset = offset;
472}
473
474inline
475int TimeTz::setTimeTzIfValid(const Time& localTime, int offset)
476{
477 if (isValid(localTime, offset)) {
479
480 return 0; // RETURN
481 }
482 return -1;
483}
484
485 // Aspects
486
487template <class STREAM>
488STREAM& TimeTz::bdexStreamIn(STREAM& stream, int version)
489{
490 if (stream) {
491 switch (version) { // switch on the schema version
492 case 2:
494 case 1: {
495 Time time;
496 time.bdexStreamIn(stream, version);
497
498 int offset;
499 stream.getInt32(offset);
500
501 if (stream && isValid(time, offset)) {
502 setTimeTz(time, offset);
503 }
504 else {
505 stream.invalidate();
506 }
507 } break;
508 default: {
509 stream.invalidate(); // unrecognized version number
510 }
511 }
512 }
513 return stream;
514}
515
516// ACCESSORS
517inline
519{
520 return d_localTime;
521}
522
523inline
524int TimeTz::offset() const
525{
526 return d_offset;
527}
528
529inline
531{
532 Time utc(d_localTime);
533
534 if (d_offset) {
535 // N.B. adding -0 minutes to a default-constructed 'Time' object (with
536 // value '24:00:00.000') would convert it to a 'Time' object with value
537 // '00:00:00.000'. The branch here preserves the 'localTime' attribute
538 // for a default-constructed 'TimeTz' object.
539
540 utc.addMinutes(-d_offset);
541 }
542
543 return utc;
544}
545
546 // Aspects
547
548template <class STREAM>
549STREAM& TimeTz::bdexStreamOut(STREAM& stream, int version) const
550{
551 if (stream) {
552 switch (version) { // switch on the schema version
553 case 2:
555 case 1: {
556 d_localTime.bdexStreamOut(stream, version);
557 stream.putInt32(d_offset);
558 } break;
559 default: {
560 stream.invalidate(); // unrecognized version number
561 }
562 }
563 }
564 return stream;
565}
566
567#ifndef BDE_OPENSOURCE_PUBLICATION // pending deprecation
568// DEPRECATED
569inline
571{
572 return utcTime();
573}
574
575inline
580
581inline
582int TimeTz::validateAndSetTimeTz(const Time& localTime, int offset)
583{
585}
586#endif // BDE_OPENSOURCE_PUBLICATION -- pending deprecation
587
588} // close package namespace
589
590// FREE OPERATORS
591inline
592bool bdlt::operator==(const TimeTz& lhs, const TimeTz& rhs)
593{
594 return lhs.localTime() == rhs.localTime()
595 && lhs.offset() == rhs.offset();
596}
597
598inline
599bool bdlt::operator!=(const TimeTz& lhs, const TimeTz& rhs)
600{
601 return lhs.localTime() != rhs.localTime()
602 || lhs.offset() != rhs.offset();
603}
604
605inline
606bsl::ostream& bdlt::operator<<(bsl::ostream& stream, const TimeTz& object)
607{
608 return object.print(stream, 0, -1);
609}
610
611// FREE FUNCTIONS
612template <class HASHALG>
613inline
614void bdlt::hashAppend(HASHALG& hashAlg, const TimeTz& object)
615{
616 using ::BloombergLP::bslh::hashAppend;
617 hashAppend(hashAlg, object.localTime());
618 hashAppend(hashAlg, object.offset());
619}
620
621namespace bslmf {
622
623// TRAITS
624
625/// This template specialization for `IsBitwiseCopyable` indicates that
626/// `bdlt::TimeTz` is a bitwise copyable type.
627template <>
628struct IsBitwiseCopyable<BloombergLP::bdlt::TimeTz> : bsl::true_type {
629};
630
631} // close namespace bslmf
632
633
634#endif
635
636// ----------------------------------------------------------------------------
637// Copyright 2014 Bloomberg Finance L.P.
638//
639// Licensed under the Apache License, Version 2.0 (the "License");
640// you may not use this file except in compliance with the License.
641// You may obtain a copy of the License at
642//
643// http://www.apache.org/licenses/LICENSE-2.0
644//
645// Unless required by applicable law or agreed to in writing, software
646// distributed under the License is distributed on an "AS IS" BASIS,
647// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
648// See the License for the specific language governing permissions and
649// limitations under the License.
650// ----------------------------- END-OF-FILE ----------------------------------
651
652/** @} */
653/** @} */
654/** @} */
Definition bdlt_timetz.h:190
Time localTime() const
Definition bdlt_timetz.h:518
void setTimeTz(const Time &localTime, int offset)
Definition bdlt_timetz.h:466
STREAM & bdexStreamOut(STREAM &stream, int version) const
Definition bdlt_timetz.h:549
bsl::ostream & print(bsl::ostream &stream, int level=0, int spacesPerLevel=4) const
TimeTz()
Create a TimeTz object having the (default) attribute values.
Definition bdlt_timetz.h:428
Time gmtTime() const
Definition bdlt_timetz.h:570
TimeTz & operator=(const TimeTz &rhs)
Definition bdlt_timetz.h:457
int validateAndSetTimeTz(const Time &localTime, int offset)
Definition bdlt_timetz.h:582
~TimeTz()
Destroy this object.
Definition bdlt_timetz.h:450
static bool isValid(const Time &localTime, int offset)
Definition bdlt_timetz.h:408
Time utcTime() const
Definition bdlt_timetz.h:530
static int maxSupportedBdexVersion()
Definition bdlt_timetz.h:576
int offset() const
Return the time zone offset of this object in minutes from UTC.
Definition bdlt_timetz.h:524
int setTimeTzIfValid(const Time &localTime, int offset)
Definition bdlt_timetz.h:475
STREAM & bdexStreamIn(STREAM &stream, int version)
Definition bdlt_timetz.h:488
Definition bdlt_time.h:196
STREAM & bdexStreamIn(STREAM &stream, int version)
Definition bdlt_time.h:858
int addMinutes(int minutes)
STREAM & bdexStreamOut(STREAM &stream, int version) const
Definition bdlt_time.h:938
#define BSLS_ANNOTATION_FALLTHROUGH
Definition bsls_annotation.h:412
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_REVIEW(X)
Definition bsls_review.h:949
void hashAppend(HASH_ALGORITHM &hashAlg, const baljsn::EncoderTestAddress &object)
Definition baljsn_encoder_testtypes.h:9236
Definition bbldc_basicisma30360.h:112
bool operator==(const Calendar &lhs, const Calendar &rhs)
bsl::ostream & operator<<(bsl::ostream &stream, const Calendar &calendar)
void hashAppend(HASHALG &hashAlg, const Calendar &object)
bool operator!=(const Calendar &lhs, const Calendar &rhs)
Definition bdlbb_blob.h:576