AceTime  3.0.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 "CompleteZoneProcessor.h"
15 #include "TimeZoneData.h"
16 #include "ZonedExtra.h"
17 
18 class Print;
19 
20 namespace ace_time {
21 
86 class TimeZone {
87  public:
89  static const uint8_t kTypeError = 0;
90 
92  static const uint8_t kTypeManual = 1;
93 
95  static const uint8_t kTypeReserved = 2;
96 
98  static TimeZone forUtc() {
99  return TimeZone();
100  }
101 
116  TimeOffset stdOffset,
117  TimeOffset dstOffset = TimeOffset()
118  ) {
119  return TimeZone(stdOffset, dstOffset);
120  }
121 
128  static TimeZone forHours(int8_t stdHours, int8_t dstHours = 0) {
130  TimeOffset::forHours(stdHours),
131  TimeOffset::forHours(dstHours)
132  );
133  }
134 
141  static TimeZone forMinutes(int16_t stdMinutes, int16_t dstMinutes = 0) {
143  TimeOffset::forMinutes(stdMinutes),
144  TimeOffset::forMinutes(dstMinutes)
145  );
146  }
147 
155  int8_t stdHour,
156  int8_t stdMinute,
157  int8_t dstHour = 0,
158  int8_t dstMinute = 0
159  ) {
161  TimeOffset::forHourMinute(stdHour, stdMinute),
162  TimeOffset::forHourMinute(dstHour, dstMinute)
163  );
164  }
165 
175  const basic::Info::ZoneInfo* zoneInfo,
176  BasicZoneProcessor* zoneProcessor
177  ) {
178  return TimeZone(
179  zoneProcessor->getType(),
180  (uintptr_t) zoneInfo,
181  zoneProcessor
182  );
183  }
184 
194  const extended::Info::ZoneInfo* zoneInfo,
195  ExtendedZoneProcessor* zoneProcessor
196  ) {
197  return TimeZone(
198  zoneProcessor->getType(),
199  (uintptr_t) zoneInfo,
200  zoneProcessor
201  );
202  }
203 
213  const complete::Info::ZoneInfo* zoneInfo,
214  CompleteZoneProcessor* zoneProcessor
215  ) {
216  return TimeZone(
217  zoneProcessor->getType(),
218  (uintptr_t) zoneInfo,
219  zoneProcessor
220  );
221  }
222 
233  static TimeZone forZoneKey(uintptr_t zoneKey, ZoneProcessor* processor) {
234  return TimeZone(processor->getType(), zoneKey, processor);
235  }
236 
241  static TimeZone forError() {
242  return TimeZone(kTypeError);
243  }
244 
247  mType(kTypeManual),
248  mStdOffsetMinutes(0),
249  mDstOffsetMinutes(0) {}
250 
258  uint8_t getType() const { return mType; }
259 
262  return TimeOffset::forMinutes(mStdOffsetMinutes);
263  }
264 
267  return TimeOffset::forMinutes(mDstOffsetMinutes);
268  }
269 
271  bool isLink() const {
272  switch (mType) {
273  case kTypeError:
274  case kTypeReserved:
275  case kTypeManual:
276  return false;
277 
278  default:
279  return getBoundZoneProcessor()->isLink();
280  }
281  }
282 
288  uint32_t getZoneId() const {
289  switch (mType) {
290  case kTypeError:
291  case kTypeReserved:
292  case kTypeManual:
293  return 0;
294 
295  default:
296  return getBoundZoneProcessor()->getZoneId();
297  }
298  }
299 
301  bool isError() const { return mType == kTypeError; }
302 
305  switch (mType) {
306  case kTypeError:
307  case kTypeReserved:
308  return ZonedExtra::forError();
309 
310  case kTypeManual:
311  const char* abbrev;
312  if (isUtc()) {
313  abbrev = "UTC";
314  } else {
315  abbrev = (mDstOffsetMinutes != 0) ? "DST" : "STD";
316  }
317  return ZonedExtra(
319  mStdOffsetMinutes * 60,
320  mDstOffsetMinutes * 60,
321  mStdOffsetMinutes * 60,
322  mDstOffsetMinutes * 60,
323  abbrev);
324 
325  default: {
326  FindResult result = getBoundZoneProcessor()->findByLocalDateTime(ldt);
327  if (result.type == FindResult::kTypeNotFound) {
328  return ZonedExtra::forError();
329  }
330  return ZonedExtra(
331  result.type, // ZonedExtra::type is identical to FindResult::type
332  result.stdOffsetSeconds,
333  result.dstOffsetSeconds,
334  result.reqStdOffsetSeconds,
335  result.reqDstOffsetSeconds,
336  result.abbrev);
337  }
338  }
339  }
340 
342  ZonedExtra getZonedExtra(acetime_t epochSeconds) const {
343  switch (mType) {
344  case kTypeError:
345  case kTypeReserved:
346  return ZonedExtra::forError();
347 
348  case kTypeManual:
349  const char* abbrev;
350  if (isUtc()) {
351  abbrev = "UTC";
352  } else {
353  abbrev = (mDstOffsetMinutes != 0) ? "DST" : "STD";
354  }
355  return ZonedExtra(
357  mStdOffsetMinutes * 60,
358  mDstOffsetMinutes * 60,
359  mStdOffsetMinutes * 60,
360  mDstOffsetMinutes * 60,
361  abbrev);
362 
363  default: {
364  FindResult result =
365  getBoundZoneProcessor()->findByEpochSeconds(epochSeconds);
366  if (result.type == FindResult::kTypeNotFound) {
367  return ZonedExtra::forError();
368  }
369  return ZonedExtra(
370  result.type, // ZonedExtra::type is identical to FindResult::type
371  result.stdOffsetSeconds,
372  result.dstOffsetSeconds,
373  result.reqStdOffsetSeconds,
374  result.reqDstOffsetSeconds,
375  result.abbrev);
376  }
377  }
378  }
379 
388  switch (mType) {
389  case kTypeError:
390  case kTypeReserved:
391  break;
392 
393  case kTypeManual:
395  ldt,
396  TimeOffset::forMinutes(mStdOffsetMinutes + mDstOffsetMinutes));
397  break;
398 
399  default: {
400  FindResult result = getBoundZoneProcessor()->findByLocalDateTime(ldt);
401  if (result.type == FindResult::kTypeNotFound) {
402  break;
403  }
404 
405  // Convert FindResult into OffsetDateTime using the requested offset.
407  result.reqStdOffsetSeconds + result.reqDstOffsetSeconds);
408  odt = OffsetDateTime::forLocalDateTimeAndOffset(ldt, reqOffset);
409  odt.fold(result.fold);
410 
411  // Special processing for kTypeGap: Convert to epochSeconds using the
412  // reqStdOffsetMinutes and reqDstOffsetMinutes, then convert back to
413  // OffsetDateTime using the target stdOffsetMinutes and
414  // dstOffsetMinutes.
415  if (result.type == FindResult::kTypeGap) {
416  acetime_t epochSeconds = odt.toEpochSeconds();
417  TimeOffset targetOffset = TimeOffset::forSeconds(
418  result.stdOffsetSeconds + result.dstOffsetSeconds);
419  odt = OffsetDateTime::forEpochSeconds(epochSeconds, targetOffset);
420  }
421  break;
422  }
423  }
424  return odt;
425  }
426 
434  switch (mType) {
435  case kTypeError:
436  case kTypeReserved:
437  break;
438 
439  case kTypeManual:
441  epochSeconds,
442  TimeOffset::forMinutes(mStdOffsetMinutes + mDstOffsetMinutes));
443  break;
444 
445  default: {
446  FindResult result =
447  getBoundZoneProcessor()->findByEpochSeconds(epochSeconds);
448  if (result.type == FindResult::kTypeNotFound) {
449  break;
450  }
451 
453  result.reqStdOffsetSeconds + result.reqDstOffsetSeconds);
455  epochSeconds, offset, result.fold);
456  break;
457  }
458  }
459  return odt;
460  }
461 
463  bool isUtc() const {
464  if (mType != kTypeManual) return false;
465  return mStdOffsetMinutes == 0 && mDstOffsetMinutes == 0;
466  }
467 
475  bool isDst() const {
476  if (mType != kTypeManual) return false;
477  return mDstOffsetMinutes != 0;
478  }
479 
487  TimeZoneData d;
488  switch (mType) {
489  case kTypeError:
490  case kTypeReserved:
491  d.type = TimeZoneData::kTypeError;
492  break;
493 
495  d.stdOffsetMinutes = mStdOffsetMinutes;
496  d.dstOffsetMinutes = mDstOffsetMinutes;
497  d.type = TimeZoneData::kTypeManual;
498  break;
499 
500  default:
501  d.zoneId = getZoneId();
502  d.type = TimeZoneData::kTypeZoneId;
503  break;
504  }
505  return d;
506  }
507 
517  void printTo(Print& printer) const;
518 
537  void printShortTo(Print& printer) const;
538 
543  void printTargetNameTo(Print& printer) const;
544 
545  // Use default copy constructor and assignment operator.
546  TimeZone(const TimeZone&) = default;
547  TimeZone& operator=(const TimeZone&) = default;
548 
549  private:
550  friend bool operator==(const TimeZone& a, const TimeZone& b);
551 
558  explicit TimeZone(TimeOffset stdOffset, TimeOffset dstOffset):
559  mType(kTypeManual),
560  mStdOffsetMinutes(stdOffset.toMinutes()),
561  mDstOffsetMinutes(dstOffset.toMinutes()) {}
562 
564  explicit TimeZone(uint8_t type):
565  mType(type) {}
566 
576  explicit TimeZone(
577  uint8_t type,
578  uintptr_t zoneKey,
579  ZoneProcessor* zoneProcessor
580  ):
581  mType(type),
582  mZoneKey(zoneKey),
583  mZoneProcessor(zoneProcessor)
584  {}
585 
593  ZoneProcessor* getBoundZoneProcessor() const {
595  return mZoneProcessor;
596  }
597 
598  private:
599  uint8_t mType;
600 
601  // 3 combinations:
602  // (kTypeError)
603  // (kTypeManual, mStdOffsetMinutes, mDstOffsetMinutes)
604  // (type, mZoneKey, mZoneProcessor)
605  union {
607  struct {
608  int16_t mStdOffsetMinutes;
609  int16_t mDstOffsetMinutes;
610  };
611 
613  struct {
625  uintptr_t mZoneKey;
626 
632  };
633  };
634 };
635 
636 inline bool operator==(const TimeZone& a, const TimeZone& b) {
637  if (a.mType != b.mType) return false;
638  switch (a.mType) {
641  return true;
642 
644  return a.mStdOffsetMinutes == b.mStdOffsetMinutes
645  && a.mDstOffsetMinutes == b.mDstOffsetMinutes;
646 
647  default:
648  return (a.mZoneKey == b.mZoneKey);
649  }
650 }
651 
652 inline bool operator!=(const TimeZone& a, const TimeZone& b) {
653  return ! (a == b);
654 }
655 
656 }
657 
658 #endif
A specific implementation of BasicZoneProcessorTemplate that uses ZoneXxxBrokers which read from zone...
A specific implementation of ExtendedZoneProcessorTemplate that uses the complete::ZoneXxxBrokers cla...
A specific implementation of ExtendedZoneProcessorTemplate that uses the extended::Info::ZoneXxxBroke...
Result of a search for transition at a specific epochSeconds or a specific LocalDateTime.
Definition: ZoneProcessor.h:23
uint8_t fold
For findByLocalDateTime(), when type==kTypeOverlap, this is a copy of the requested LocalDateTime::fo...
Definition: ZoneProcessor.h:76
int32_t stdOffsetSeconds
STD offset of the resulting OffsetDateTime.
Definition: ZoneProcessor.h:79
int32_t dstOffsetSeconds
DST offset of the resulting OffsetDateTime.
Definition: ZoneProcessor.h:82
int32_t reqDstOffsetSeconds
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.
int32_t reqStdOffsetSeconds
STD offset of the Transition which matched the epochSeconds requested by findByEpochSeconds(),...
Definition: ZoneProcessor.h:95
uint8_t type
Result of the findByEpochSeconds() or findByLocalDateTime() search methods.
Definition: ZoneProcessor.h:65
Class that holds the date-time as the components (year, month, day, hour, minute, second) without reg...
Definition: LocalDateTime.h:30
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 forSeconds(int32_t seconds)
Create TimeOffset from seconds from 00:00.
Definition: TimeOffset.h:96
static TimeOffset forHours(int8_t hours)
Create TimeOffset with the corresponding hour offset.
Definition: TimeOffset.h:62
static TimeOffset forHourMinute(int8_t hour, int8_t minute)
Create TimeOffset from (hour, minute) offset.
Definition: TimeOffset.h:74
static TimeOffset forMinutes(int16_t minutes)
Create TimeOffset from minutes from 00:00.
Definition: TimeOffset.h:91
Class that describes a time zone.
Definition: TimeZone.h:86
ZonedExtra getZonedExtra(acetime_t epochSeconds) const
Return the ZonedExtra information at epochSeconds.
Definition: TimeZone.h:342
static TimeZone forZoneInfo(const complete::Info::ZoneInfo *zoneInfo, CompleteZoneProcessor *zoneProcessor)
Convenience factory method to create from a zoneInfo and an associated ExtendedZoneProcessor.
Definition: TimeZone.h:212
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:12
uint32_t getZoneId() const
Return the zoneId for kTypeBasic, kTypeExtended.
Definition: TimeZone.h:288
ZoneProcessor * mZoneProcessor
An instance of a ZoneProcessor, for example, BasicZoneProcessor or ExtendedZoneProcessor.
Definition: TimeZone.h:631
static TimeZone forZoneInfo(const basic::Info::ZoneInfo *zoneInfo, BasicZoneProcessor *zoneProcessor)
Convenience factory method to create from a zoneInfo and an associated BasicZoneProcessor.
Definition: TimeZone.h:174
void printTargetNameTo(Print &printer) const
Print the name of the target zone if the current time zone is a Link.
Definition: TimeZone.cpp:60
static TimeZone forZoneInfo(const extended::Info::ZoneInfo *zoneInfo, ExtendedZoneProcessor *zoneProcessor)
Convenience factory method to create from a zoneInfo and an associated ExtendedZoneProcessor.
Definition: TimeZone.h:193
OffsetDateTime getOffsetDateTime(const LocalDateTime &ldt) const
Return the best estimate of the OffsetDateTime at the given LocalDateTime for the current TimeZone.
Definition: TimeZone.h:386
OffsetDateTime getOffsetDateTime(acetime_t epochSeconds) const
Return the best estimate of the OffsetDateTime at the given epochSeconds.
Definition: TimeZone.h:432
bool isUtc() const
Return true if UTC (+00:00+00:00).
Definition: TimeZone.h:463
static TimeZone forUtc()
Factory method to create a UTC TimeZone.
Definition: TimeZone.h:98
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:128
uint8_t getType() const
Return the type of TimeZone, used to determine the behavior of certain methods at runtime.
Definition: TimeZone.h:258
bool isLink() const
Return true if timezone is a Link entry pointing to a Zone entry.
Definition: TimeZone.h:271
uintptr_t mZoneKey
An opaque zone key.
Definition: TimeZone.h:625
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:141
void printShortTo(Print &printer) const
Print the short human readable representation of the time zone.
Definition: TimeZone.cpp:34
static const uint8_t kTypeError
A TimeZone that represents an invalid condition.
Definition: TimeZone.h:89
static TimeZone forError()
Return a TimeZone representing an error condition.
Definition: TimeZone.h:241
static TimeZone forZoneKey(uintptr_t zoneKey, ZoneProcessor *processor)
Factory method to create from a generic zoneKey and a generic zoneProcessor.
Definition: TimeZone.h:233
TimeOffset getDstOffset() const
Return the DST TimeOffset.
Definition: TimeZone.h:266
bool isError() const
Return true if TimeZone is an error.
Definition: TimeZone.h:301
bool isDst() const
Return if mDstOffsetMinutes is not zero.
Definition: TimeZone.h:475
static TimeZone forTimeOffset(TimeOffset stdOffset, TimeOffset dstOffset=TimeOffset())
Factory method to create from a UTC offset and an optional DST offset.
Definition: TimeZone.h:115
static const uint8_t kTypeReserved
Reserved for future use.
Definition: TimeZone.h:95
ZonedExtra getZonedExtra(const LocalDateTime &ldt) const
Return the ZonedExtra information at epochSeconds.
Definition: TimeZone.h:304
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:154
TimeZoneData toTimeZoneData() const
Convert to a TimeZoneData object, which can be fed back into ZoneManager::createForTimeZoneData() to ...
Definition: TimeZone.h:486
TimeOffset getStdOffset() const
Return the Standard TimeOffset.
Definition: TimeZone.h:261
static const uint8_t kTypeManual
Manual STD offset and DST offset.
Definition: TimeZone.h:92
TimeZone()
Default constructor creates a UTC TimeZone.
Definition: TimeZone.h:246
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.
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:55
static const uint8_t kTypeExact
The given LocalDateTime matches a single epochSeconds.
Definition: ZonedExtra.h:35
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
Representation of a given time zone, implemented as an array of ZoneEra records.
Definition: ZoneInfoHigh.h:303
Representation of a given time zone, implemented as an array of ZoneEra records.
Definition: ZoneInfoLow.h:324