AceTime  2.1.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 
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(int8_t stdMinutes, int8_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::ZoneInfo* zoneInfo,
176  BasicZoneProcessor* zoneProcessor
177  ) {
178  return TimeZone(
179  zoneProcessor->getType(),
180  (uintptr_t) zoneInfo,
181  zoneProcessor
182  );
183  }
184 
194  const extended::ZoneInfo* zoneInfo,
195  ExtendedZoneProcessor* zoneProcessor
196  ) {
197  return TimeZone(
198  zoneProcessor->getType(),
199  (uintptr_t) zoneInfo,
200  zoneProcessor
201  );
202  }
203 
216  static TimeZone forZoneKey(uintptr_t zoneKey, ZoneProcessor* processor) {
217  return TimeZone(processor->getType(), zoneKey, processor);
218  }
219 
224  static TimeZone forError() {
225  return TimeZone(kTypeError);
226  }
227 
230  mType(kTypeManual),
231  mStdOffsetMinutes(0),
232  mDstOffsetMinutes(0) {}
233 
241  uint8_t getType() const { return mType; }
242 
245  switch (mType) {
246  case kTypeError:
247  case kTypeReserved:
248  case kTypeManual:
249  break;
250 
251  default:
252  return getBoundZoneProcessor()->resetTransitionCache();
253  }
254  }
255 
258  return TimeOffset::forMinutes(mStdOffsetMinutes);
259  }
260 
263  return TimeOffset::forMinutes(mDstOffsetMinutes);
264  }
265 
267  bool isLink() const {
268  switch (mType) {
269  case kTypeError:
270  case kTypeReserved:
271  case kTypeManual:
272  return false;
273 
274  default:
275  return getBoundZoneProcessor()->isLink();
276  }
277  }
278 
284  uint32_t getZoneId() const {
285  switch (mType) {
286  case kTypeError:
287  case kTypeReserved:
288  case kTypeManual:
289  return 0;
290 
291  default:
292  return getBoundZoneProcessor()->getZoneId();
293  }
294  }
295 
297  bool isError() const { return mType == kTypeError; }
298 
301  switch (mType) {
302  case kTypeError:
303  case kTypeReserved:
304  return ZonedExtra::forError();
305 
306  case kTypeManual:
307  const char* abbrev;
308  if (isUtc()) {
309  abbrev = "UTC";
310  } else {
311  abbrev = (mDstOffsetMinutes != 0) ? "DST" : "STD";
312  }
313  return ZonedExtra(
315  mStdOffsetMinutes,
316  mDstOffsetMinutes,
317  mStdOffsetMinutes,
318  mDstOffsetMinutes,
319  abbrev);
320 
321  default: {
322  FindResult result = getBoundZoneProcessor()->findByLocalDateTime(ldt);
323  if (result.type == FindResult::kTypeNotFound) {
324  return ZonedExtra::forError();
325  }
326  return ZonedExtra(
327  result.type, // ZonedExtra::type is identical to FindResult::type
328  result.stdOffsetMinutes,
329  result.dstOffsetMinutes,
330  result.reqStdOffsetMinutes,
331  result.reqDstOffsetMinutes,
332  result.abbrev);
333  }
334  }
335  }
336 
338  ZonedExtra getZonedExtra(acetime_t epochSeconds) const {
339  switch (mType) {
340  case kTypeError:
341  case kTypeReserved:
342  return ZonedExtra::forError();
343 
344  case kTypeManual:
345  const char* abbrev;
346  if (isUtc()) {
347  abbrev = "UTC";
348  } else {
349  abbrev = (mDstOffsetMinutes != 0) ? "DST" : "STD";
350  }
351  return ZonedExtra(
353  mStdOffsetMinutes,
354  mDstOffsetMinutes,
355  mStdOffsetMinutes,
356  mDstOffsetMinutes,
357  abbrev);
358 
359  default: {
360  FindResult result =
361  getBoundZoneProcessor()->findByEpochSeconds(epochSeconds);
362  if (result.type == FindResult::kTypeNotFound) {
363  return ZonedExtra::forError();
364  }
365  return ZonedExtra(
366  result.type, // ZonedExtra::type is identical to FindResult::type
367  result.stdOffsetMinutes,
368  result.dstOffsetMinutes,
369  result.reqStdOffsetMinutes,
370  result.reqDstOffsetMinutes,
371  result.abbrev);
372  }
373  }
374  }
375 
384  switch (mType) {
385  case kTypeError:
386  case kTypeReserved:
387  break;
388 
389  case kTypeManual:
391  ldt,
392  TimeOffset::forMinutes(mStdOffsetMinutes + mDstOffsetMinutes));
393  break;
394 
395  default: {
396  FindResult result = getBoundZoneProcessor()->findByLocalDateTime(ldt);
397  if (result.type == FindResult::kTypeNotFound) {
398  break;
399  }
400 
401  // Convert FindResult into OffsetDateTime using the requested offset.
403  result.reqStdOffsetMinutes + result.reqDstOffsetMinutes);
404  odt = OffsetDateTime::forLocalDateTimeAndOffset(ldt, reqOffset);
405  odt.fold(result.fold);
406 
407  // Special processing for kTypeGap: Convert to epochSeconds using the
408  // reqStdOffsetMinutes and reqDstOffsetMinutes, then convert back to
409  // OffsetDateTime using the target stdOffsetMinutes and
410  // dstOffsetMinutes.
411  if (result.type == FindResult::kTypeGap) {
412  acetime_t epochSeconds = odt.toEpochSeconds();
413  TimeOffset targetOffset = TimeOffset::forMinutes(
414  result.stdOffsetMinutes + result.dstOffsetMinutes);
415  odt = OffsetDateTime::forEpochSeconds(epochSeconds, targetOffset);
416  }
417  break;
418  }
419  }
420  return odt;
421  }
422 
430  switch (mType) {
431  case kTypeError:
432  case kTypeReserved:
433  break;
434 
435  case kTypeManual:
437  epochSeconds,
438  TimeOffset::forMinutes(mStdOffsetMinutes + mDstOffsetMinutes));
439  break;
440 
441  default: {
442  FindResult result =
443  getBoundZoneProcessor()->findByEpochSeconds(epochSeconds);
444  if (result.type == FindResult::kTypeNotFound) {
445  break;
446  }
447 
449  result.reqStdOffsetMinutes + result.reqDstOffsetMinutes);
451  epochSeconds, offset, result.fold);
452  break;
453  }
454  }
455  return odt;
456  }
457 
459  bool isUtc() const {
460  if (mType != kTypeManual) return false;
461  return mStdOffsetMinutes == 0 && mDstOffsetMinutes == 0;
462  }
463 
471  bool isDst() const {
472  if (mType != kTypeManual) return false;
473  return mDstOffsetMinutes != 0;
474  }
475 
480  void setStdOffset(TimeOffset stdOffset) {
481  if (mType != kTypeManual) return;
482  mStdOffsetMinutes = stdOffset.toMinutes();
483  }
484 
489  void setDstOffset(TimeOffset dstOffset) {
490  if (mType != kTypeManual) return;
491  mDstOffsetMinutes = dstOffset.toMinutes();
492  }
493 
501  TimeZoneData d;
502  switch (mType) {
503  case kTypeError:
504  case kTypeReserved:
505  d.type = TimeZoneData::kTypeError;
506  break;
507 
509  d.stdOffsetMinutes = mStdOffsetMinutes;
510  d.dstOffsetMinutes = mDstOffsetMinutes;
511  d.type = TimeZoneData::kTypeManual;
512  break;
513 
514  default:
515  d.zoneId = getZoneId();
516  d.type = TimeZoneData::kTypeZoneId;
517  break;
518  }
519  return d;
520  }
521 
531  void printTo(Print& printer) const;
532 
551  void printShortTo(Print& printer) const;
552 
557  void printTargetNameTo(Print& printer) const;
558 
559  // Use default copy constructor and assignment operator.
560  TimeZone(const TimeZone&) = default;
561  TimeZone& operator=(const TimeZone&) = default;
562 
563  private:
564  friend bool operator==(const TimeZone& a, const TimeZone& b);
565 
572  explicit TimeZone(TimeOffset stdOffset, TimeOffset dstOffset):
573  mType(kTypeManual),
574  mStdOffsetMinutes(stdOffset.toMinutes()),
575  mDstOffsetMinutes(dstOffset.toMinutes()) {}
576 
578  explicit TimeZone(uint8_t type):
579  mType(type) {}
580 
590  explicit TimeZone(
591  uint8_t type,
592  uintptr_t zoneKey,
593  ZoneProcessor* zoneProcessor
594  ):
595  mType(type),
596  mZoneKey(zoneKey),
597  mZoneProcessor(zoneProcessor)
598  {}
599 
607  ZoneProcessor* getBoundZoneProcessor() const {
609  return mZoneProcessor;
610  }
611 
612  uint8_t mType;
613 
614  // 3 combinations:
615  // (kTypeError)
616  // (kTypeManual, mStdOffsetMinutes, mDstOffsetMinutes)
617  // (type, mZoneKey, mZoneProcessor)
618  union {
620  struct {
621  int16_t mStdOffsetMinutes;
622  int16_t mDstOffsetMinutes;
623  };
624 
625  /* Used by kTypeBasic and kTypeExtended. */
626  struct {
637  uintptr_t mZoneKey;
638 
644  };
645  };
646 };
647 
648 inline bool operator==(const TimeZone& a, const TimeZone& b) {
649  if (a.mType != b.mType) return false;
650  switch (a.mType) {
653  return true;
654 
656  return a.mStdOffsetMinutes == b.mStdOffsetMinutes
657  && a.mDstOffsetMinutes == b.mDstOffsetMinutes;
658 
659  default:
660  return (a.mZoneKey == b.mZoneKey);
661  }
662 }
663 
664 inline bool operator!=(const TimeZone& a, const TimeZone& b) {
665  return ! (a == b);
666 }
667 
668 }
669 
670 #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:25
uint8_t fold
For findByLocalDateTime(), when type==kTypeOverlap, this is a copy of the requested LocalDateTime::fo...
Definition: ZoneProcessor.h:78
int16_t dstOffsetMinutes
DST offset of the resulting OffsetDateTime.
Definition: ZoneProcessor.h:84
int16_t reqStdOffsetMinutes
STD offset of the Transition which matched the epochSeconds requested by findByEpochSeconds(),...
Definition: ZoneProcessor.h:97
int16_t stdOffsetMinutes
STD offset of the resulting OffsetDateTime.
Definition: ZoneProcessor.h:81
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:67
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
int16_t toMinutes() const
Return the time offset as minutes.
Definition: TimeOffset.h:111
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:86
ZonedExtra getZonedExtra(acetime_t epochSeconds) const
Return the ZonedExtra information at epochSeconds.
Definition: TimeZone.h:338
static TimeZone forZoneInfo(const extended::ZoneInfo *zoneInfo, ExtendedZoneProcessor *zoneProcessor)
Convenience factory method to create from a zoneInfo and an associated ExtendedZoneProcessor.
Definition: TimeZone.h:193
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:284
ZoneProcessor * mZoneProcessor
An instance of a ZoneProcessor, for example, BasicZoneProcessor or ExtendedZoneProcessor.
Definition: TimeZone.h:643
void setDstOffset(TimeOffset dstOffset)
Sets the dstOffset of the TimeZone.
Definition: TimeZone.h:489
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:382
OffsetDateTime getOffsetDateTime(acetime_t epochSeconds) const
Return the best estimate of the OffsetDateTime at the given epochSeconds.
Definition: TimeZone.h:428
bool isUtc() const
Return true if UTC (+00:00+00:00).
Definition: TimeZone.h:459
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
void resetZoneProcessor()
Reset the underlying ZoneProcessor if a ZoneProcessor is used.
Definition: TimeZone.h:244
uint8_t getType() const
Return the type of TimeZone, used to determine the behavior of certain methods at runtime.
Definition: TimeZone.h:241
bool isLink() const
Return true if timezone is a Link entry pointing to a Zone entry.
Definition: TimeZone.h:267
uintptr_t mZoneKey
An opaque zone key.
Definition: TimeZone.h:637
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:89
static TimeZone forError()
Return a TimeZone representing an error condition.
Definition: TimeZone.h:224
static TimeZone forZoneKey(uintptr_t zoneKey, ZoneProcessor *processor)
Factory method to create from a generic zoneKey and a generic zoneProcessor.
Definition: TimeZone.h:216
TimeOffset getDstOffset() const
Return the DST TimeOffset.
Definition: TimeZone.h:262
bool isError() const
Return true if TimeZone is an error.
Definition: TimeZone.h:297
void setStdOffset(TimeOffset stdOffset)
Sets the stdOffset of the TimeZone.
Definition: TimeZone.h:480
static TimeZone forZoneInfo(const basic::ZoneInfo *zoneInfo, BasicZoneProcessor *zoneProcessor)
Convenience factory method to create from a zoneInfo and an associated BasicZoneProcessor.
Definition: TimeZone.h:174
bool isDst() const
Return if mDstOffsetMinutes is not zero.
Definition: TimeZone.h:471
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:300
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:500
TimeOffset getStdOffset() const
Return the Standard TimeOffset.
Definition: TimeZone.h:257
static TimeZone forMinutes(int8_t stdMinutes, int8_t dstMinutes=0)
Factory method to create from UTC minute offset and optional DST minute offset.
Definition: TimeZone.h:141
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:229
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: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