AceTime  2.2.0
Date and time classes for Arduino that support timezones from the TZ Database.
TimeZone.h
1 /*
2  * MIT License
3  * Copyright (c) 2018 Brian T. Park
4  */
5 
6 #ifndef ACE_TIME_TIME_ZONE_H
7 #define ACE_TIME_TIME_ZONE_H
8 
9 #include <stdint.h> // uintptr_t
10 #include "TimeOffset.h"
11 #include "ZoneProcessor.h"
12 #include "BasicZoneProcessor.h"
13 #include "ExtendedZoneProcessor.h"
14 #include "TimeZoneData.h"
15 #include "ZonedExtra.h"
16 
17 class Print;
18 
19 namespace ace_time {
20 
85 class TimeZone {
86  public:
88  static const uint8_t kTypeError = 0;
89 
91  static const uint8_t kTypeManual = 1;
92 
94  static const uint8_t kTypeReserved = 2;
95 
97  static TimeZone forUtc() {
98  return TimeZone();
99  }
100 
115  TimeOffset stdOffset,
116  TimeOffset dstOffset = TimeOffset()
117  ) {
118  return TimeZone(stdOffset, dstOffset);
119  }
120 
127  static TimeZone forHours(int8_t stdHours, int8_t dstHours = 0) {
129  TimeOffset::forHours(stdHours),
130  TimeOffset::forHours(dstHours)
131  );
132  }
133 
140  static TimeZone forMinutes(int16_t stdMinutes, int16_t dstMinutes = 0) {
142  TimeOffset::forMinutes(stdMinutes),
143  TimeOffset::forMinutes(dstMinutes)
144  );
145  }
146 
154  int8_t stdHour,
155  int8_t stdMinute,
156  int8_t dstHour = 0,
157  int8_t dstMinute = 0
158  ) {
160  TimeOffset::forHourMinute(stdHour, stdMinute),
161  TimeOffset::forHourMinute(dstHour, dstMinute)
162  );
163  }
164 
174  const basic::ZoneInfo* zoneInfo,
175  BasicZoneProcessor* zoneProcessor
176  ) {
177  return TimeZone(
178  zoneProcessor->getType(),
179  (uintptr_t) zoneInfo,
180  zoneProcessor
181  );
182  }
183 
193  const extended::ZoneInfo* zoneInfo,
194  ExtendedZoneProcessor* zoneProcessor
195  ) {
196  return TimeZone(
197  zoneProcessor->getType(),
198  (uintptr_t) zoneInfo,
199  zoneProcessor
200  );
201  }
202 
213  static TimeZone forZoneKey(uintptr_t zoneKey, ZoneProcessor* processor) {
214  return TimeZone(processor->getType(), zoneKey, processor);
215  }
216 
221  static TimeZone forError() {
222  return TimeZone(kTypeError);
223  }
224 
227  mType(kTypeManual),
228  mStdOffsetMinutes(0),
229  mDstOffsetMinutes(0) {}
230 
238  uint8_t getType() const { return mType; }
239 
246  switch (mType) {
247  case kTypeError:
248  case kTypeReserved:
249  case kTypeManual:
250  break;
251 
252  default:
253  return getBoundZoneProcessor()->resetTransitionCache();
254  }
255  }
256 
259  return TimeOffset::forMinutes(mStdOffsetMinutes);
260  }
261 
264  return TimeOffset::forMinutes(mDstOffsetMinutes);
265  }
266 
268  bool isLink() const {
269  switch (mType) {
270  case kTypeError:
271  case kTypeReserved:
272  case kTypeManual:
273  return false;
274 
275  default:
276  return getBoundZoneProcessor()->isLink();
277  }
278  }
279 
285  uint32_t getZoneId() const {
286  switch (mType) {
287  case kTypeError:
288  case kTypeReserved:
289  case kTypeManual:
290  return 0;
291 
292  default:
293  return getBoundZoneProcessor()->getZoneId();
294  }
295  }
296 
298  bool isError() const { return mType == kTypeError; }
299 
302  switch (mType) {
303  case kTypeError:
304  case kTypeReserved:
305  return ZonedExtra::forError();
306 
307  case kTypeManual:
308  const char* abbrev;
309  if (isUtc()) {
310  abbrev = "UTC";
311  } else {
312  abbrev = (mDstOffsetMinutes != 0) ? "DST" : "STD";
313  }
314  return ZonedExtra(
316  mStdOffsetMinutes,
317  mDstOffsetMinutes,
318  mStdOffsetMinutes,
319  mDstOffsetMinutes,
320  abbrev);
321 
322  default: {
323  FindResult result = getBoundZoneProcessor()->findByLocalDateTime(ldt);
324  if (result.type == FindResult::kTypeNotFound) {
325  return ZonedExtra::forError();
326  }
327  return ZonedExtra(
328  result.type, // ZonedExtra::type is identical to FindResult::type
329  result.stdOffsetMinutes,
330  result.dstOffsetMinutes,
331  result.reqStdOffsetMinutes,
332  result.reqDstOffsetMinutes,
333  result.abbrev);
334  }
335  }
336  }
337 
339  ZonedExtra getZonedExtra(acetime_t epochSeconds) const {
340  switch (mType) {
341  case kTypeError:
342  case kTypeReserved:
343  return ZonedExtra::forError();
344 
345  case kTypeManual:
346  const char* abbrev;
347  if (isUtc()) {
348  abbrev = "UTC";
349  } else {
350  abbrev = (mDstOffsetMinutes != 0) ? "DST" : "STD";
351  }
352  return ZonedExtra(
354  mStdOffsetMinutes,
355  mDstOffsetMinutes,
356  mStdOffsetMinutes,
357  mDstOffsetMinutes,
358  abbrev);
359 
360  default: {
361  FindResult result =
362  getBoundZoneProcessor()->findByEpochSeconds(epochSeconds);
363  if (result.type == FindResult::kTypeNotFound) {
364  return ZonedExtra::forError();
365  }
366  return ZonedExtra(
367  result.type, // ZonedExtra::type is identical to FindResult::type
368  result.stdOffsetMinutes,
369  result.dstOffsetMinutes,
370  result.reqStdOffsetMinutes,
371  result.reqDstOffsetMinutes,
372  result.abbrev);
373  }
374  }
375  }
376 
385  switch (mType) {
386  case kTypeError:
387  case kTypeReserved:
388  break;
389 
390  case kTypeManual:
392  ldt,
393  TimeOffset::forMinutes(mStdOffsetMinutes + mDstOffsetMinutes));
394  break;
395 
396  default: {
397  FindResult result = getBoundZoneProcessor()->findByLocalDateTime(ldt);
398  if (result.type == FindResult::kTypeNotFound) {
399  break;
400  }
401 
402  // Convert FindResult into OffsetDateTime using the requested offset.
404  result.reqStdOffsetMinutes + result.reqDstOffsetMinutes);
405  odt = OffsetDateTime::forLocalDateTimeAndOffset(ldt, reqOffset);
406  odt.fold(result.fold);
407 
408  // Special processing for kTypeGap: Convert to epochSeconds using the
409  // reqStdOffsetMinutes and reqDstOffsetMinutes, then convert back to
410  // OffsetDateTime using the target stdOffsetMinutes and
411  // dstOffsetMinutes.
412  if (result.type == FindResult::kTypeGap) {
413  acetime_t epochSeconds = odt.toEpochSeconds();
414  TimeOffset targetOffset = TimeOffset::forMinutes(
415  result.stdOffsetMinutes + result.dstOffsetMinutes);
416  odt = OffsetDateTime::forEpochSeconds(epochSeconds, targetOffset);
417  }
418  break;
419  }
420  }
421  return odt;
422  }
423 
431  switch (mType) {
432  case kTypeError:
433  case kTypeReserved:
434  break;
435 
436  case kTypeManual:
438  epochSeconds,
439  TimeOffset::forMinutes(mStdOffsetMinutes + mDstOffsetMinutes));
440  break;
441 
442  default: {
443  FindResult result =
444  getBoundZoneProcessor()->findByEpochSeconds(epochSeconds);
445  if (result.type == FindResult::kTypeNotFound) {
446  break;
447  }
448 
450  result.reqStdOffsetMinutes + result.reqDstOffsetMinutes);
452  epochSeconds, offset, result.fold);
453  break;
454  }
455  }
456  return odt;
457  }
458 
460  bool isUtc() const {
461  if (mType != kTypeManual) return false;
462  return mStdOffsetMinutes == 0 && mDstOffsetMinutes == 0;
463  }
464 
472  bool isDst() const {
473  if (mType != kTypeManual) return false;
474  return mDstOffsetMinutes != 0;
475  }
476 
484  TimeZoneData d;
485  switch (mType) {
486  case kTypeError:
487  case kTypeReserved:
488  d.type = TimeZoneData::kTypeError;
489  break;
490 
492  d.stdOffsetMinutes = mStdOffsetMinutes;
493  d.dstOffsetMinutes = mDstOffsetMinutes;
494  d.type = TimeZoneData::kTypeManual;
495  break;
496 
497  default:
498  d.zoneId = getZoneId();
499  d.type = TimeZoneData::kTypeZoneId;
500  break;
501  }
502  return d;
503  }
504 
514  void printTo(Print& printer) const;
515 
534  void printShortTo(Print& printer) const;
535 
540  void printTargetNameTo(Print& printer) const;
541 
542  // Use default copy constructor and assignment operator.
543  TimeZone(const TimeZone&) = default;
544  TimeZone& operator=(const TimeZone&) = default;
545 
546  private:
547  friend bool operator==(const TimeZone& a, const TimeZone& b);
548 
555  explicit TimeZone(TimeOffset stdOffset, TimeOffset dstOffset):
556  mType(kTypeManual),
557  mStdOffsetMinutes(stdOffset.toMinutes()),
558  mDstOffsetMinutes(dstOffset.toMinutes()) {}
559 
561  explicit TimeZone(uint8_t type):
562  mType(type) {}
563 
573  explicit TimeZone(
574  uint8_t type,
575  uintptr_t zoneKey,
576  ZoneProcessor* zoneProcessor
577  ):
578  mType(type),
579  mZoneKey(zoneKey),
580  mZoneProcessor(zoneProcessor)
581  {}
582 
590  ZoneProcessor* getBoundZoneProcessor() const {
592  return mZoneProcessor;
593  }
594 
595  uint8_t mType;
596 
597  // 3 combinations:
598  // (kTypeError)
599  // (kTypeManual, mStdOffsetMinutes, mDstOffsetMinutes)
600  // (type, mZoneKey, mZoneProcessor)
601  union {
603  struct {
604  int16_t mStdOffsetMinutes;
605  int16_t mDstOffsetMinutes;
606  };
607 
608  /* Used by kTypeBasic and kTypeExtended. */
609  struct {
620  uintptr_t mZoneKey;
621 
627  };
628  };
629 };
630 
631 inline bool operator==(const TimeZone& a, const TimeZone& b) {
632  if (a.mType != b.mType) return false;
633  switch (a.mType) {
636  return true;
637 
639  return a.mStdOffsetMinutes == b.mStdOffsetMinutes
640  && a.mDstOffsetMinutes == b.mDstOffsetMinutes;
641 
642  default:
643  return (a.mZoneKey == b.mZoneKey);
644  }
645 }
646 
647 inline bool operator!=(const TimeZone& a, const TimeZone& b) {
648  return ! (a == b);
649 }
650 
651 }
652 
653 #endif
A specific implementation of BasicZoneProcessorTemplate that uses ZoneXxxBrokers which read from zone...
A specific implementation of ExtendedZoneProcessorTemplate that uses ZoneXxxBrokers which read from z...
Result of a search for transition at a specific epochSeconds or a specific LocalDateTime.
Definition: ZoneProcessor.h:24
uint8_t fold
For findByLocalDateTime(), when type==kTypeOverlap, this is a copy of the requested LocalDateTime::fo...
Definition: ZoneProcessor.h:77
int16_t dstOffsetMinutes
DST offset of the resulting OffsetDateTime.
Definition: ZoneProcessor.h:83
int16_t reqStdOffsetMinutes
STD offset of the Transition which matched the epochSeconds requested by findByEpochSeconds(),...
Definition: ZoneProcessor.h:96
int16_t stdOffsetMinutes
STD offset of the resulting OffsetDateTime.
Definition: ZoneProcessor.h:80
int16_t reqDstOffsetMinutes
DST offset of the Transition which matched the epochSeconds requested by findByEpochSeconds(),...
const char * abbrev
Pointer to the abbreviation stored in the transient Transition::abbrev variable.
uint8_t type
Result of the findByEpochSeconds() or findByLocalDateTime() search methods.
Definition: ZoneProcessor.h:66
Class that holds the date-time as the components (year, month, day, hour, minute, second) without reg...
Definition: LocalDateTime.h:31
The date (year, month, day), time (hour, minute, second) and fixed offset from UTC (timeOffset).
static OffsetDateTime forLocalDateTimeAndOffset(const LocalDateTime &localDateTime, TimeOffset timeOffset)
Factory method from LocalDateTime and TimeOffset.
acetime_t toEpochSeconds() const
Return seconds since AceTime epoch taking into account the UTC offset.
static OffsetDateTime forError()
Factory method that returns an instance whose isError() is true.
uint8_t fold() const
Return the fold.
static OffsetDateTime forEpochSeconds(acetime_t epochSeconds, TimeOffset timeOffset, uint8_t fold=0)
Factory method.
A thin wrapper that represents a time offset from a reference point, usually 00:00 at UTC,...
Definition: TimeOffset.h:56
static TimeOffset forHours(int8_t hours)
Create TimeOffset with the corresponding hour offset.
Definition: TimeOffset.h:65
static TimeOffset forHourMinute(int8_t hour, int8_t minute)
Create TimeOffset from (hour, minute) offset.
Definition: TimeOffset.h:77
static TimeOffset forMinutes(int16_t minutes)
Create TimeOffset from minutes from 00:00.
Definition: TimeOffset.h:83
Class that describes a time zone.
Definition: TimeZone.h:85
ZonedExtra getZonedExtra(acetime_t epochSeconds) const
Return the ZonedExtra information at epochSeconds.
Definition: TimeZone.h:339
static TimeZone forZoneInfo(const extended::ZoneInfo *zoneInfo, ExtendedZoneProcessor *zoneProcessor)
Convenience factory method to create from a zoneInfo and an associated ExtendedZoneProcessor.
Definition: TimeZone.h:192
void printTo(Print &printer) const
Print the text representation of the time zone using the full canonical time zone name or UTC offset ...
Definition: TimeZone.cpp:11
uint32_t getZoneId() const
Return the zoneId for kTypeBasic, kTypeExtended.
Definition: TimeZone.h:285
ZoneProcessor * mZoneProcessor
An instance of a ZoneProcessor, for example, BasicZoneProcessor or ExtendedZoneProcessor.
Definition: TimeZone.h:626
void printTargetNameTo(Print &printer) const
Print the name of the target zone if the current time zone is a Link.
Definition: TimeZone.cpp:59
OffsetDateTime getOffsetDateTime(const LocalDateTime &ldt) const
Return the best estimate of the OffsetDateTime at the given LocalDateTime for the current TimeZone.
Definition: TimeZone.h:383
OffsetDateTime getOffsetDateTime(acetime_t epochSeconds) const
Return the best estimate of the OffsetDateTime at the given epochSeconds.
Definition: TimeZone.h:429
bool isUtc() const
Return true if UTC (+00:00+00:00).
Definition: TimeZone.h:460
static TimeZone forUtc()
Factory method to create a UTC TimeZone.
Definition: TimeZone.h:97
static TimeZone forHours(int8_t stdHours, int8_t dstHours=0)
Factory method to create from UTC hour offset and optional DST hour offset.
Definition: TimeZone.h:127
void resetZoneProcessor()
Reset the underlying ZoneProcessor if a ZoneProcessor is used.
Definition: TimeZone.h:245
uint8_t getType() const
Return the type of TimeZone, used to determine the behavior of certain methods at runtime.
Definition: TimeZone.h:238
bool isLink() const
Return true if timezone is a Link entry pointing to a Zone entry.
Definition: TimeZone.h:268
uintptr_t mZoneKey
An opaque zone key.
Definition: TimeZone.h:620
static TimeZone forMinutes(int16_t stdMinutes, int16_t dstMinutes=0)
Factory method to create from UTC minute offset and optional DST minute offset.
Definition: TimeZone.h:140
void printShortTo(Print &printer) const
Print the short human readable representation of the time zone.
Definition: TimeZone.cpp:33
static const uint8_t kTypeError
A TimeZone that represents an invalid condition.
Definition: TimeZone.h:88
static TimeZone forError()
Return a TimeZone representing an error condition.
Definition: TimeZone.h:221
static TimeZone forZoneKey(uintptr_t zoneKey, ZoneProcessor *processor)
Factory method to create from a generic zoneKey and a generic zoneProcessor.
Definition: TimeZone.h:213
TimeOffset getDstOffset() const
Return the DST TimeOffset.
Definition: TimeZone.h:263
bool isError() const
Return true if TimeZone is an error.
Definition: TimeZone.h:298
static TimeZone forZoneInfo(const basic::ZoneInfo *zoneInfo, BasicZoneProcessor *zoneProcessor)
Convenience factory method to create from a zoneInfo and an associated BasicZoneProcessor.
Definition: TimeZone.h:173
bool isDst() const
Return if mDstOffsetMinutes is not zero.
Definition: TimeZone.h:472
static TimeZone forTimeOffset(TimeOffset stdOffset, TimeOffset dstOffset=TimeOffset())
Factory method to create from a UTC offset and an optional DST offset.
Definition: TimeZone.h:114
static const uint8_t kTypeReserved
Reserved for future use.
Definition: TimeZone.h:94
ZonedExtra getZonedExtra(const LocalDateTime &ldt) const
Return the ZonedExtra information at epochSeconds.
Definition: TimeZone.h:301
static TimeZone forHourMinute(int8_t stdHour, int8_t stdMinute, int8_t dstHour=0, int8_t dstMinute=0)
Factory method to create from UTC (hour, minute) pair and optional DST (hour, minute) pair.
Definition: TimeZone.h:153
TimeZoneData toTimeZoneData() const
Convert to a TimeZoneData object, which can be fed back into ZoneManager::createForTimeZoneData() to ...
Definition: TimeZone.h:483
TimeOffset getStdOffset() const
Return the Standard TimeOffset.
Definition: TimeZone.h:258
static const uint8_t kTypeManual
Manual STD offset and DST offset.
Definition: TimeZone.h:91
TimeZone()
Default constructor creates a UTC TimeZone.
Definition: TimeZone.h:226
Base interface for ZoneProcessor classes.
uint8_t getType() const
Return the kTypeXxx of the current instance.
virtual FindResult findByEpochSeconds(acetime_t epochSeconds) const =0
Return the search results at given epochSeconds.
virtual uint32_t getZoneId() const =0
Return the unique stable zoneId.
virtual FindResult findByLocalDateTime(const LocalDateTime &ldt) const =0
Return the search results at given LocalDateTime.
virtual bool isLink() const =0
Return true if timezone is a Link entry pointing to a Zone entry.
void resetTransitionCache()
Reset the internal transition cache.
virtual void setZoneKey(uintptr_t zoneKey)=0
Set the opaque zoneKey of this object to a new value, reseting any internally cached information.
static ZonedExtra forError()
Return an instance that indicates an error.
Definition: ZonedExtra.h:54
static const uint8_t kTypeExact
The given LocalDateTime matches a single epochSeconds.
Definition: ZonedExtra.h:34
int32_t acetime_t
Type for the number of seconds from epoch.
Definition: common.h:24
Data structure that captures the internal state of a TimeZone object with enough information so that ...
Definition: TimeZoneData.h:38
uint32_t zoneId
Both TimeZone::kTypeBasic and TimeZone::kTypeExtended are mapped to a TimeZoneData::kTypeZoneId.
Definition: TimeZoneData.h:85