AceTime  3.0.0
Date and time classes for Arduino that support timezones from the TZ Database.
ZoneInfoHigh.h
Go to the documentation of this file.
1 /*
2  * MIT License
3  * Copyright (c) 2023 Brian T. Park
4  */
5 
6 #ifndef ACE_TIME_ZONE_INFO_HIGH_H
7 #define ACE_TIME_ZONE_INFO_HIGH_H
8 
27 #include <stdint.h>
28 #include <Arduino.h> // pgm_read_xxx()
29 #include <AceCommon.h> // KString
30 #include "compat.h" // ACE_TIME_USE_PROGMEM
31 #include "BrokerCommon.h"
32 
33 class __FlashStringHelper;
34 class Print;
35 
36 namespace ace_time {
37 
42 class ZoneInfoHigh {
43 public:
44 
49 struct ZoneContext {
56  static const int16_t kMaxUntilYear = 32767;
57 
64  static const int16_t kMaxYear = kMaxUntilYear - 1;
65 
74  static const int16_t kMinYear = -32767;
75 
77  static const uint8_t kSuffixW = 0x00;
78 
80  static const uint8_t kSuffixS = 0x10;
81 
83  static const uint8_t kSuffixU = 0x20;
84 
86  int16_t const startYear;
87 
89  int16_t const untilYear;
90 
92  int16_t const startYearAccurate;
93 
95  int16_t const untilYearAccurate;
96 
98  int16_t const baseYear;
99 
101  int16_t const maxTransitions;
102 
104  const char* const tzVersion;
105 
107  uint8_t const numFragments;
108 
110  uint8_t const numLetters;;
111 
113  const char* const* const fragments;
114 
116  const char* const* const letters;
117 };
118 
124 struct ZoneRule {
126  int16_t const fromYear;
127 
129  int16_t const toYear;
130 
132  uint8_t const inMonth;
133 
144  uint8_t const onDayOfWeek;
145 
150  int8_t const onDayOfMonth;
151 
161  uint8_t const atTimeModifier;
162 
167  uint16_t const atTimeCode;
168 
174  int8_t const deltaMinutes;
175 
188  uint8_t const letterIndex;
189 };
190 
197 struct ZonePolicy {
198  const ZoneRule* const rules;
199  uint8_t const numRules;
200 };
201 
215 struct ZoneEra {
220  const ZonePolicy* const zonePolicy;
221 
246  const char* const format;
247 
252  int16_t const offsetCode;
253 
255  uint8_t const offsetRemainder;
256 
263  int8_t const deltaMinutes;
264 
268  int16_t const untilYear;
269 
271  uint8_t const untilMonth;
272 
278  uint8_t const untilDay;
279 
284  uint16_t const untilTimeCode;
285 
296  uint8_t const untilTimeModifier;
297 };
298 
303 struct ZoneInfo {
305  const char* const name;
306 
312  uint32_t const zoneId;
313 
315  const ZoneContext* const zoneContext;
316 
332  uint8_t const numEras;
333 
338  const ZoneEra* const eras;
339 
341  const ZoneInfo* const targetInfo;
342 };
343 
344 //-----------------------------------------------------------------------------
345 // Brokers are wrappers around the above data objects so that outside code
346 // can use the data objects with a consistent API.
347 //-----------------------------------------------------------------------------
348 
353 static int32_t toDeltaSeconds(uint8_t deltaMinutes) {
354  return int32_t(60) * (int8_t) deltaMinutes;
355 }
356 
360 static int32_t toOffsetSeconds(uint16_t offsetCode, uint8_t offsetRemainder) {
361  return int32_t(15) * (int16_t) offsetCode + (int32_t) offsetRemainder;
362 }
363 
370 static uint32_t timeCodeToSeconds(uint16_t code, uint8_t modifier) {
371  return code * (uint32_t) 15 + (modifier & 0x0f);
372 }
373 
379 static uint8_t toSuffix(uint8_t modifier) {
380  return modifier & 0xf0;
381 }
382 
383 //-----------------------------------------------------------------------------
384 
389  public:
390  explicit ZoneContextBroker(const ZoneContext* zoneContext = nullptr)
391  : mZoneContext(zoneContext)
392  {}
393 
394  // use the default copy constructor
395  ZoneContextBroker(const ZoneContextBroker&) = default;
396 
397  // use the default assignment operator
398  ZoneContextBroker& operator=(const ZoneContextBroker&) = default;
399 
400  bool isNull() const { return mZoneContext == nullptr; }
401 
402  const ZoneContext* raw() const { return mZoneContext; }
403 
404  int16_t startYear() const {
405  return (int16_t) pgm_read_word(&mZoneContext->startYear);
406  }
407 
408  int16_t untilYear() const {
409  return (int16_t) pgm_read_word(&mZoneContext->untilYear);
410  }
411 
412  int16_t startYearAccurate() const {
413  return (int16_t) pgm_read_word(&mZoneContext->startYearAccurate);
414  }
415 
416  int16_t untilYearAccurate() const {
417  return (int16_t) pgm_read_word(&mZoneContext->untilYearAccurate);
418  }
419 
420  int16_t baseYear() const {
421  return (int16_t) pgm_read_word(&mZoneContext->baseYear);
422  }
423 
424  int16_t maxTransitions() const {
425  return (int16_t) pgm_read_word(&mZoneContext->maxTransitions);
426  }
427 
428  const __FlashStringHelper* tzVersion() const {
429  return (const __FlashStringHelper*)
430  pgm_read_ptr(&mZoneContext->tzVersion);
431  }
432 
433  uint8_t numFragments() const {
434  return (uint8_t) pgm_read_byte(&mZoneContext->numFragments);
435  }
436 
437  uint8_t numLetters() const {
438  return (uint8_t) pgm_read_byte(&mZoneContext->numLetters);
439  }
440 
441  const __FlashStringHelper* const* fragments() const {
442  return (const __FlashStringHelper* const*)
443  pgm_read_ptr(&mZoneContext->fragments);
444  }
445 
446  const __FlashStringHelper* letter(uint8_t i) const {
447  const char * const* letters = (const char* const*)
448  pgm_read_ptr(&mZoneContext->letters);
449  const char* letter = (const char*) pgm_read_ptr(letters + i);
450  return (const __FlashStringHelper*) letter;
451  }
452 
453  private:
454  const ZoneContext* mZoneContext;
455 };
456 
457 //-----------------------------------------------------------------------------
458 
463  public:
464  explicit ZoneRuleBroker(
465  const ZoneContext* zoneContext = nullptr,
466  const ZoneRule* zoneRule = nullptr)
467  : mZoneContext(zoneContext)
468  , mZoneRule(zoneRule)
469  {}
470 
471  // use the default copy constructor
472  ZoneRuleBroker(const ZoneRuleBroker&) = default;
473 
474  // use the default assignment operator
475  ZoneRuleBroker& operator=(const ZoneRuleBroker&) = default;
476 
477  bool isNull() const { return mZoneRule == nullptr; }
478 
479  int16_t fromYear() const {
480  return pgm_read_word(&mZoneRule->fromYear);
481  }
482 
483  int16_t toYear() const {
484  return pgm_read_word(&mZoneRule->toYear);
485  }
486 
487  uint8_t inMonth() const {
488  return pgm_read_byte(&mZoneRule->inMonth);
489  }
490 
491  uint8_t onDayOfWeek() const {
492  return pgm_read_byte(&mZoneRule->onDayOfWeek);
493  }
494 
495  int8_t onDayOfMonth() const {
496  return pgm_read_byte(&mZoneRule->onDayOfMonth);
497  }
498 
499  uint32_t atTimeSeconds() const {
500  return timeCodeToSeconds(
501  pgm_read_word(&mZoneRule->atTimeCode),
502  pgm_read_byte(&mZoneRule->atTimeModifier));
503  }
504 
505  uint8_t atTimeSuffix() const {
506  return toSuffix(pgm_read_byte(&mZoneRule->atTimeModifier));
507  }
508 
509  int32_t deltaSeconds() const {
510  return toDeltaSeconds(pgm_read_byte(&mZoneRule->deltaMinutes));
511  }
512 
513  const __FlashStringHelper* letter() const {
514  uint8_t index = pgm_read_byte(&mZoneRule->letterIndex);
515  return ZoneContextBroker(mZoneContext).letter(index);
516  }
517 
518  private:
519  const ZoneContext* mZoneContext;
520  const ZoneRule* mZoneRule;
521 };
522 
527  public:
528  explicit ZonePolicyBroker(
529  const ZoneContext* zoneContext,
530  const ZonePolicy* zonePolicy)
531  : mZoneContext(zoneContext)
532  , mZonePolicy(zonePolicy)
533  {}
534 
535  // use default copy constructor
536  ZonePolicyBroker(const ZonePolicyBroker&) = default;
537 
538  // use default assignment operator
539  ZonePolicyBroker& operator=(const ZonePolicyBroker&) = default;
540 
541  bool isNull() const { return mZonePolicy == nullptr; }
542 
543  uint8_t numRules() const {
544  return pgm_read_byte(&mZonePolicy->numRules);
545  }
546 
547  const ZoneRuleBroker rule(uint8_t i) const {
548  const ZoneRule* rules =
549  (const ZoneRule*) pgm_read_ptr(&mZonePolicy->rules);
550  return ZoneRuleBroker(mZoneContext, &rules[i]);
551  }
552 
553  private:
554  const ZoneContext* mZoneContext;
555  const ZonePolicy* mZonePolicy;
556 };
557 
558 //-----------------------------------------------------------------------------
559 
564  public:
565  explicit ZoneEraBroker(
566  const ZoneContext* zoneContext = nullptr,
567  const ZoneEra* zoneEra = nullptr)
568  : mZoneContext(zoneContext)
569  , mZoneEra(zoneEra)
570  {}
571 
572  // use default copy constructor
573  ZoneEraBroker(const ZoneEraBroker&) = default;
574 
575  // use default assignment operator
576  ZoneEraBroker& operator=(const ZoneEraBroker&) = default;
577 
578  bool isNull() const { return mZoneEra == nullptr; }
579 
580  bool equals(const ZoneEraBroker& other) const {
581  return mZoneEra == other.mZoneEra;
582  }
583 
584  const ZonePolicyBroker zonePolicy() const {
585  return ZonePolicyBroker(
586  mZoneContext,
587  (const ZonePolicy*) pgm_read_ptr(&mZoneEra->zonePolicy));
588  }
589 
590  int32_t offsetSeconds() const {
591  return toOffsetSeconds(
592  pgm_read_word(&mZoneEra->offsetCode),
593  pgm_read_byte(&mZoneEra->offsetRemainder));
594  }
595 
596  int32_t deltaSeconds() const {
597  return toDeltaSeconds(pgm_read_byte(&mZoneEra->deltaMinutes));
598  }
599 
600  const char* format() const {
601  return (const char*) pgm_read_ptr(&mZoneEra->format);
602  }
603 
604  int16_t untilYear() const {
605  return pgm_read_word(&mZoneEra->untilYear);
606  }
607 
608  uint8_t untilMonth() const {
609  return pgm_read_byte(&mZoneEra->untilMonth);
610  }
611 
612  uint8_t untilDay() const {
613  return pgm_read_byte(&mZoneEra->untilDay);
614  }
615 
616  uint32_t untilTimeSeconds() const {
617  return timeCodeToSeconds(
618  pgm_read_word(&mZoneEra->untilTimeCode),
619  pgm_read_byte(&mZoneEra->untilTimeModifier));
620  }
621 
622  uint8_t untilTimeSuffix() const {
623  return toSuffix(pgm_read_byte(&mZoneEra->untilTimeModifier));
624  }
625 
626  private:
627  const ZoneContext* mZoneContext;
628  const ZoneEra* mZoneEra;
629 };
630 
635  public:
636  explicit ZoneInfoBroker(const ZoneInfo* zoneInfo = nullptr):
637  mZoneInfo(zoneInfo) {}
638 
639  // use default copy constructor
640  ZoneInfoBroker(const ZoneInfoBroker&) = default;
641 
642  // use default assignment operator
643  ZoneInfoBroker& operator=(const ZoneInfoBroker&) = default;
644 
649  bool equals(uintptr_t zoneKey) const {
650  return mZoneInfo == (const ZoneInfo*) zoneKey;
651  }
652 
653  bool equals(const ZoneInfoBroker& zoneInfoBroker) const {
654  return mZoneInfo == zoneInfoBroker.mZoneInfo;
655  }
656 
657  bool isNull() const { return mZoneInfo == nullptr; }
658 
659  const ZoneContextBroker zoneContext() const {
660  const ZoneContext* context =
661  (const ZoneContext*) pgm_read_ptr(&mZoneInfo->zoneContext);
662  return ZoneContextBroker(context);
663  }
664 
665  const __FlashStringHelper* name() const {
666  return FPSTR(pgm_read_ptr(&mZoneInfo->name));
667  }
668 
669  uint32_t zoneId() const {
670  return pgm_read_dword(&mZoneInfo->zoneId);
671  }
672 
673  uint8_t numEras() const {
674  return pgm_read_byte(&mZoneInfo->numEras);
675  }
676 
677  const ZoneEraBroker era(uint8_t i) const {
678  auto eras = (const ZoneEra*) pgm_read_ptr(&mZoneInfo->eras);
679  return ZoneEraBroker(zoneContext().raw(), &eras[i]);
680  }
681 
682  bool isLink() const {
683  return mZoneInfo->targetInfo != nullptr;
684  }
685 
686  ZoneInfoBroker targetInfo() const {
687  return ZoneInfoBroker(
688  (const ZoneInfo*) pgm_read_ptr(&mZoneInfo->targetInfo));
689  }
690 
692  void printNameTo(Print& printer) const {
693  ZoneContextBroker zc = zoneContext();
694  ace_common::KString kname(name(), zc.fragments(), zc.numFragments());
695  kname.printTo(printer);
696  }
697 
702  void printShortNameTo(Print& printer) const {
703  ace_common::printReplaceCharTo(
704  printer, zoneinfo::findShortName(name()), '_', ' ');
705  }
706 
707  private:
708  const ZoneInfo* mZoneInfo;
709 };
710 
711 //-----------------------------------------------------------------------------
712 
718  public:
719  ZoneRegistryBroker(const ZoneInfo* const* zoneRegistry):
720  mZoneRegistry(zoneRegistry) {}
721 
722  // use default copy constructor
723  ZoneRegistryBroker(const ZoneRegistryBroker&) = default;
724 
725  // use default assignment operator
726  ZoneRegistryBroker& operator=(const ZoneRegistryBroker&) = default;
727 
728  const ZoneInfo* zoneInfo(uint16_t i) const {
729  return (const ZoneInfo*) pgm_read_ptr(&mZoneRegistry[i]);
730  }
731 
732  private:
733  const ZoneInfo* const* mZoneRegistry;
734 };
735 
736 //-----------------------------------------------------------------------------
737 // A factory class for a ZoneInfoBroker.
738 //-----------------------------------------------------------------------------
739 
746  public:
751  ZoneInfoBroker createZoneInfoBroker(uintptr_t zoneKey) const {
752  return ZoneInfoBroker((const ZoneInfo*) zoneKey);
753  }
754 };
755 
756 }; // ZoneInfoHigh
757 
758 } // ace_time
759 
760 #endif
Helper functions are used in both Basic brokers and Extended brokers.
Data broker for accessing a ZoneContext.
Definition: ZoneInfoHigh.h:388
Data broker for accessing ZoneEra.
Definition: ZoneInfoHigh.h:563
Data broker for accessing ZoneInfo.
Definition: ZoneInfoHigh.h:634
void printShortNameTo(Print &printer) const
Print a short human-readable identifier (e.g.
Definition: ZoneInfoHigh.h:702
void printNameTo(Print &printer) const
Print a human-readable identifier (e.g.
Definition: ZoneInfoHigh.h:692
bool equals(uintptr_t zoneKey) const
Definition: ZoneInfoHigh.h:649
A storage object that creates an ZoneInfoBroker from a key that identifies the ZoneInfo.
Definition: ZoneInfoHigh.h:745
ZoneInfoBroker createZoneInfoBroker(uintptr_t zoneKey) const
Definition: ZoneInfoHigh.h:751
Data broker for accessing ZonePolicy.
Definition: ZoneInfoHigh.h:526
Data broker for accessing the ZoneRegistry.
Definition: ZoneInfoHigh.h:717
Data broker for accessing ZoneRule.
Definition: ZoneInfoHigh.h:462
Wrapper class so that the entire collection can be referenced as a singel template parameter.
Definition: ZoneInfoHigh.h:42
static int32_t toOffsetSeconds(uint16_t offsetCode, uint8_t offsetRemainder)
Convert (code, remainder) holding the STDOFF field of ZoneEra into seconds.
Definition: ZoneInfoHigh.h:360
static int32_t toDeltaSeconds(uint8_t deltaMinutes)
Convert the deltaMinutes holding the RULES/DSTOFF field in ZoneEra or the SAVE field in ZoneRule to d...
Definition: ZoneInfoHigh.h:353
static uint32_t timeCodeToSeconds(uint16_t code, uint8_t modifier)
Convert (code, modifier) holding the UNTIL time in ZoneInfo or AT time in ZoneRule into seconds.
Definition: ZoneInfoHigh.h:370
static uint8_t toSuffix(uint8_t modifier)
Extract the 'w', 's' 'u' suffix from the 'modifier' field, so that they can be compared against kSuff...
Definition: ZoneInfoHigh.h:379
Macros and definitions that provide a consistency layer among the various Arduino boards for compatib...
Metadata about the zone database.
Definition: ZoneInfoHigh.h:49
int16_t const startYearAccurate
Start year of accurate transitions.
Definition: ZoneInfoHigh.h:92
static const int16_t kMinYear
The minimum value of fromYear and toYear.
Definition: ZoneInfoHigh.h:74
static const uint8_t kSuffixW
Represents 'w' or wall time.
Definition: ZoneInfoHigh.h:77
int16_t const untilYear
Until year of the zone files as requested.
Definition: ZoneInfoHigh.h:89
static const int16_t kMaxUntilYear
The maximum value of untilYear.
Definition: ZoneInfoHigh.h:56
int16_t const untilYearAccurate
Until year of accurate transitions.
Definition: ZoneInfoHigh.h:95
int16_t const startYear
Start year of the zone files as requested.
Definition: ZoneInfoHigh.h:86
uint8_t const numLetters
Number of fragments.
Definition: ZoneInfoHigh.h:110
int16_t const baseYear
Base year for tiny years.
Definition: ZoneInfoHigh.h:98
int16_t const maxTransitions
Max number of transitions required in TransitionStorage.
Definition: ZoneInfoHigh.h:101
const char *const *const fragments
Zone Name fragment list.
Definition: ZoneInfoHigh.h:110
uint8_t const numFragments
Number of fragments.
Definition: ZoneInfoHigh.h:107
static const uint8_t kSuffixU
Represents 'u' or UTC time.
Definition: ZoneInfoHigh.h:83
static const int16_t kMaxYear
The maximum value fromYear and toYear.
Definition: ZoneInfoHigh.h:64
const char *const *const letters
Zone Rule letters list.
Definition: ZoneInfoHigh.h:116
static const uint8_t kSuffixS
Represents 's' or standard time.
Definition: ZoneInfoHigh.h:80
const char *const tzVersion
TZ Database version which generated the zone info.
Definition: ZoneInfoHigh.h:104
An entry in ZoneInfo which describes which ZonePolicy was being followed during a particular time per...
Definition: ZoneInfoHigh.h:215
int16_t const untilYear
Era is valid until currentTime < untilYear.
Definition: ZoneInfoHigh.h:268
const char *const format
Zone abbreviations (e.g.
Definition: ZoneInfoHigh.h:246
uint8_t const untilMonth
The month field in UNTIL (1-12).
Definition: ZoneInfoHigh.h:271
uint8_t const offsetRemainder
The remainder seconds from offsetCode.
Definition: ZoneInfoHigh.h:255
uint8_t const untilTimeModifier
The untilTimeModifier is a packed field containing 2 pieces of info:
Definition: ZoneInfoHigh.h:296
uint8_t const untilDay
The day field in UNTIL (1-31).
Definition: ZoneInfoHigh.h:278
const ZonePolicy *const zonePolicy
Zone policy, determined by the RULES column.
Definition: ZoneInfoHigh.h:220
uint16_t const untilTimeCode
The time field of UNTIL field in 15-second increments.
Definition: ZoneInfoHigh.h:284
int8_t const deltaMinutes
If zonePolicy is nullptr, this is the DST offset in minutes as defined by the RULES column in 'hh:mm'...
Definition: ZoneInfoHigh.h:263
int16_t const offsetCode
UTC offset in 15-second increments.
Definition: ZoneInfoHigh.h:252
Representation of a given time zone, implemented as an array of ZoneEra records.
Definition: ZoneInfoHigh.h:303
const char *const name
Full name of zone (e.g.
Definition: ZoneInfoHigh.h:305
const ZoneInfo *const targetInfo
If Link, points to the target zone info.
Definition: ZoneInfoHigh.h:341
const ZoneContext *const zoneContext
ZoneContext metadata.
Definition: ZoneInfoHigh.h:315
const ZoneEra *const eras
A const ZoneEras* pointer to numEras ZoneEra entries in increasing order of UNTIL time.
Definition: ZoneInfoHigh.h:338
uint8_t const numEras
Number of ZoneEra entries.
Definition: ZoneInfoHigh.h:332
uint32_t const zoneId
Unique, stable ID of the zone name, created from a hash of the name.
Definition: ZoneInfoHigh.h:312
A collection of transition rules which describe the DST rules of a given administrative region.
Definition: ZoneInfoHigh.h:197
A time zone transition rule.
Definition: ZoneInfoHigh.h:124
uint8_t const letterIndex
Determined by the LETTER column.
Definition: ZoneInfoHigh.h:188
uint8_t const atTimeModifier
The atTimeModifier is a packed field containing 2 pieces of info:
Definition: ZoneInfoHigh.h:161
uint8_t const onDayOfWeek
Determined by the ON column.
Definition: ZoneInfoHigh.h:144
int16_t const fromYear
FROM year.
Definition: ZoneInfoHigh.h:126
int8_t const deltaMinutes
Determined by the SAVE column and contains the offset from UTC in minutes.
Definition: ZoneInfoHigh.h:174
int8_t const onDayOfMonth
Determined by the ON column.
Definition: ZoneInfoHigh.h:150
uint16_t const atTimeCode
Determined by the AT column in units of 15-seconds from 00:00.
Definition: ZoneInfoHigh.h:167
int16_t const toYear
TO year.
Definition: ZoneInfoHigh.h:129
uint8_t const inMonth
Determined by the IN column.
Definition: ZoneInfoHigh.h:132