AceTime  3.0.0
Date and time classes for Arduino that support timezones from the TZ Database.
ZoneInfoMid.h
Go to the documentation of this file.
1 /*
2  * MIT License
3  * Copyright (c) 2018 Brian T. Park
4  */
5 
6 #ifndef ACE_TIME_ZONE_INFO_MID_H
7 #define ACE_TIME_ZONE_INFO_MID_H
8 
31 #include <stdint.h>
32 #include <Arduino.h> // pgm_read_xxx()
33 #include <AceCommon.h> // KString
34 #include "compat.h" // ACE_TIME_USE_PROGMEM
35 #include "BrokerCommon.h"
36 
37 class __FlashStringHelper;
38 class Print;
39 
40 namespace ace_time {
41 
46 class ZoneInfoMid {
47 public:
48 
53 struct ZoneContext {
60  static const int16_t kMaxUntilYear = 32767;
61 
68  static const int16_t kMaxYear = kMaxUntilYear - 1;
69 
78  static const int16_t kMinYear = -32767;
79 
81  static const uint8_t kSuffixW = 0x00;
82 
84  static const uint8_t kSuffixS = 0x10;
85 
87  static const uint8_t kSuffixU = 0x20;
88 
90  int16_t const startYear;
91 
93  int16_t const untilYear;
94 
96  int16_t const startYearAccurate;
97 
99  int16_t const untilYearAccurate;
100 
102  int16_t const baseYear;
103 
105  int16_t const maxTransitions;
106 
108  const char* const tzVersion;
109 
111  uint8_t const numFragments;
112 
114  uint8_t const numLetters;;
115 
117  const char* const* const fragments;
118 
120  const char* const* const letters;
121 };
122 
128 struct ZoneRule {
130  int16_t const fromYear;
131 
133  int16_t const toYear;
134 
136  uint8_t const inMonth;
137 
148  uint8_t const onDayOfWeek;
149 
154  int8_t const onDayOfMonth;
155 
160  uint8_t const atTimeCode;
161 
171  uint8_t const atTimeModifier;
172 
183  uint8_t const deltaCode;
184 
197  uint8_t const letterIndex;
198 };
199 
206 struct ZonePolicy {
207  const ZoneRule* const rules;
208  uint8_t const numRules;
209 };
210 
223 struct ZoneEra {
228  const ZonePolicy* const zonePolicy;
229 
254  const char* const format;
255 
257  int8_t const offsetCode;
258 
276  uint8_t const deltaCode;
277 
281  int16_t const untilYear;
282 
284  uint8_t const untilMonth;
285 
291  uint8_t const untilDay;
292 
297  uint8_t const untilTimeCode;
298 
309  uint8_t const untilTimeModifier;
310 };
311 
316 struct ZoneInfo {
318  const char* const name;
319 
325  uint32_t const zoneId;
326 
328  const ZoneContext* const zoneContext;
329 
345  uint8_t const numEras;
346 
351  const ZoneEra* const eras;
352 
354  const ZoneInfo* const targetInfo;
355 };
356 
357 //-----------------------------------------------------------------------------
358 // Brokers are wrappers around the above data objects so that outside code
359 // can use the data objects with a consistent API.
360 //-----------------------------------------------------------------------------
361 
372 static int16_t toDeltaMinutes(uint8_t deltaCode) {
373  return ((int16_t)(deltaCode & 0x0f) - 4) * 15;
374 }
375 
382 static int16_t toOffsetMinutes(uint8_t offsetCode, uint8_t deltaCode) {
383  return ((int8_t)offsetCode * 15) + ((deltaCode & 0xf0) >> 4);
384 }
385 
386 
393 static uint16_t timeCodeToMinutes(uint8_t code, uint8_t modifier) {
394  return code * (uint16_t) 15 + (modifier & 0x0f);
395 }
396 
402 static uint8_t toSuffix(uint8_t modifier) {
403  return modifier & 0xf0;
404 }
405 
406 //-----------------------------------------------------------------------------
407 
412  public:
413  explicit ZoneContextBroker(const ZoneContext* zoneContext = nullptr)
414  : mZoneContext(zoneContext)
415  {}
416 
417  // use the default copy constructor
418  ZoneContextBroker(const ZoneContextBroker&) = default;
419 
420  // use the default assignment operator
421  ZoneContextBroker& operator=(const ZoneContextBroker&) = default;
422 
423  bool isNull() const { return mZoneContext == nullptr; }
424 
425  const ZoneContext* raw() const { return mZoneContext; }
426 
427  int16_t startYear() const {
428  return (int16_t) pgm_read_word(&mZoneContext->startYear);
429  }
430 
431  int16_t untilYear() const {
432  return (int16_t) pgm_read_word(&mZoneContext->untilYear);
433  }
434 
435  int16_t startYearAccurate() const {
436  return (int16_t) pgm_read_word(&mZoneContext->startYearAccurate);
437  }
438 
439  int16_t untilYearAccurate() const {
440  return (int16_t) pgm_read_word(&mZoneContext->untilYearAccurate);
441  }
442 
443  int16_t baseYear() const {
444  return (int16_t) pgm_read_word(&mZoneContext->baseYear);
445  }
446 
447  int16_t maxTransitions() const {
448  return (int16_t) pgm_read_word(&mZoneContext->maxTransitions);
449  }
450 
451  const __FlashStringHelper* tzVersion() const {
452  return (const __FlashStringHelper*)
453  pgm_read_ptr(&mZoneContext->tzVersion);
454  }
455 
456  uint8_t numFragments() const {
457  return (uint8_t) pgm_read_byte(&mZoneContext->numFragments);
458  }
459 
460  uint8_t numLetters() const {
461  return (uint8_t) pgm_read_byte(&mZoneContext->numLetters);
462  }
463 
464  const __FlashStringHelper* const* fragments() const {
465  return (const __FlashStringHelper* const*)
466  pgm_read_ptr(&mZoneContext->fragments);
467  }
468 
469  const __FlashStringHelper* letter(uint8_t i) const {
470  const char * const* letters = (const char* const*)
471  pgm_read_ptr(&mZoneContext->letters);
472  const char* letter = (const char*) pgm_read_ptr(letters + i);
473  return (const __FlashStringHelper*) letter;
474  }
475 
476  private:
477  const ZoneContext* mZoneContext;
478 };
479 
480 //-----------------------------------------------------------------------------
481 
486  public:
487  explicit ZoneRuleBroker(
488  const ZoneContext* zoneContext = nullptr,
489  const ZoneRule* zoneRule = nullptr)
490  : mZoneContext(zoneContext)
491  , mZoneRule(zoneRule)
492  {}
493 
494  // use the default copy constructor
495  ZoneRuleBroker(const ZoneRuleBroker&) = default;
496 
497  // use the default assignment operator
498  ZoneRuleBroker& operator=(const ZoneRuleBroker&) = default;
499 
500  bool isNull() const { return mZoneRule == nullptr; }
501 
502  int16_t fromYear() const {
503  return pgm_read_word(&mZoneRule->fromYear);
504  }
505 
506  int16_t toYear() const {
507  return pgm_read_word(&mZoneRule->toYear);
508  }
509 
510  uint8_t inMonth() const {
511  return pgm_read_byte(&mZoneRule->inMonth);
512  }
513 
514  uint8_t onDayOfWeek() const {
515  return pgm_read_byte(&mZoneRule->onDayOfWeek);
516  }
517 
518  int8_t onDayOfMonth() const {
519  return pgm_read_byte(&mZoneRule->onDayOfMonth);
520  }
521 
522  uint32_t atTimeSeconds() const {
523  return 60 * timeCodeToMinutes(
524  pgm_read_byte(&mZoneRule->atTimeCode),
525  pgm_read_byte(&mZoneRule->atTimeModifier));
526  }
527 
528  uint8_t atTimeSuffix() const {
529  return toSuffix(pgm_read_byte(&mZoneRule->atTimeModifier));
530  }
531 
532  int32_t deltaSeconds() const {
533  return 60 * toDeltaMinutes(pgm_read_byte(&mZoneRule->deltaCode));
534  }
535 
536  const __FlashStringHelper* letter() const {
537  uint8_t index = pgm_read_byte(&mZoneRule->letterIndex);
538  return ZoneContextBroker(mZoneContext).letter(index);
539  }
540 
541  private:
542  const ZoneContext* mZoneContext;
543  const ZoneRule* mZoneRule;
544 };
545 
550  public:
551  explicit ZonePolicyBroker(
552  const ZoneContext* zoneContext,
553  const ZonePolicy* zonePolicy)
554  : mZoneContext(zoneContext)
555  , mZonePolicy(zonePolicy)
556  {}
557 
558  // use default copy constructor
559  ZonePolicyBroker(const ZonePolicyBroker&) = default;
560 
561  // use default assignment operator
562  ZonePolicyBroker& operator=(const ZonePolicyBroker&) = default;
563 
564  bool isNull() const { return mZonePolicy == nullptr; }
565 
566  uint8_t numRules() const {
567  return pgm_read_byte(&mZonePolicy->numRules);
568  }
569 
570  const ZoneRuleBroker rule(uint8_t i) const {
571  const ZoneRule* rules =
572  (const ZoneRule*) pgm_read_ptr(&mZonePolicy->rules);
573  return ZoneRuleBroker(mZoneContext, &rules[i]);
574  }
575 
576  private:
577  const ZoneContext* mZoneContext;
578  const ZonePolicy* mZonePolicy;
579 };
580 
581 //-----------------------------------------------------------------------------
582 
587  public:
588  explicit ZoneEraBroker(
589  const ZoneContext* zoneContext = nullptr,
590  const ZoneEra* zoneEra = nullptr)
591  : mZoneContext(zoneContext)
592  , mZoneEra(zoneEra)
593  {}
594 
595  // use default copy constructor
596  ZoneEraBroker(const ZoneEraBroker&) = default;
597 
598  // use default assignment operator
599  ZoneEraBroker& operator=(const ZoneEraBroker&) = default;
600 
601  bool isNull() const { return mZoneEra == nullptr; }
602 
603  bool equals(const ZoneEraBroker& other) const {
604  return mZoneEra == other.mZoneEra;
605  }
606 
607  const ZonePolicyBroker zonePolicy() const {
608  return ZonePolicyBroker(
609  mZoneContext,
610  (const ZonePolicy*) pgm_read_ptr(&mZoneEra->zonePolicy));
611  }
612 
613  int32_t offsetSeconds() const {
614  return 60 * toOffsetMinutes(
615  pgm_read_byte(&mZoneEra->offsetCode),
616  pgm_read_byte(&mZoneEra->deltaCode));
617  }
618 
619  int32_t deltaSeconds() const {
620  return 60 * toDeltaMinutes(pgm_read_byte(&mZoneEra->deltaCode));
621  }
622 
623  const char* format() const {
624  return (const char*) pgm_read_ptr(&mZoneEra->format);
625  }
626 
627  int16_t untilYear() const {
628  return pgm_read_word(&mZoneEra->untilYear);
629  }
630 
631  uint8_t untilMonth() const {
632  return pgm_read_byte(&mZoneEra->untilMonth);
633  }
634 
635  uint8_t untilDay() const {
636  return pgm_read_byte(&mZoneEra->untilDay);
637  }
638 
639  uint32_t untilTimeSeconds() const {
640  return 60 * timeCodeToMinutes(
641  pgm_read_byte(&mZoneEra->untilTimeCode),
642  pgm_read_byte(&mZoneEra->untilTimeModifier));
643  }
644 
645  uint8_t untilTimeSuffix() const {
646  return toSuffix(pgm_read_byte(&mZoneEra->untilTimeModifier));
647  }
648 
649  private:
650  const ZoneContext* mZoneContext;
651  const ZoneEra* mZoneEra;
652 };
653 
658  public:
659  explicit ZoneInfoBroker(const ZoneInfo* zoneInfo = nullptr):
660  mZoneInfo(zoneInfo) {}
661 
662  // use default copy constructor
663  ZoneInfoBroker(const ZoneInfoBroker&) = default;
664 
665  // use default assignment operator
666  ZoneInfoBroker& operator=(const ZoneInfoBroker&) = default;
667 
672  bool equals(uintptr_t zoneKey) const {
673  return mZoneInfo == (const ZoneInfo*) zoneKey;
674  }
675 
676  bool equals(const ZoneInfoBroker& zoneInfoBroker) const {
677  return mZoneInfo == zoneInfoBroker.mZoneInfo;
678  }
679 
680  bool isNull() const { return mZoneInfo == nullptr; }
681 
682  const ZoneContextBroker zoneContext() const {
683  const ZoneContext* context =
684  (const ZoneContext*) pgm_read_ptr(&mZoneInfo->zoneContext);
685  return ZoneContextBroker(context);
686  }
687 
688  const __FlashStringHelper* name() const {
689  return FPSTR(pgm_read_ptr(&mZoneInfo->name));
690  }
691 
692  uint32_t zoneId() const {
693  return pgm_read_dword(&mZoneInfo->zoneId);
694  }
695 
696  uint8_t numEras() const {
697  return pgm_read_byte(&mZoneInfo->numEras);
698  }
699 
700  const ZoneEraBroker era(uint8_t i) const {
701  auto eras = (const ZoneEra*) pgm_read_ptr(&mZoneInfo->eras);
702  return ZoneEraBroker(zoneContext().raw(), &eras[i]);
703  }
704 
705  bool isLink() const {
706  return mZoneInfo->targetInfo != nullptr;
707  }
708 
709  ZoneInfoBroker targetInfo() const {
710  return ZoneInfoBroker(
711  (const ZoneInfo*) pgm_read_ptr(&mZoneInfo->targetInfo));
712  }
713 
715  void printNameTo(Print& printer) const {
716  ZoneContextBroker zc = zoneContext();
717  ace_common::KString kname(name(), zc.fragments(), zc.numFragments());
718  kname.printTo(printer);
719  }
720 
725  void printShortNameTo(Print& printer) const {
726  ace_common::printReplaceCharTo(
727  printer, zoneinfo::findShortName(name()), '_', ' ');
728  }
729 
730  private:
731  const ZoneInfo* mZoneInfo;
732 };
733 
734 //-----------------------------------------------------------------------------
735 
741  public:
742  ZoneRegistryBroker(const ZoneInfo* const* zoneRegistry):
743  mZoneRegistry(zoneRegistry) {}
744 
745  // use default copy constructor
746  ZoneRegistryBroker(const ZoneRegistryBroker&) = default;
747 
748  // use default assignment operator
749  ZoneRegistryBroker& operator=(const ZoneRegistryBroker&) = default;
750 
751  const ZoneInfo* zoneInfo(uint16_t i) const {
752  return (const ZoneInfo*) pgm_read_ptr(&mZoneRegistry[i]);
753  }
754 
755  private:
756  const ZoneInfo* const* mZoneRegistry;
757 };
758 
759 //-----------------------------------------------------------------------------
760 // A factory class for a ZoneInfoBroker.
761 //-----------------------------------------------------------------------------
762 
769  public:
774  ZoneInfoBroker createZoneInfoBroker(uintptr_t zoneKey) const {
775  return ZoneInfoBroker((const ZoneInfo*) zoneKey);
776  }
777 };
778 
779 }; // ZoneInfoMid
780 
781 } // ace_time
782 
783 #endif
Helper functions are used in both Basic brokers and Extended brokers.
Data broker for accessing a ZoneContext.
Definition: ZoneInfoMid.h:411
Data broker for accessing ZoneEra.
Definition: ZoneInfoMid.h:586
Data broker for accessing ZoneInfo.
Definition: ZoneInfoMid.h:657
void printShortNameTo(Print &printer) const
Print a short human-readable identifier (e.g.
Definition: ZoneInfoMid.h:725
void printNameTo(Print &printer) const
Print a human-readable identifier (e.g.
Definition: ZoneInfoMid.h:715
bool equals(uintptr_t zoneKey) const
Definition: ZoneInfoMid.h:672
A storage object that creates an ZoneInfoBroker from a key that identifies the ZoneInfo.
Definition: ZoneInfoMid.h:768
ZoneInfoBroker createZoneInfoBroker(uintptr_t zoneKey) const
Definition: ZoneInfoMid.h:774
Data broker for accessing ZonePolicy.
Definition: ZoneInfoMid.h:549
Data broker for accessing the ZoneRegistry.
Definition: ZoneInfoMid.h:740
Data broker for accessing ZoneRule.
Definition: ZoneInfoMid.h:485
Wrapper class so that the entire collection can be referenced as a singel template parameter.
Definition: ZoneInfoMid.h:46
static uint16_t timeCodeToMinutes(uint8_t code, uint8_t modifier)
Convert (code, modifier) fields representing the UNTIL time in ZoneInfo or AT time in ZoneRule in one...
Definition: ZoneInfoMid.h:393
static int16_t toDeltaMinutes(uint8_t deltaCode)
Convert the deltaCode holding the RULES/DSTOFF field in ZoneEra or the SAVE field in ZoneRule to the ...
Definition: ZoneInfoMid.h:372
static int16_t toOffsetMinutes(uint8_t offsetCode, uint8_t deltaCode)
Convert the offsetCode and deltaCode holding the STDOFF field of the ZoneEra into minutes.
Definition: ZoneInfoMid.h:382
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: ZoneInfoMid.h:402
Macros and definitions that provide a consistency layer among the various Arduino boards for compatib...
Metadata about the zone database.
Definition: ZoneInfoMid.h:53
int16_t const startYearAccurate
Start year of accurate transitions.
Definition: ZoneInfoMid.h:96
int16_t const startYear
Start year of the zone files as requested.
Definition: ZoneInfoMid.h:90
int16_t const baseYear
Base year for tiny years.
Definition: ZoneInfoMid.h:102
const char *const tzVersion
TZ Database version which generated the zone info.
Definition: ZoneInfoMid.h:108
static const uint8_t kSuffixU
Represents 'u' or UTC time.
Definition: ZoneInfoMid.h:87
int16_t const untilYearAccurate
Until year of accurate transitions.
Definition: ZoneInfoMid.h:99
uint8_t const numFragments
Number of fragments.
Definition: ZoneInfoMid.h:111
static const int16_t kMinYear
The minimum value of fromYear and toYear.
Definition: ZoneInfoMid.h:78
const char *const *const fragments
Zone Name fragment list.
Definition: ZoneInfoMid.h:114
static const int16_t kMaxYear
The maximum value fromYear and toYear.
Definition: ZoneInfoMid.h:68
int16_t const maxTransitions
Max number of transitions required in TransitionStorage.
Definition: ZoneInfoMid.h:105
static const uint8_t kSuffixS
Represents 's' or standard time.
Definition: ZoneInfoMid.h:84
int16_t const untilYear
Until year of the zone files as requested.
Definition: ZoneInfoMid.h:93
static const uint8_t kSuffixW
Represents 'w' or wall time.
Definition: ZoneInfoMid.h:81
const char *const *const letters
Zone Rule letters list.
Definition: ZoneInfoMid.h:120
uint8_t const numLetters
Number of fragments.
Definition: ZoneInfoMid.h:114
static const int16_t kMaxUntilYear
The maximum value of untilYear.
Definition: ZoneInfoMid.h:60
An entry in ZoneInfo which describes which ZonePolicy was being followed during a particular time per...
Definition: ZoneInfoMid.h:223
uint8_t const untilMonth
The month field in UNTIL (1-12).
Definition: ZoneInfoMid.h:284
const ZonePolicy *const zonePolicy
Zone policy, determined by the RULES column.
Definition: ZoneInfoMid.h:228
uint8_t const untilTimeModifier
The untilTimeModifier is a packed field containing 2 pieces of info:
Definition: ZoneInfoMid.h:309
int16_t const untilYear
Era is valid until currentTime < untilYear.
Definition: ZoneInfoMid.h:281
uint8_t const untilTimeCode
The time field of UNTIL field in 15-minute increments.
Definition: ZoneInfoMid.h:297
int8_t const offsetCode
UTC offset in 15 min increments.
Definition: ZoneInfoMid.h:257
const char *const format
Zone abbreviations (e.g.
Definition: ZoneInfoMid.h:254
uint8_t const deltaCode
This is a composite of two 4-bit fields:
Definition: ZoneInfoMid.h:276
uint8_t const untilDay
The day field in UNTIL (1-31).
Definition: ZoneInfoMid.h:291
Representation of a given time zone, implemented as an array of ZoneEra records.
Definition: ZoneInfoMid.h:316
const char *const name
Full name of zone (e.g.
Definition: ZoneInfoMid.h:318
const ZoneInfo *const targetInfo
If Link, points to the target zone info.
Definition: ZoneInfoMid.h:354
const ZoneEra *const eras
A const ZoneEras* pointer to numEras ZoneEra entries in increasing order of UNTIL time.
Definition: ZoneInfoMid.h:351
uint32_t const zoneId
Unique, stable ID of the zone name, created from a hash of the name.
Definition: ZoneInfoMid.h:325
uint8_t const numEras
Number of ZoneEra entries.
Definition: ZoneInfoMid.h:345
const ZoneContext *const zoneContext
ZoneContext metadata.
Definition: ZoneInfoMid.h:328
A collection of transition rules which describe the DST rules of a given administrative region.
Definition: ZoneInfoMid.h:206
A time zone transition rule.
Definition: ZoneInfoMid.h:128
uint8_t const letterIndex
Determined by the LETTER column.
Definition: ZoneInfoMid.h:197
int8_t const onDayOfMonth
Determined by the ON column.
Definition: ZoneInfoMid.h:154
uint8_t const deltaCode
Determined by the SAVE column and contains the offset from UTC, in 15-min increments.
Definition: ZoneInfoMid.h:183
int16_t const fromYear
FROM year.
Definition: ZoneInfoMid.h:130
uint8_t const inMonth
Determined by the IN column.
Definition: ZoneInfoMid.h:136
uint8_t const atTimeModifier
The atTimeModifier is a packed field containing 2 pieces of info:
Definition: ZoneInfoMid.h:171
uint8_t const atTimeCode
Determined by the AT column in units of 15-minutes from 00:00.
Definition: ZoneInfoMid.h:160
uint8_t const onDayOfWeek
Determined by the ON column.
Definition: ZoneInfoMid.h:148
int16_t const toYear
TO year.
Definition: ZoneInfoMid.h:133