diff --git a/CHANGELOG.md b/CHANGELOG.md index 274917844..e8b54a427 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,15 @@ # Changelog - Unreleased +- 2.4.0 (2024-12-13, TZDB version 2024b) + - Support new `%z` value in FORMAT column. + - Upgrade TZDB to 2024b + - https://lists.iana.org/hyperkitty/list/tz-announce@iana.org/thread/IZ7AO6WRE3W3TWBL5IR6PMQUL433BQIE/ + - "Improve historical data for Mexico, Mongolia, and Portugal. System V + names are now obsolescent. The main data form now uses %z. The code + now conforms to RFC 8536 for early timestamps. Support POSIX.1-2024, + which removes asctime_r and ctime_r. Assume POSIX.2-1992 or later for + shell scripts. SUPPORT_C89 now defaults to 1." - 2.3.2 (2024-07-25, TZDB version 2024a) - Upgrade TZDB to 2024a - https://mm.icann.org/pipermail/tz-announce/2024-February/000081.html diff --git a/DEVELOPER.md b/DEVELOPER.md index 41b991f85..15904f164 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -123,7 +123,7 @@ implementations defined, corresponding to different resolution levels supported by each set: * `ZoneInfoLow.h` - * low resolution + * low resolution persistence format * 1-minute resolution for AT, UNTIL, STDOFF; 15-minute resolution for DST offsets * year fields using 1-byte offset from a `baseYear` of 2100, @@ -136,7 +136,7 @@ by each set: * `ZoneInfoMid.h` * medium resolution persistence format * 1-minute resolution for AT, UNTIL, STDOFF; 15-minute resolution for - DST offset) + DST offset * 2-byte year fields supporting years `[-32767,32765]` * `zoneinfomid::ZoneContext<>` * `zoneinfomid::ZoneRule<>` diff --git a/README.md b/README.md index e40338d09..e595b788c 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ and the `zonedbc` database to support all timezones, for all transitions defined in the IANA TZ database (`[1844,2087]`), and extending the validity of timezone calculations from `[2000,10000)` to `[0001,10000)`. -**Version**: 2.3.2 (2024-07-25, TZDB version 2024a) +**Version**: 2.4.0 (2024-12-13, TZDB version 2024b) **Changelog**: [CHANGELOG.md](CHANGELOG.md) diff --git a/USER_GUIDE.md b/USER_GUIDE.md index e5d4f9f88..55882f358 100644 --- a/USER_GUIDE.md +++ b/USER_GUIDE.md @@ -18,7 +18,7 @@ The IANA TZ database is programmatically generated into 3 predefined databases: databases have different accuracy ranges, and are designed to work with different `ZoneProcessor` and `ZoneManager` classes. -**Version**: 2.3.2 (2024-07-25, TZDB 2024a) +**Version**: 2.4.0 (2024-12-13, TZDB 2024b) **Related Documents**: diff --git a/docs/doxygen.cfg b/docs/doxygen.cfg index b9e4cb4b2..fe18e1720 100644 --- a/docs/doxygen.cfg +++ b/docs/doxygen.cfg @@ -38,7 +38,7 @@ PROJECT_NAME = AceTime # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 2.3.0 +PROJECT_NUMBER = 2.4.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/docs/html/AceTime_8h_source.html b/docs/html/AceTime_8h_source.html index 55be1d0d9..8ac70b621 100644 --- a/docs/html/AceTime_8h_source.html +++ b/docs/html/AceTime_8h_source.html @@ -22,7 +22,7 @@
AceTime -  2.3.0 +  2.4.0
Date and time classes for Arduino that support timezones from the TZ Database.
@@ -91,50 +91,51 @@
29 #include "zoneinfo/brokers.h"
30 #include "ace_time/common/common.h"
31 #include "ace_time/common/DateStrings.h"
-
32 #include "ace_time/EpochConverterJulian.h"
-
33 #include "ace_time/EpochConverterHinnant.h"
-
34 #include "ace_time/Epoch.h"
-
35 #include "ace_time/LocalDate.h"
-
36 #include "ace_time/local_date_mutation.h"
-
37 #include "ace_time/LocalTime.h"
-
38 #include "ace_time/LocalDateTime.h"
-
39 #include "ace_time/TimeOffset.h"
-
40 #include "ace_time/time_offset_mutation.h"
-
41 #include "ace_time/OffsetDateTime.h"
-
42 #include "ace_time/offset_date_time_mutation.h"
-
43 #include "ace_time/ZoneProcessor.h"
-
44 #include "ace_time/BasicZoneProcessor.h"
-
45 #include "ace_time/ExtendedZoneProcessor.h"
-
46 #include "ace_time/CompleteZoneProcessor.h"
-
47 #include "ace_time/ZoneProcessorCache.h"
-
48 #include "ace_time/ZoneRegistrar.h"
-
49 #include "ace_time/ZoneManager.h"
-
50 #include "ace_time/ZoneSorterByName.h"
-
51 #include "ace_time/ZoneSorterByOffsetAndName.h"
-
52 #include "ace_time/TimeZoneData.h"
-
53 #include "ace_time/TimeZone.h"
-
54 #include "ace_time/BasicZone.h"
-
55 #include "ace_time/ExtendedZone.h"
-
56 #include "ace_time/ZonedDateTime.h"
-
57 #include "ace_time/zoned_date_time_mutation.h"
-
58 #include "ace_time/TimePeriod.h"
-
59 #include "ace_time/time_period_mutation.h"
-
60 #include "ace_time/ace_time_utils.h"
-
61 #include "zonedb/zone_policies.h"
-
62 #include "zonedb/zone_infos.h"
-
63 #include "zonedb/zone_registry.h"
-
64 #include "zonedbx/zone_policies.h"
-
65 #include "zonedbx/zone_infos.h"
-
66 #include "zonedbx/zone_registry.h"
-
67 #include "zonedbc/zone_policies.h"
-
68 #include "zonedbc/zone_infos.h"
-
69 #include "zonedbc/zone_registry.h"
-
70 
-
71 // Version format: xxyyzz == "xx.yy.zz"
-
72 #define ACE_TIME_VERSION 20300
-
73 #define ACE_TIME_VERSION_STRING "2.3.0"
-
74 
-
75 #endif
+
32 #include "ace_time/common/DateConv.h"
+
33 #include "ace_time/EpochConverterJulian.h"
+
34 #include "ace_time/EpochConverterHinnant.h"
+
35 #include "ace_time/Epoch.h"
+
36 #include "ace_time/LocalDate.h"
+
37 #include "ace_time/local_date_mutation.h"
+
38 #include "ace_time/LocalTime.h"
+
39 #include "ace_time/LocalDateTime.h"
+
40 #include "ace_time/TimeOffset.h"
+
41 #include "ace_time/time_offset_mutation.h"
+
42 #include "ace_time/OffsetDateTime.h"
+
43 #include "ace_time/offset_date_time_mutation.h"
+
44 #include "ace_time/ZoneProcessor.h"
+
45 #include "ace_time/BasicZoneProcessor.h"
+
46 #include "ace_time/ExtendedZoneProcessor.h"
+
47 #include "ace_time/CompleteZoneProcessor.h"
+
48 #include "ace_time/ZoneProcessorCache.h"
+
49 #include "ace_time/ZoneRegistrar.h"
+
50 #include "ace_time/ZoneManager.h"
+
51 #include "ace_time/ZoneSorterByName.h"
+
52 #include "ace_time/ZoneSorterByOffsetAndName.h"
+
53 #include "ace_time/TimeZoneData.h"
+
54 #include "ace_time/TimeZone.h"
+
55 #include "ace_time/BasicZone.h"
+
56 #include "ace_time/ExtendedZone.h"
+
57 #include "ace_time/ZonedDateTime.h"
+
58 #include "ace_time/zoned_date_time_mutation.h"
+
59 #include "ace_time/TimePeriod.h"
+
60 #include "ace_time/time_period_mutation.h"
+
61 #include "ace_time/ace_time_utils.h"
+
62 #include "zonedb/zone_policies.h"
+
63 #include "zonedb/zone_infos.h"
+
64 #include "zonedb/zone_registry.h"
+
65 #include "zonedbx/zone_policies.h"
+
66 #include "zonedbx/zone_infos.h"
+
67 #include "zonedbx/zone_registry.h"
+
68 #include "zonedbc/zone_policies.h"
+
69 #include "zonedbc/zone_infos.h"
+
70 #include "zonedbc/zone_registry.h"
+
71 
+
72 // Version format: xxyyzz == "xx.yy.zz"
+
73 #define ACE_TIME_VERSION 20400
+
74 #define ACE_TIME_VERSION_STRING "2.4.0"
+
75 
+
76 #endif
brokers.h
The brokers in the basic:: and extended:: namespaces are identical in code.
common.h
Identifiers used by implementation code which need to be publically exported.
compat.h
Macros and definitions that provide a consistency layer among the various Arduino boards for compatib...
diff --git a/docs/html/BasicZoneProcessor_8h_source.html b/docs/html/BasicZoneProcessor_8h_source.html index f7c6d2599..fe4bdecd4 100644 --- a/docs/html/BasicZoneProcessor_8h_source.html +++ b/docs/html/BasicZoneProcessor_8h_source.html @@ -22,7 +22,7 @@
AceTime -  2.3.0 +  2.4.0
Date and time classes for Arduino that support timezones from the TZ Database.
@@ -101,662 +101,658 @@
28 class BasicZoneProcessorTest_init_primitives;
29 class BasicZoneProcessorTest_initForLocalDate;
30 class BasicZoneProcessorTest_setZoneKey;
-
31 class BasicZoneProcessorTest_createAbbreviation;
-
32 class BasicZoneProcessorTest_calcRuleOffsetMinutes;
-
33 
-
34 class Print;
-
35 
-
36 namespace ace_time {
-
37 namespace basic {
-
38 
-
59 template <typename ZIB, typename ZEB, typename ZPB, typename ZRB>
-
60 struct TransitionTemplate {
-
66  ZEB era;
-
67 
-
77  ZRB rule;
-
78 
-
80  acetime_t startEpochSeconds;
-
81 
-
87  int16_t offsetMinutes;
-
88 
-
90  int16_t deltaMinutes;
-
91 
-
93  int16_t year;
-
94 
-
100  uint8_t month;
-
101 
-
109  char abbrev[internal::kAbbrevSize];
-
110 
-
112  void log() const {
-
113  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
-
114  logging::printf("(%d/%d)", year, month);
-
115  if (sizeof(acetime_t) == sizeof(int)) {
-
116  logging::printf("; stEps: %d", startEpochSeconds);
-
117  } else {
-
118  logging::printf("; stEps: %ld", startEpochSeconds);
-
119  }
-
120  logging::printf("; offMin: %d", offsetMinutes);
-
121  logging::printf("; abbrev: %s", abbrev);
-
122  if (! rule.isNull()) {
-
123  logging::printf("; r.fromYear: %d", rule.fromYear());
-
124  logging::printf("; r.toYear: %d", rule.toYear());
-
125  logging::printf("; r.inMonth: %d", rule.inMonth());
-
126  logging::printf("; r.onDayOfMonth: %d", rule.onDayOfMonth());
-
127  }
-
128  logging::printf("\n");
-
129  }
-
130  }
-
131 };
-
132 
-
134 inline int8_t compareYearMonth(int16_t aYear, uint8_t aMonth,
-
135  int16_t bYear, uint8_t bMonth) {
-
136  if (aYear < bYear) return -1;
-
137  if (aYear > bYear) return 1;
-
138  if (aMonth < bMonth) return -1;
-
139  if (aMonth > bMonth) return 1;
-
140  return 0;
-
141 }
+
31 class BasicZoneProcessorTest_calcRuleOffsetMinutes;
+
32 
+
33 class Print;
+
34 
+
35 namespace ace_time {
+
36 namespace basic {
+
37 
+
58 template <typename ZIB, typename ZEB, typename ZPB, typename ZRB>
+
59 struct TransitionTemplate {
+
65  ZEB era;
+
66 
+
76  ZRB rule;
+
77 
+
79  acetime_t startEpochSeconds;
+
80 
+
85  int16_t offsetMinutes;
+
86 
+
88  int16_t deltaMinutes;
+
89 
+
91  int16_t year;
+
92 
+
98  uint8_t month;
+
99 
+
107  char abbrev[internal::kAbbrevSize];
+
108 
+
110  void log() const {
+
111  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
+
112  logging::printf("(%d/%d)", year, month);
+
113  if (sizeof(acetime_t) == sizeof(int)) {
+
114  logging::printf("; stEps: %d", startEpochSeconds);
+
115  } else {
+
116  logging::printf("; stEps: %ld", startEpochSeconds);
+
117  }
+
118  logging::printf("; offMin: %d", offsetMinutes);
+
119  logging::printf("; abbrev: %s", abbrev);
+
120  if (! rule.isNull()) {
+
121  logging::printf("; r.fromYear: %d", rule.fromYear());
+
122  logging::printf("; r.toYear: %d", rule.toYear());
+
123  logging::printf("; r.inMonth: %d", rule.inMonth());
+
124  logging::printf("; r.onDayOfMonth: %d", rule.onDayOfMonth());
+
125  }
+
126  logging::printf("\n");
+
127  }
+
128  }
+
129 };
+
130 
+
132 inline int8_t compareYearMonth(int16_t aYear, uint8_t aMonth,
+
133  int16_t bYear, uint8_t bMonth) {
+
134  if (aYear < bYear) return -1;
+
135  if (aYear > bYear) return 1;
+
136  if (aMonth < bMonth) return -1;
+
137  if (aMonth > bMonth) return 1;
+
138  return 0;
+
139 }
+
140 
+
141 } // namespace basic
142 
-
143 } // namespace basic
-
144 
-
202 template <typename ZIS, typename ZIB, typename ZEB, typename ZPB, typename ZRB>
-
203 class BasicZoneProcessorTemplate: public ZoneProcessor {
-
204  public:
-
206  typedef basic::TransitionTemplate<ZIB, ZEB, ZPB, ZRB> Transition;
-
207 
-
208  bool isLink() const override {
-
209  return ! mZoneInfoBroker.targetInfo().isNull();
-
210  }
-
211 
-
212  uint32_t getZoneId() const override {
-
213  return mZoneInfoBroker.zoneId();
-
214  }
-
215 
-
244  FindResult findByLocalDateTime(
-
245  const LocalDateTime& ldt) const override {
-
246  FindResult result;
-
247  bool success = initForLocalDate(ldt.localDate());
-
248  if (!success) return result;
-
249 
-
250  // 0) Use the UTC epochSeconds to get intial guess of offset.
-
251  acetime_t epochSeconds0 = ldt.toEpochSeconds();
-
252  auto result0 = findByEpochSeconds(epochSeconds0);
-
253  if (result0.type == FindResult::kTypeNotFound) return result;
-
254  auto offset0 = TimeOffset::forSeconds(
-
255  result0.reqStdOffsetSeconds + result0.reqDstOffsetSeconds);
-
256 
-
257  // 1) Use offset0 to get the next epochSeconds and offset.
-
258  auto odt = OffsetDateTime::forLocalDateTimeAndOffset(ldt, offset0);
-
259  acetime_t epochSeconds1 = odt.toEpochSeconds();
-
260  auto result1 = findByEpochSeconds(epochSeconds1);
-
261  if (result1.type == FindResult::kTypeNotFound) return result;
-
262  auto offset1 = TimeOffset::forSeconds(
-
263  result1.reqStdOffsetSeconds + result1.reqDstOffsetSeconds);
-
264 
-
265  // 2) Use offset1 to get the next epochSeconds and offset.
-
266  odt = OffsetDateTime::forLocalDateTimeAndOffset(ldt, offset1);
-
267  acetime_t epochSeconds2 = odt.toEpochSeconds();
-
268  auto result2 = findByEpochSeconds(epochSeconds2);
-
269  if (result2.type == FindResult::kTypeNotFound) return result;
-
270  auto offset2 = TimeOffset::forSeconds(
-
271  result2.reqStdOffsetSeconds + result2.reqDstOffsetSeconds);
-
272 
-
273  // If offset1 and offset2 are equal, then we have an equilibrium
-
274  // and odt(1) must equal odt(2).
-
275  if (offset1 == offset2) {
-
276  // I think this happens for kTypeExact or kTypeOverlap, but the current
-
277  // algorithm cannot distinguish between the two, so let's pretend that
-
278  // it is kTypeExact. Pick either of result1 or result2.
-
279  result = result1;
-
280  } else {
-
281  // If the offsets don't match, then I think we have a kTypeGap.
-
282  // Pick the stdOffset and dstOffset that generate the later epochSeconds
-
283  // (the earlier transition), but convert into the LocalDateTime of the
-
284  // earlier epochSeconds (the later transition).
-
285  if (epochSeconds1 > epochSeconds2) {
-
286  result = result1;
-
287  } else {
-
288  result = result2;
-
289  }
-
290  result.type = FindResult::kTypeGap;
-
291  }
-
292 
-
293  return result;
-
294  }
-
295 
-
296  FindResult findByEpochSeconds(acetime_t epochSeconds) const override {
-
297  FindResult result;
-
298  const Transition* transition = getTransition(epochSeconds);
-
299  if (!transition) return result;
-
300 
-
301  result.dstOffsetSeconds = transition->deltaMinutes * kSecPerMin;
-
302  result.stdOffsetSeconds = (transition->offsetMinutes
-
303  - transition->deltaMinutes) * kSecPerMin;
-
304  result.reqStdOffsetSeconds = result.stdOffsetSeconds;
-
305  result.reqDstOffsetSeconds = result.dstOffsetSeconds;
-
306  result.type = FindResult::kTypeExact;
-
307  result.abbrev = transition->abbrev;
+
200 template <typename ZIS, typename ZIB, typename ZEB, typename ZPB, typename ZRB>
+
201 class BasicZoneProcessorTemplate: public ZoneProcessor {
+
202  public:
+
204  typedef basic::TransitionTemplate<ZIB, ZEB, ZPB, ZRB> Transition;
+
205 
+
206  bool isLink() const override {
+
207  return ! mZoneInfoBroker.targetInfo().isNull();
+
208  }
+
209 
+
210  uint32_t getZoneId() const override {
+
211  return mZoneInfoBroker.zoneId();
+
212  }
+
213 
+
242  FindResult findByLocalDateTime(
+
243  const LocalDateTime& ldt) const override {
+
244  FindResult result;
+
245  bool success = initForLocalDate(ldt.localDate());
+
246  if (!success) return result;
+
247 
+
248  // 0) Use the UTC epochSeconds to get intial guess of offset.
+
249  acetime_t epochSeconds0 = ldt.toEpochSeconds();
+
250  auto result0 = findByEpochSeconds(epochSeconds0);
+
251  if (result0.type == FindResult::kTypeNotFound) return result;
+
252  auto offset0 = TimeOffset::forSeconds(
+
253  result0.reqStdOffsetSeconds + result0.reqDstOffsetSeconds);
+
254 
+
255  // 1) Use offset0 to get the next epochSeconds and offset.
+
256  auto odt = OffsetDateTime::forLocalDateTimeAndOffset(ldt, offset0);
+
257  acetime_t epochSeconds1 = odt.toEpochSeconds();
+
258  auto result1 = findByEpochSeconds(epochSeconds1);
+
259  if (result1.type == FindResult::kTypeNotFound) return result;
+
260  auto offset1 = TimeOffset::forSeconds(
+
261  result1.reqStdOffsetSeconds + result1.reqDstOffsetSeconds);
+
262 
+
263  // 2) Use offset1 to get the next epochSeconds and offset.
+
264  odt = OffsetDateTime::forLocalDateTimeAndOffset(ldt, offset1);
+
265  acetime_t epochSeconds2 = odt.toEpochSeconds();
+
266  auto result2 = findByEpochSeconds(epochSeconds2);
+
267  if (result2.type == FindResult::kTypeNotFound) return result;
+
268  auto offset2 = TimeOffset::forSeconds(
+
269  result2.reqStdOffsetSeconds + result2.reqDstOffsetSeconds);
+
270 
+
271  // If offset1 and offset2 are equal, then we have an equilibrium
+
272  // and odt(1) must equal odt(2).
+
273  if (offset1 == offset2) {
+
274  // I think this happens for kTypeExact or kTypeOverlap, but the current
+
275  // algorithm cannot distinguish between the two, so let's pretend that
+
276  // it is kTypeExact. Pick either of result1 or result2.
+
277  result = result1;
+
278  } else {
+
279  // If the offsets don't match, then I think we have a kTypeGap.
+
280  // Pick the stdOffset and dstOffset that generate the later epochSeconds
+
281  // (the earlier transition), but convert into the LocalDateTime of the
+
282  // earlier epochSeconds (the later transition).
+
283  if (epochSeconds1 > epochSeconds2) {
+
284  result = result1;
+
285  } else {
+
286  result = result2;
+
287  }
+
288  result.type = FindResult::kTypeGap;
+
289  }
+
290 
+
291  return result;
+
292  }
+
293 
+
294  FindResult findByEpochSeconds(acetime_t epochSeconds) const override {
+
295  FindResult result;
+
296  const Transition* transition = getTransition(epochSeconds);
+
297  if (!transition) return result;
+
298 
+
299  result.dstOffsetSeconds = transition->deltaMinutes * kSecPerMin;
+
300  result.stdOffsetSeconds = transition->offsetMinutes * kSecPerMin;
+
301  result.reqStdOffsetSeconds = result.stdOffsetSeconds;
+
302  result.reqDstOffsetSeconds = result.dstOffsetSeconds;
+
303  result.type = FindResult::kTypeExact;
+
304  result.abbrev = transition->abbrev;
+
305 
+
306  return result;
+
307  }
308 
-
309  return result;
-
310  }
-
311 
-
312  void printNameTo(Print& printer) const override {
-
313  mZoneInfoBroker.printNameTo(printer);
-
314  }
-
315 
-
316  void printShortNameTo(Print& printer) const override {
-
317  mZoneInfoBroker.printShortNameTo(printer);
-
318  }
-
319 
-
320  void printTargetNameTo(Print& printer) const override {
-
321  if (isLink()) {
-
322  mZoneInfoBroker.targetInfo().printNameTo(printer);
-
323  }
-
324  }
-
325 
-
326  void setZoneKey(uintptr_t zoneKey) override {
-
327  if (! mZoneInfoStore) return;
-
328  if (mZoneInfoBroker.equals(zoneKey)) return;
-
329 
-
330  mZoneInfoBroker = mZoneInfoStore->createZoneInfoBroker(zoneKey);
-
331  mYear = LocalDate::kInvalidYear;
-
332  mNumTransitions = 0;
-
333  }
-
334 
-
335  bool equalsZoneKey(uintptr_t zoneKey) const override {
-
336  return mZoneInfoBroker.equals(zoneKey);
-
337  }
-
338 
-
340  void log() const {
-
341  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
-
342  logging::printf("BasicZoneProcessor:\n");
-
343  logging::printf(" mEpochYear: %d\n", mEpochYear);
-
344  logging::printf(" mYear: %d\n", mYear);
-
345  logging::printf(" mNumTransitions: %d\n", mNumTransitions);
-
346  for (int i = 0; i < mNumTransitions; i++) {
-
347  logging::printf(" mT[%d]=", i);
-
348  mTransitions[i].log();
-
349  }
-
350  }
-
351  }
-
352 
-
359  void setZoneInfoStore(const ZIS* zoneInfoStore) {
-
360  mZoneInfoStore = zoneInfoStore;
-
361  }
-
362 
-
363  protected:
-
364 
-
375  explicit BasicZoneProcessorTemplate(
-
376  uint8_t type,
-
377  const ZIS* zoneInfoStore /*nullable*/,
-
378  uintptr_t zoneKey
-
379  ) :
-
380  ZoneProcessor(type),
-
381  mZoneInfoStore(zoneInfoStore)
-
382  {
-
383  setZoneKey(zoneKey);
-
384  }
-
385 
-
386  private:
-
387  friend class ::BasicZoneProcessorTest_priorYearOfRule;
-
388  friend class ::BasicZoneProcessorTest_compareRulesBeforeYear;
-
389  friend class ::BasicZoneProcessorTest_findLatestPriorRule;
-
390  friend class ::BasicZoneProcessorTest_findZoneEra;
-
391  friend class ::BasicZoneProcessorTest_init_primitives;
-
392  friend class ::BasicZoneProcessorTest_initForLocalDate;
-
393  friend class ::BasicZoneProcessorTest_setZoneKey;
-
394  friend class ::BasicZoneProcessorTest_createAbbreviation;
-
395  friend class ::BasicZoneProcessorTest_calcRuleOffsetMinutes;
-
396 
-
407  static const uint8_t kMaxCacheEntries = 5;
-
408 
-
414  static const acetime_t kMinEpochSeconds = INT32_MIN + 1;
-
415 
-
416  // Disable copy constructor and assignment operator.
-
417  BasicZoneProcessorTemplate(const BasicZoneProcessorTemplate&) = delete;
-
418  BasicZoneProcessorTemplate& operator=(const BasicZoneProcessorTemplate&) =
-
419  delete;
-
420 
-
421  bool equals(const ZoneProcessor& other) const override {
-
422  return mZoneInfoBroker.equals(
-
423  ((const BasicZoneProcessorTemplate&) other).mZoneInfoBroker);
-
424  }
-
425 
-
427  const Transition* getTransition(acetime_t epochSeconds) const {
-
428  bool success = initForEpochSeconds(epochSeconds);
-
429  return (success) ? findMatch(epochSeconds) : nullptr;
-
430  }
-
431 
-
460  bool initForLocalDate(const LocalDate& ld) const {
-
461  int16_t year = ld.year();
-
462  if (ld.month() == 1 && ld.day() == 1) {
-
463  year--;
-
464  }
-
465  // Restrict to [1,9999], even though LocalDate should be able to handle
-
466  // [0,10000].
-
467  if (year <= LocalDate::kMinYear || LocalDate::kMaxYear <= year) {
-
468  return false;
-
469  }
-
470 
-
471  if (isFilled(year)) return true;
-
472  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
-
473  logging::printf("initForLocalDate(): %d (new year %d)\n",
-
474  ld.year(), year);
-
475  }
+
309  void printNameTo(Print& printer) const override {
+
310  mZoneInfoBroker.printNameTo(printer);
+
311  }
+
312 
+
313  void printShortNameTo(Print& printer) const override {
+
314  mZoneInfoBroker.printShortNameTo(printer);
+
315  }
+
316 
+
317  void printTargetNameTo(Print& printer) const override {
+
318  if (isLink()) {
+
319  mZoneInfoBroker.targetInfo().printNameTo(printer);
+
320  }
+
321  }
+
322 
+
323  void setZoneKey(uintptr_t zoneKey) override {
+
324  if (! mZoneInfoStore) return;
+
325  if (mZoneInfoBroker.equals(zoneKey)) return;
+
326 
+
327  mZoneInfoBroker = mZoneInfoStore->createZoneInfoBroker(zoneKey);
+
328  mYear = LocalDate::kInvalidYear;
+
329  mNumTransitions = 0;
+
330  }
+
331 
+
332  bool equalsZoneKey(uintptr_t zoneKey) const override {
+
333  return mZoneInfoBroker.equals(zoneKey);
+
334  }
+
335 
+
337  void log() const {
+
338  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
+
339  logging::printf("BasicZoneProcessor:\n");
+
340  logging::printf(" mEpochYear: %d\n", mEpochYear);
+
341  logging::printf(" mYear: %d\n", mYear);
+
342  logging::printf(" mNumTransitions: %d\n", mNumTransitions);
+
343  for (int i = 0; i < mNumTransitions; i++) {
+
344  logging::printf(" mT[%d]=", i);
+
345  mTransitions[i].log();
+
346  }
+
347  }
+
348  }
+
349 
+
356  void setZoneInfoStore(const ZIS* zoneInfoStore) {
+
357  mZoneInfoStore = zoneInfoStore;
+
358  }
+
359 
+
360  protected:
+
361 
+
372  explicit BasicZoneProcessorTemplate(
+
373  uint8_t type,
+
374  const ZIS* zoneInfoStore /*nullable*/,
+
375  uintptr_t zoneKey
+
376  ) :
+
377  ZoneProcessor(type),
+
378  mZoneInfoStore(zoneInfoStore)
+
379  {
+
380  setZoneKey(zoneKey);
+
381  }
+
382 
+
383  private:
+
384  friend class ::BasicZoneProcessorTest_priorYearOfRule;
+
385  friend class ::BasicZoneProcessorTest_compareRulesBeforeYear;
+
386  friend class ::BasicZoneProcessorTest_findLatestPriorRule;
+
387  friend class ::BasicZoneProcessorTest_findZoneEra;
+
388  friend class ::BasicZoneProcessorTest_init_primitives;
+
389  friend class ::BasicZoneProcessorTest_initForLocalDate;
+
390  friend class ::BasicZoneProcessorTest_setZoneKey;
+
391  friend class ::BasicZoneProcessorTest_calcRuleOffsetMinutes;
+
392 
+
403  static const uint8_t kMaxCacheEntries = 5;
+
404 
+
410  static const acetime_t kMinEpochSeconds = INT32_MIN + 1;
+
411 
+
412  // Disable copy constructor and assignment operator.
+
413  BasicZoneProcessorTemplate(const BasicZoneProcessorTemplate&) = delete;
+
414  BasicZoneProcessorTemplate& operator=(const BasicZoneProcessorTemplate&) =
+
415  delete;
+
416 
+
417  bool equals(const ZoneProcessor& other) const override {
+
418  return mZoneInfoBroker.equals(
+
419  ((const BasicZoneProcessorTemplate&) other).mZoneInfoBroker);
+
420  }
+
421 
+
423  const Transition* getTransition(acetime_t epochSeconds) const {
+
424  bool success = initForEpochSeconds(epochSeconds);
+
425  return (success) ? findMatch(epochSeconds) : nullptr;
+
426  }
+
427 
+
456  bool initForLocalDate(const LocalDate& ld) const {
+
457  int16_t year = ld.year();
+
458  if (ld.month() == 1 && ld.day() == 1) {
+
459  year--;
+
460  }
+
461  // Restrict to [1,9999], even though LocalDate should be able to handle
+
462  // [0,10000].
+
463  if (year <= LocalDate::kMinYear || LocalDate::kMaxYear <= year) {
+
464  return false;
+
465  }
+
466 
+
467  if (isFilled(year)) return true;
+
468  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
+
469  logging::printf("initForLocalDate(): %d (new year %d)\n",
+
470  ld.year(), year);
+
471  }
+
472 
+
473  mYear = year;
+
474  mEpochYear = Epoch::currentEpochYear();
+
475  mNumTransitions = 0; // clear cache
476 
-
477  mYear = year;
-
478  mEpochYear = Epoch::currentEpochYear();
-
479  mNumTransitions = 0; // clear cache
-
480 
-
481  ZEB priorEra = addTransitionPriorToYear(year);
-
482  ZEB currentEra = addTransitionsForYear(year, priorEra);
-
483  addTransitionAfterYear(year, currentEra);
-
484  calcTransitions();
-
485  calcAbbreviations();
+
477  ZEB priorEra = addTransitionPriorToYear(year);
+
478  ZEB currentEra = addTransitionsForYear(year, priorEra);
+
479  addTransitionAfterYear(year, currentEra);
+
480  calcTransitions();
+
481  calcAbbreviations();
+
482 
+
483  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
+
484  log();
+
485  }
486 
-
487  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
-
488  log();
-
489  }
-
490 
-
491  return true;
-
492  }
-
493 
-
499  bool initForEpochSeconds(acetime_t epochSeconds) const {
-
500  LocalDate ld = LocalDate::forEpochSeconds(epochSeconds);
-
501  return initForLocalDate(ld);
-
502  }
-
503 
-
510  ZEB addTransitionPriorToYear(int16_t year) const {
-
511  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
-
512  logging::printf("addTransitionPriorToYear(): %d\n", year);
-
513  }
-
514 
-
515  const ZEB era = findZoneEra(mZoneInfoBroker, year - 1);
-
516 
-
517  // If the prior ZoneEra has a ZonePolicy), then find the latest rule
-
518  // within the ZoneEra. Otherwise, add a Transition using a rule==nullptr.
-
519  ZRB latest = findLatestPriorRule(era.zonePolicy(), year);
-
520  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
-
521  logging::printf("addTransitionsPriorToYear(): adding latest prior ");
-
522  if (latest.isNull()) {
-
523  logging::printf("ZR(null)\n");
-
524  } else {
-
525  logging::printf("ZR[%d,%d]\n", latest.fromYear(), latest.toYear());
-
526  }
-
527  }
-
528  addTransition(year - 1, 0 /*month*/, era, latest);
-
529 
-
530  return era;
-
531  }
-
532 
-
538  static ZRB findLatestPriorRule(const ZPB& zonePolicy, int16_t year) {
-
539  ZRB latest;
-
540  if (zonePolicy.isNull()) return latest;
-
541 
-
542  uint8_t numRules = zonePolicy.numRules();
-
543  for (uint8_t i = 0; i < numRules; i++) {
-
544  const ZRB rule = zonePolicy.rule(i);
-
545  // Check if rule is effective prior to the given year
-
546  if (rule.fromYear() < year) {
-
547  if ((latest.isNull()) ||
-
548  compareRulesBeforeYear(year, rule, latest) > 0) {
-
549  latest = rule;
-
550  }
-
551  }
-
552  }
-
553 
-
554  return latest;
-
555  }
-
556 
-
558  static int8_t compareRulesBeforeYear(
-
559  int16_t year, const ZRB& a, const ZRB& b) {
-
560  return basic::compareYearMonth(
-
561  priorYearOfRule(year, a), a.inMonth(),
-
562  priorYearOfRule(year, b), b.inMonth());
-
563  }
-
564 
-
573  static int16_t priorYearOfRule(int16_t year, const ZRB& rule) {
-
574  if (rule.toYear() < year) {
-
575  return rule.toYear();
-
576  }
-
577  return year - 1;
-
578  }
-
579 
-
584  ZEB addTransitionsForYear(int16_t year, const ZEB& priorEra) const {
-
585  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
-
586  logging::printf("addTransitionsForYear(): %d\n", year);
-
587  }
-
588 
-
589  const ZEB era = findZoneEra(mZoneInfoBroker, year);
-
590 
-
591  // If the ZonePolicy has no rules, then add a Transition which takes
-
592  // effect at the start time of the current year.
-
593  const ZPB zonePolicy = era.zonePolicy();
-
594  if (zonePolicy.isNull()) {
-
595  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
-
596  logging::printf("addTransitionsForYear(): adding ZE.untilY=%d\n",
-
597  era.untilYear());
-
598  }
-
599  addTransition(year, 0 /*month*/, era, ZRB());
-
600  return era;
-
601  }
-
602 
-
603  if (! era.equals(priorEra)) {
-
604  // The ZoneEra has changed, so we need to find the Rule in effect at
-
605  // the start of the current year of the current ZoneEra. This may be a
-
606  // rule far in the past, but shift the rule forward to {year, 1, 1}.
-
607  ZRB latestPrior = findLatestPriorRule(era.zonePolicy(), year);
-
608  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
-
609  logging::printf(
-
610  "addTransitionsForYear(): adding latest prior ");
-
611  if (latestPrior.isNull()) {
-
612  logging::printf("ZR(null)\n");
-
613  } else {
-
614  logging::printf("ZR[%d,%d]\n",
-
615  latestPrior.fromYear(), latestPrior.toYear());
-
616  }
-
617  }
-
618  addTransition(year, 1 /*month*/, era, latestPrior);
-
619  }
-
620 
-
621  // Find all directly matching transitions (i.e. the [from, to] overlap
-
622  // with the current year) and add them to mTransitions, in sorted order
-
623  // according to the ZoneRule::inMonth field.
-
624  uint8_t numRules = zonePolicy.numRules();
-
625  for (uint8_t i = 0; i < numRules; i++) {
-
626  const ZRB rule = zonePolicy.rule(i);
-
627  if ((rule.fromYear() <= year) && (year <= rule.toYear())) {
-
628  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
-
629  logging::printf(
-
630  "addTransitionsForYear(): adding rule ");
-
631  if (rule.isNull()) {
-
632  logging::printf("ZR(null)\n");
-
633  } else {
-
634  logging::printf("ZR[%d,%d]\n", rule.fromYear(), rule.toYear());
-
635  }
-
636  }
-
637  addTransition(year, 0 /*month*/, era, rule);
-
638  }
-
639  }
-
640 
-
641  return era;
-
642  }
-
643 
-
645  void addTransitionAfterYear(int16_t year, const ZEB& currentEra) const {
-
646  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
-
647  logging::printf("addTransitionAfterYear(): %d\n", year);
-
648  }
-
649 
-
650  const ZEB eraAfter = findZoneEra(mZoneInfoBroker, year + 1);
-
651 
-
652  // If the current era is the same as the following year, then we'll just
-
653  // assume that the latest ZoneRule carries over to Jan 1st of the next
-
654  // year. tzcompiler.py guarantees no ZoneRule occurs on Jan 1st.
-
655  if (currentEra.equals(eraAfter)) {
-
656  return;
-
657  }
-
658 
-
659  // If the ZoneEra did change, find the latest transition prior to
-
660  // {year + 1, 1, 1}, then shift that Transition to Jan 1st of the
-
661  // following year.
-
662  ZRB latest = findLatestPriorRule(eraAfter.zonePolicy(), year + 1);
-
663  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
-
664  logging::printf(
-
665  "addTransitionsAfterYear(): adding latest prior ");
-
666  if (latest.isNull()) {
-
667  logging::printf("ZR(null)\n");
-
668  } else {
-
669  logging::printf("ZR[%d,%d]\n", latest.fromYear(), latest.toYear());
-
670  }
-
671  }
-
672  addTransition(year + 1, 1 /*month*/, eraAfter, latest);
-
673  }
-
674 
-
698  void addTransition(int16_t year, uint8_t month, const ZEB& era,
-
699  const ZRB& rule) const {
-
700 
-
701  // If a zone needs more transitions than kMaxCacheEntries, the check below
-
702  // will cause the DST transition information to be inaccurate, and it is
-
703  // highly likely that this situation would be caught in the
-
704  // AceTimeValidation tests. Since these integration tests pass, I feel
-
705  // confident that those zones which need more than kMaxCacheEntries are
-
706  // already filtered out by tzcompiler.py.
-
707  //
-
708  // Ideally, the tzcompiler.py script would explicitly remove those zones
-
709  // which need more than kMaxCacheEntries Transitions. But this would
-
710  // require a Python version of the BasicZoneProcessor, and unfortunately,
-
711  // zone_processor.py implements only the ExtendedZoneProcessor algorithm
-
712  // An early version of zone_processor.py may have implemented something
-
713  // close to BasicZoneProcessor, and it may be available in the git
-
714  // history. But it seems like too much work right now to try to dig that
-
715  // out, just to implement the explicit check for kMaxCacheEntries. It
-
716  // would mean maintaining another version of zone_processor.py.
-
717  if (mNumTransitions >= kMaxCacheEntries) return;
-
718 
-
719  // Insert new element at the end of the list.
-
720  // NOTE: It is probably tempting to pass a pointer (or reference) to
-
721  // mTransitions[mNumTransitions] into createTransition(), instead of
-
722  // returning it by value. However, MemoryBenchmark shows that directly
-
723  // updating the Transition through the pointer increases flash memory
-
724  // consumption by ~110 bytes on AVR processors. It seems that creating a
-
725  // local copy of Transition on the stack, filling it, and then copying it
-
726  // by value takes fewer instructions.
-
727  mTransitions[mNumTransitions] = createTransition(year, month, era, rule);
-
728  mNumTransitions++;
-
729 
-
730  // perform an insertion sort based on ZoneRule.inMonth()
-
731  for (uint8_t i = mNumTransitions - 1; i > 0; i--) {
-
732  Transition& left = mTransitions[i - 1];
-
733  Transition& right = mTransitions[i];
-
734  // assume only 1 rule per month
-
735  if (basic::compareYearMonth(left.year, left.month,
-
736  right.year, right.month) > 0) {
-
737  Transition tmp = left;
-
738  left = right;
-
739  right = tmp;
-
740  }
-
741  }
-
742  }
-
743 
-
749  static Transition createTransition(int16_t year, uint8_t month,
-
750  const ZEB& era, const ZRB& rule) {
-
751 
-
752  Transition transition;
-
753  int16_t deltaMinutes;
-
754  uint8_t mon;
-
755  if (rule.isNull()) {
-
756  mon = 1; // RULES is either '-' or 'hh:mm' so takes effect in Jan
-
757  deltaMinutes = era.deltaSeconds() / kSecPerMin;
-
758  transition.abbrev[0] = '\0';
-
759  } else {
-
760  mon = rule.inMonth();
-
761  deltaMinutes = rule.deltaSeconds() / kSecPerMin;
-
762  ace_common::strncpy_T(
-
763  transition.abbrev, rule.letter(), internal::kAbbrevSize - 1);
-
764  transition.abbrev[internal::kAbbrevSize - 1] = '\0';
+
487  return true;
+
488  }
+
489 
+
495  bool initForEpochSeconds(acetime_t epochSeconds) const {
+
496  LocalDate ld = LocalDate::forEpochSeconds(epochSeconds);
+
497  return initForLocalDate(ld);
+
498  }
+
499 
+
506  ZEB addTransitionPriorToYear(int16_t year) const {
+
507  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
+
508  logging::printf("addTransitionPriorToYear(): %d\n", year);
+
509  }
+
510 
+
511  const ZEB era = findZoneEra(mZoneInfoBroker, year - 1);
+
512 
+
513  // If the prior ZoneEra has a ZonePolicy), then find the latest rule
+
514  // within the ZoneEra. Otherwise, add a Transition using a rule==nullptr.
+
515  ZRB latest = findLatestPriorRule(era.zonePolicy(), year);
+
516  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
+
517  logging::printf("addTransitionsPriorToYear(): adding latest prior ");
+
518  if (latest.isNull()) {
+
519  logging::printf("ZR(null)\n");
+
520  } else {
+
521  logging::printf("ZR[%d,%d]\n", latest.fromYear(), latest.toYear());
+
522  }
+
523  }
+
524  addTransition(year - 1, 0 /*month*/, era, latest);
+
525 
+
526  return era;
+
527  }
+
528 
+
534  static ZRB findLatestPriorRule(const ZPB& zonePolicy, int16_t year) {
+
535  ZRB latest;
+
536  if (zonePolicy.isNull()) return latest;
+
537 
+
538  uint8_t numRules = zonePolicy.numRules();
+
539  for (uint8_t i = 0; i < numRules; i++) {
+
540  const ZRB rule = zonePolicy.rule(i);
+
541  // Check if rule is effective prior to the given year
+
542  if (rule.fromYear() < year) {
+
543  if ((latest.isNull()) ||
+
544  compareRulesBeforeYear(year, rule, latest) > 0) {
+
545  latest = rule;
+
546  }
+
547  }
+
548  }
+
549 
+
550  return latest;
+
551  }
+
552 
+
554  static int8_t compareRulesBeforeYear(
+
555  int16_t year, const ZRB& a, const ZRB& b) {
+
556  return basic::compareYearMonth(
+
557  priorYearOfRule(year, a), a.inMonth(),
+
558  priorYearOfRule(year, b), b.inMonth());
+
559  }
+
560 
+
569  static int16_t priorYearOfRule(int16_t year, const ZRB& rule) {
+
570  if (rule.toYear() < year) {
+
571  return rule.toYear();
+
572  }
+
573  return year - 1;
+
574  }
+
575 
+
580  ZEB addTransitionsForYear(int16_t year, const ZEB& priorEra) const {
+
581  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
+
582  logging::printf("addTransitionsForYear(): %d\n", year);
+
583  }
+
584 
+
585  const ZEB era = findZoneEra(mZoneInfoBroker, year);
+
586 
+
587  // If the ZonePolicy has no rules, then add a Transition which takes
+
588  // effect at the start time of the current year.
+
589  const ZPB zonePolicy = era.zonePolicy();
+
590  if (zonePolicy.isNull()) {
+
591  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
+
592  logging::printf("addTransitionsForYear(): adding ZE.untilY=%d\n",
+
593  era.untilYear());
+
594  }
+
595  addTransition(year, 0 /*month*/, era, ZRB());
+
596  return era;
+
597  }
+
598 
+
599  if (! era.equals(priorEra)) {
+
600  // The ZoneEra has changed, so we need to find the Rule in effect at
+
601  // the start of the current year of the current ZoneEra. This may be a
+
602  // rule far in the past, but shift the rule forward to {year, 1, 1}.
+
603  ZRB latestPrior = findLatestPriorRule(era.zonePolicy(), year);
+
604  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
+
605  logging::printf(
+
606  "addTransitionsForYear(): adding latest prior ");
+
607  if (latestPrior.isNull()) {
+
608  logging::printf("ZR(null)\n");
+
609  } else {
+
610  logging::printf("ZR[%d,%d]\n",
+
611  latestPrior.fromYear(), latestPrior.toYear());
+
612  }
+
613  }
+
614  addTransition(year, 1 /*month*/, era, latestPrior);
+
615  }
+
616 
+
617  // Find all directly matching transitions (i.e. the [from, to] overlap
+
618  // with the current year) and add them to mTransitions, in sorted order
+
619  // according to the ZoneRule::inMonth field.
+
620  uint8_t numRules = zonePolicy.numRules();
+
621  for (uint8_t i = 0; i < numRules; i++) {
+
622  const ZRB rule = zonePolicy.rule(i);
+
623  if ((rule.fromYear() <= year) && (year <= rule.toYear())) {
+
624  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
+
625  logging::printf(
+
626  "addTransitionsForYear(): adding rule ");
+
627  if (rule.isNull()) {
+
628  logging::printf("ZR(null)\n");
+
629  } else {
+
630  logging::printf("ZR[%d,%d]\n", rule.fromYear(), rule.toYear());
+
631  }
+
632  }
+
633  addTransition(year, 0 /*month*/, era, rule);
+
634  }
+
635  }
+
636 
+
637  return era;
+
638  }
+
639 
+
641  void addTransitionAfterYear(int16_t year, const ZEB& currentEra) const {
+
642  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
+
643  logging::printf("addTransitionAfterYear(): %d\n", year);
+
644  }
+
645 
+
646  const ZEB eraAfter = findZoneEra(mZoneInfoBroker, year + 1);
+
647 
+
648  // If the current era is the same as the following year, then we'll just
+
649  // assume that the latest ZoneRule carries over to Jan 1st of the next
+
650  // year. tzcompiler.py guarantees no ZoneRule occurs on Jan 1st.
+
651  if (currentEra.equals(eraAfter)) {
+
652  return;
+
653  }
+
654 
+
655  // If the ZoneEra did change, find the latest transition prior to
+
656  // {year + 1, 1, 1}, then shift that Transition to Jan 1st of the
+
657  // following year.
+
658  ZRB latest = findLatestPriorRule(eraAfter.zonePolicy(), year + 1);
+
659  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
+
660  logging::printf(
+
661  "addTransitionsAfterYear(): adding latest prior ");
+
662  if (latest.isNull()) {
+
663  logging::printf("ZR(null)\n");
+
664  } else {
+
665  logging::printf("ZR[%d,%d]\n", latest.fromYear(), latest.toYear());
+
666  }
+
667  }
+
668  addTransition(year + 1, 1 /*month*/, eraAfter, latest);
+
669  }
+
670 
+
694  void addTransition(int16_t year, uint8_t month, const ZEB& era,
+
695  const ZRB& rule) const {
+
696 
+
697  // If a zone needs more transitions than kMaxCacheEntries, the check below
+
698  // will cause the DST transition information to be inaccurate, and it is
+
699  // highly likely that this situation would be caught in the
+
700  // AceTimeValidation tests. Since these integration tests pass, I feel
+
701  // confident that those zones which need more than kMaxCacheEntries are
+
702  // already filtered out by tzcompiler.py.
+
703  //
+
704  // Ideally, the tzcompiler.py script would explicitly remove those zones
+
705  // which need more than kMaxCacheEntries Transitions. But this would
+
706  // require a Python version of the BasicZoneProcessor, and unfortunately,
+
707  // zone_processor.py implements only the ExtendedZoneProcessor algorithm
+
708  // An early version of zone_processor.py may have implemented something
+
709  // close to BasicZoneProcessor, and it may be available in the git
+
710  // history. But it seems like too much work right now to try to dig that
+
711  // out, just to implement the explicit check for kMaxCacheEntries. It
+
712  // would mean maintaining another version of zone_processor.py.
+
713  if (mNumTransitions >= kMaxCacheEntries) return;
+
714 
+
715  // Insert new element at the end of the list.
+
716  // NOTE: It is probably tempting to pass a pointer (or reference) to
+
717  // mTransitions[mNumTransitions] into createTransition(), instead of
+
718  // returning it by value. However, MemoryBenchmark shows that directly
+
719  // updating the Transition through the pointer increases flash memory
+
720  // consumption by ~110 bytes on AVR processors. It seems that creating a
+
721  // local copy of Transition on the stack, filling it, and then copying it
+
722  // by value takes fewer instructions.
+
723  mTransitions[mNumTransitions] = createTransition(year, month, era, rule);
+
724  mNumTransitions++;
+
725 
+
726  // perform an insertion sort based on ZoneRule.inMonth()
+
727  for (uint8_t i = mNumTransitions - 1; i > 0; i--) {
+
728  Transition& left = mTransitions[i - 1];
+
729  Transition& right = mTransitions[i];
+
730  // assume only 1 rule per month
+
731  if (basic::compareYearMonth(left.year, left.month,
+
732  right.year, right.month) > 0) {
+
733  Transition tmp = left;
+
734  left = right;
+
735  right = tmp;
+
736  }
+
737  }
+
738  }
+
739 
+
745  static Transition createTransition(int16_t year, uint8_t month,
+
746  const ZEB& era, const ZRB& rule) {
+
747 
+
748  Transition transition;
+
749  int16_t deltaMinutes;
+
750  uint8_t mon;
+
751  if (rule.isNull()) {
+
752  mon = 1; // RULES is either '-' or 'hh:mm' so takes effect in Jan
+
753  deltaMinutes = era.deltaSeconds() / kSecPerMin;
+
754  transition.abbrev[0] = '\0';
+
755  } else {
+
756  mon = rule.inMonth();
+
757  deltaMinutes = rule.deltaSeconds() / kSecPerMin;
+
758  ace_common::strncpy_T(
+
759  transition.abbrev, rule.letter(), internal::kAbbrevSize - 1);
+
760  transition.abbrev[internal::kAbbrevSize - 1] = '\0';
+
761  }
+
762  // Clobber the month if specified.
+
763  if (month != 0) {
+
764  mon = month;
765  }
-
766  // Clobber the month if specified.
-
767  if (month != 0) {
-
768  mon = month;
-
769  }
-
770  int16_t offsetMinutes = era.offsetSeconds() / kSecPerMin + deltaMinutes;
-
771 
-
772  transition.era = era;
-
773  transition.rule = rule;
-
774  transition.startEpochSeconds = 0;
-
775  transition.offsetMinutes = offsetMinutes;
-
776  transition.deltaMinutes = deltaMinutes;
-
777  transition.year = year;
-
778  transition.month = mon;
-
779  return transition;
-
780  }
-
781 
-
786  static ZEB findZoneEra(const ZIB& info, int16_t year) {
-
787  for (uint8_t i = 0; i < info.numEras(); i++) {
-
788  const ZEB era = info.era(i);
-
789  if (year < era.untilYear()) return era;
-
790  }
-
791  // Return the last ZoneEra if we run off the end.
-
792  return info.era(info.numEras() - 1);
-
793  }
-
794 
-
802  void calcTransitions() const {
-
803  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
-
804  logging::printf("calcTransitions():\n");
-
805  }
+
766  int16_t offsetMinutes = era.offsetSeconds() / kSecPerMin;
+
767 
+
768  transition.era = era;
+
769  transition.rule = rule;
+
770  transition.startEpochSeconds = 0;
+
771  transition.offsetMinutes = offsetMinutes;
+
772  transition.deltaMinutes = deltaMinutes;
+
773  transition.year = year;
+
774  transition.month = mon;
+
775  return transition;
+
776  }
+
777 
+
782  static ZEB findZoneEra(const ZIB& info, int16_t year) {
+
783  for (uint8_t i = 0; i < info.numEras(); i++) {
+
784  const ZEB era = info.era(i);
+
785  if (year < era.untilYear()) return era;
+
786  }
+
787  // Return the last ZoneEra if we run off the end.
+
788  return info.era(info.numEras() - 1);
+
789  }
+
790 
+
798  void calcTransitions() const {
+
799  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
+
800  logging::printf("calcTransitions():\n");
+
801  }
+
802 
+
803  // Set the initial startEpochSeconds to be -Infinity
+
804  Transition* prevTransition = &mTransitions[0];
+
805  prevTransition->startEpochSeconds = kMinEpochSeconds;
806 
-
807  // Set the initial startEpochSeconds to be -Infinity
-
808  Transition* prevTransition = &mTransitions[0];
-
809  prevTransition->startEpochSeconds = kMinEpochSeconds;
+
807  for (uint8_t i = 1; i < mNumTransitions; i++) {
+
808  Transition& transition = mTransitions[i];
+
809  const int16_t year = transition.year;
810 
-
811  for (uint8_t i = 1; i < mNumTransitions; i++) {
-
812  Transition& transition = mTransitions[i];
-
813  const int16_t year = transition.year;
-
814 
-
815  if (transition.rule.isNull()) {
-
816  // If the transition is simple (has no named rule), then the
-
817  // ZoneEra applies for the entire year (since BasicZoneProcessor
-
818  // supports only whole year in the UNTIL field). The whole year UNTIL
-
819  // field has an implied 'w' suffix on 00:00, we don't need to call
-
820  // calcRuleOffsetMinutes() with a 'w', we can just use the previous
-
821  // transition's offset to calculate the startDateTime of this
-
822  // transition.
-
823  //
-
824  // Also, when transition.rule == nullptr, the mNumTransitions should
-
825  // be 1, since only a single transition is added by
-
826  // addTransitionsForYear().
-
827  const int16_t prevOffsetMinutes = prevTransition->offsetMinutes;
-
828  OffsetDateTime startDateTime = OffsetDateTime::forComponents(
-
829  year, 1, 1, 0, 0, 0,
-
830  TimeOffset::forMinutes(prevOffsetMinutes));
-
831  transition.startEpochSeconds = startDateTime.toEpochSeconds();
-
832  } else {
-
833  // In this case, the transition points to a named ZonePolicy, which
-
834  // means that there could be multiple ZoneRules associated with the
-
835  // given year. For each transition, determine the startEpochSeconds,
-
836  // and the effective offset code.
-
837 
-
838  // Determine the start date of the rule.
-
839  const internal::MonthDay monthDay = internal::calcStartDayOfMonth(
-
840  year, transition.month, transition.rule.onDayOfWeek(),
-
841  transition.rule.onDayOfMonth());
-
842 
-
843  // Determine the offset of the 'atTimeSuffix'. The 'w' suffix
-
844  // requires the offset of the previous transition.
-
845  const int16_t prevOffsetMinutes = calcRuleOffsetMinutes(
-
846  prevTransition->offsetMinutes,
-
847  transition.era.offsetSeconds() / kSecPerMin,
-
848  transition.rule.atTimeSuffix());
-
849 
-
850  // startDateTime
-
851  const uint16_t minutes = transition.rule.atTimeSeconds() / 60;
-
852  const uint8_t atHour = minutes / 60;
-
853  const uint8_t atMinute = minutes % 60;
-
854  OffsetDateTime startDateTime = OffsetDateTime::forComponents(
-
855  year, monthDay.month, monthDay.day,
-
856  atHour, atMinute, 0 /*second*/,
-
857  TimeOffset::forMinutes(prevOffsetMinutes));
-
858  transition.startEpochSeconds = startDateTime.toEpochSeconds();
-
859  }
-
860 
-
861  prevTransition = &transition;
-
862  }
-
863  }
-
864 
-
871  static int16_t calcRuleOffsetMinutes(int16_t prevEffectiveOffsetMinutes,
-
872  int16_t currentBaseOffsetMinutes, uint8_t atSuffix) {
-
873  if (atSuffix == basic::ZoneContext::kSuffixW) {
-
874  return prevEffectiveOffsetMinutes;
-
875  } else if (atSuffix == basic::ZoneContext::kSuffixS) {
-
876  return currentBaseOffsetMinutes;
-
877  } else { // 'u', 'g' or 'z'
-
878  return 0;
-
879  }
-
880  }
-
881 
-
883  void calcAbbreviations() const {
-
884  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
-
885  logging::printf("calcAbbreviations():\n");
-
886  }
-
887 
-
888  for (uint8_t i = 0; i < mNumTransitions; i++) {
-
889  calcAbbreviation(&mTransitions[i]);
-
890  }
-
891  }
-
892 
-
894  static void calcAbbreviation(Transition* transition) {
-
895  internal::createAbbreviation(
-
896  transition->abbrev,
-
897  internal::kAbbrevSize,
-
898  transition->era.format(),
-
899  transition->deltaMinutes,
-
900  transition->abbrev);
-
901  }
-
902 
-
904  const Transition* findMatch(acetime_t epochSeconds) const {
-
905  const Transition* closestMatch = nullptr;
-
906  for (uint8_t i = 0; i < mNumTransitions; i++) {
-
907  const Transition* m = &mTransitions[i];
-
908  if (closestMatch == nullptr || m->startEpochSeconds <= epochSeconds) {
-
909  closestMatch = m;
-
910  }
-
911  }
-
912  return closestMatch;
-
913  }
+
811  if (transition.rule.isNull()) {
+
812  // If the transition is simple (has no named rule), then the
+
813  // ZoneEra applies for the entire year (since BasicZoneProcessor
+
814  // supports only whole year in the UNTIL field). The whole year UNTIL
+
815  // field has an implied 'w' suffix on 00:00, we don't need to call
+
816  // calcRuleOffsetMinutes() with a 'w', we can just use the previous
+
817  // transition's offset to calculate the startDateTime of this
+
818  // transition.
+
819  //
+
820  // Also, when transition.rule == nullptr, the mNumTransitions should
+
821  // be 1, since only a single transition is added by
+
822  // addTransitionsForYear().
+
823  const int16_t prevTotalOffsetMinutes = prevTransition->offsetMinutes
+
824  + prevTransition->deltaMinutes;
+
825  OffsetDateTime startDateTime = OffsetDateTime::forComponents(
+
826  year, 1, 1, 0, 0, 0,
+
827  TimeOffset::forMinutes(prevTotalOffsetMinutes));
+
828  transition.startEpochSeconds = startDateTime.toEpochSeconds();
+
829  } else {
+
830  // In this case, the transition points to a named ZonePolicy, which
+
831  // means that there could be multiple ZoneRules associated with the
+
832  // given year. For each transition, determine the startEpochSeconds,
+
833  // and the effective offset time.
+
834 
+
835  // Determine the start date of the rule.
+
836  const internal::MonthDay monthDay = internal::calcStartDayOfMonth(
+
837  year, transition.month, transition.rule.onDayOfWeek(),
+
838  transition.rule.onDayOfMonth());
+
839 
+
840  // Determine the offset of the 'atTimeSuffix'. The 'w' suffix
+
841  // requires the offset of the previous transition.
+
842  const int16_t prevTotalOffsetMinutes = calcRuleOffsetMinutes(
+
843  prevTransition->offsetMinutes + prevTransition->deltaMinutes,
+
844  transition.era.offsetSeconds() / kSecPerMin,
+
845  transition.rule.atTimeSuffix());
+
846 
+
847  // startDateTime
+
848  const uint16_t minutes = transition.rule.atTimeSeconds() / 60;
+
849  const uint8_t atHour = minutes / 60;
+
850  const uint8_t atMinute = minutes % 60;
+
851  OffsetDateTime startDateTime = OffsetDateTime::forComponents(
+
852  year, monthDay.month, monthDay.day,
+
853  atHour, atMinute, 0 /*second*/,
+
854  TimeOffset::forMinutes(prevTotalOffsetMinutes));
+
855  transition.startEpochSeconds = startDateTime.toEpochSeconds();
+
856  }
+
857 
+
858  prevTransition = &transition;
+
859  }
+
860  }
+
861 
+
868  static int16_t calcRuleOffsetMinutes(int16_t prevTotalOffsetMinutes,
+
869  int16_t currentBaseOffsetMinutes, uint8_t atSuffix) {
+
870  if (atSuffix == basic::ZoneContext::kSuffixW) {
+
871  return prevTotalOffsetMinutes;
+
872  } else if (atSuffix == basic::ZoneContext::kSuffixS) {
+
873  return currentBaseOffsetMinutes;
+
874  } else { // 'u', 'g' or 'z'
+
875  return 0;
+
876  }
+
877  }
+
878 
+
880  void calcAbbreviations() const {
+
881  if (ACE_TIME_BASIC_ZONE_PROCESSOR_DEBUG) {
+
882  logging::printf("calcAbbreviations():\n");
+
883  }
+
884 
+
885  for (uint8_t i = 0; i < mNumTransitions; i++) {
+
886  Transition* transition = &mTransitions[i];
+
887  internal::createAbbreviation(
+
888  transition->abbrev,
+
889  internal::kAbbrevSize,
+
890  transition->era.format(),
+
891  transition->offsetMinutes * kSecPerMin,
+
892  transition->deltaMinutes * kSecPerMin,
+
893  transition->abbrev);
+
894  }
+
895  }
+
896 
+
898  const Transition* findMatch(acetime_t epochSeconds) const {
+
899  const Transition* closestMatch = nullptr;
+
900  for (uint8_t i = 0; i < mNumTransitions; i++) {
+
901  const Transition* m = &mTransitions[i];
+
902  if (closestMatch == nullptr || m->startEpochSeconds <= epochSeconds) {
+
903  closestMatch = m;
+
904  }
+
905  }
+
906  return closestMatch;
+
907  }
+
908 
+
909  private:
+
910  static const int32_t kSecPerMin = 60;
+
911 
+
912  const ZIS* mZoneInfoStore; // nullable
+
913  ZIB mZoneInfoBroker;
914 
-
915  private:
-
916  static const int32_t kSecPerMin = 60;
-
917 
-
918  const ZIS* mZoneInfoStore; // nullable
-
919  ZIB mZoneInfoBroker;
-
920 
-
921  mutable uint8_t mNumTransitions = 0;
-
922  mutable Transition mTransitions[kMaxCacheEntries];
-
923 };
-
924 
-
929 class BasicZoneProcessor: public BasicZoneProcessorTemplate<
-
930  basic::ZoneInfoStore,
-
931  basic::ZoneInfoBroker,
-
932  basic::ZoneEraBroker,
-
933  basic::ZonePolicyBroker,
-
934  basic::ZoneRuleBroker> {
-
935 
-
936  public:
-
938  static const uint8_t kTypeBasic = 3;
-
939 
-
940  explicit BasicZoneProcessor(const basic::ZoneInfo* zoneInfo = nullptr)
-
941  : BasicZoneProcessorTemplate<
-
942  basic::ZoneInfoStore,
-
943  basic::ZoneInfoBroker,
-
944  basic::ZoneEraBroker,
-
945  basic::ZonePolicyBroker,
-
946  basic::ZoneRuleBroker>(
-
947  kTypeBasic, &mZoneInfoStore, (uintptr_t) zoneInfo)
-
948  {}
+
915  mutable uint8_t mNumTransitions = 0;
+
916  mutable Transition mTransitions[kMaxCacheEntries];
+
917 };
+
918 
+
923 class BasicZoneProcessor: public BasicZoneProcessorTemplate<
+
924  basic::ZoneInfoStore,
+
925  basic::ZoneInfoBroker,
+
926  basic::ZoneEraBroker,
+
927  basic::ZonePolicyBroker,
+
928  basic::ZoneRuleBroker> {
+
929 
+
930  public:
+
932  static const uint8_t kTypeBasic = 3;
+
933 
+
934  explicit BasicZoneProcessor(const basic::ZoneInfo* zoneInfo = nullptr)
+
935  : BasicZoneProcessorTemplate<
+
936  basic::ZoneInfoStore,
+
937  basic::ZoneInfoBroker,
+
938  basic::ZoneEraBroker,
+
939  basic::ZonePolicyBroker,
+
940  basic::ZoneRuleBroker>(
+
941  kTypeBasic, &mZoneInfoStore, (uintptr_t) zoneInfo)
+
942  {}
+
943 
+
944  private:
+
945  basic::ZoneInfoStore mZoneInfoStore;
+
946 };
+
947 
+
948 } // namespace ace_time
949 
-
950  private:
-
951  basic::ZoneInfoStore mZoneInfoStore;
-
952 };
-
953 
-
954 } // namespace ace_time
-
955 
-
956 #endif
-
ace_time::BasicZoneProcessorTemplate
An implementation of ZoneProcessor that supports a subset of the zones containing in the TZ Database.
Definition: BasicZoneProcessor.h:203
-
ace_time::BasicZoneProcessorTemplate::isLink
bool isLink() const override
Return true if timezone is a Link entry pointing to a Zone entry.
Definition: BasicZoneProcessor.h:208
-
ace_time::BasicZoneProcessorTemplate::Transition
basic::TransitionTemplate< ZIB, ZEB, ZPB, ZRB > Transition
Exposed only for testing purposes.
Definition: BasicZoneProcessor.h:206
-
ace_time::BasicZoneProcessorTemplate::setZoneKey
void setZoneKey(uintptr_t zoneKey) override
Set the opaque zoneKey of this object to a new value, reseting any internally cached information.
Definition: BasicZoneProcessor.h:326
-
ace_time::BasicZoneProcessorTemplate::printNameTo
void printNameTo(Print &printer) const override
Print a human-readable identifier (e.g.
Definition: BasicZoneProcessor.h:312
-
ace_time::BasicZoneProcessorTemplate::findByEpochSeconds
FindResult findByEpochSeconds(acetime_t epochSeconds) const override
Return the search results at given epochSeconds.
Definition: BasicZoneProcessor.h:296
-
ace_time::BasicZoneProcessorTemplate::setZoneInfoStore
void setZoneInfoStore(const ZIS *zoneInfoStore)
Set the zone info store at runtime.
Definition: BasicZoneProcessor.h:359
-
ace_time::BasicZoneProcessorTemplate::log
void log() const
Used only for debugging.
Definition: BasicZoneProcessor.h:340
-
ace_time::BasicZoneProcessorTemplate::BasicZoneProcessorTemplate
BasicZoneProcessorTemplate(uint8_t type, const ZIS *zoneInfoStore, uintptr_t zoneKey)
Constructor.
Definition: BasicZoneProcessor.h:375
-
ace_time::BasicZoneProcessorTemplate::printShortNameTo
void printShortNameTo(Print &printer) const override
Print a short human-readable identifier (e.g.
Definition: BasicZoneProcessor.h:316
-
ace_time::BasicZoneProcessorTemplate::equalsZoneKey
bool equalsZoneKey(uintptr_t zoneKey) const override
Return true if ZoneProcessor is associated with the given opaque zoneKey.
Definition: BasicZoneProcessor.h:335
-
ace_time::BasicZoneProcessorTemplate::findByLocalDateTime
FindResult findByLocalDateTime(const LocalDateTime &ldt) const override
Return the search results at given LocalDateTime.
Definition: BasicZoneProcessor.h:244
-
ace_time::BasicZoneProcessorTemplate::getZoneId
uint32_t getZoneId() const override
Return the unique stable zoneId.
Definition: BasicZoneProcessor.h:212
-
ace_time::BasicZoneProcessorTemplate::printTargetNameTo
void printTargetNameTo(Print &printer) const override
Print the full identifier (e.g.
Definition: BasicZoneProcessor.h:320
-
ace_time::BasicZoneProcessor
A specific implementation of BasicZoneProcessorTemplate that uses ZoneXxxBrokers which read from zone...
Definition: BasicZoneProcessor.h:934
-
ace_time::BasicZoneProcessor::kTypeBasic
static const uint8_t kTypeBasic
Unique TimeZone type identifier for BasicZoneProcessor.
Definition: BasicZoneProcessor.h:938
+
950 #endif
+
ace_time::BasicZoneProcessorTemplate
An implementation of ZoneProcessor that supports a subset of the zones containing in the TZ Database.
Definition: BasicZoneProcessor.h:201
+
ace_time::BasicZoneProcessorTemplate::isLink
bool isLink() const override
Return true if timezone is a Link entry pointing to a Zone entry.
Definition: BasicZoneProcessor.h:206
+
ace_time::BasicZoneProcessorTemplate::Transition
basic::TransitionTemplate< ZIB, ZEB, ZPB, ZRB > Transition
Exposed only for testing purposes.
Definition: BasicZoneProcessor.h:204
+
ace_time::BasicZoneProcessorTemplate::setZoneKey
void setZoneKey(uintptr_t zoneKey) override
Set the opaque zoneKey of this object to a new value, reseting any internally cached information.
Definition: BasicZoneProcessor.h:323
+
ace_time::BasicZoneProcessorTemplate::printNameTo
void printNameTo(Print &printer) const override
Print a human-readable identifier (e.g.
Definition: BasicZoneProcessor.h:309
+
ace_time::BasicZoneProcessorTemplate::findByEpochSeconds
FindResult findByEpochSeconds(acetime_t epochSeconds) const override
Return the search results at given epochSeconds.
Definition: BasicZoneProcessor.h:294
+
ace_time::BasicZoneProcessorTemplate::setZoneInfoStore
void setZoneInfoStore(const ZIS *zoneInfoStore)
Set the zone info store at runtime.
Definition: BasicZoneProcessor.h:356
+
ace_time::BasicZoneProcessorTemplate::log
void log() const
Used only for debugging.
Definition: BasicZoneProcessor.h:337
+
ace_time::BasicZoneProcessorTemplate::BasicZoneProcessorTemplate
BasicZoneProcessorTemplate(uint8_t type, const ZIS *zoneInfoStore, uintptr_t zoneKey)
Constructor.
Definition: BasicZoneProcessor.h:372
+
ace_time::BasicZoneProcessorTemplate::printShortNameTo
void printShortNameTo(Print &printer) const override
Print a short human-readable identifier (e.g.
Definition: BasicZoneProcessor.h:313
+
ace_time::BasicZoneProcessorTemplate::equalsZoneKey
bool equalsZoneKey(uintptr_t zoneKey) const override
Return true if ZoneProcessor is associated with the given opaque zoneKey.
Definition: BasicZoneProcessor.h:332
+
ace_time::BasicZoneProcessorTemplate::findByLocalDateTime
FindResult findByLocalDateTime(const LocalDateTime &ldt) const override
Return the search results at given LocalDateTime.
Definition: BasicZoneProcessor.h:242
+
ace_time::BasicZoneProcessorTemplate::getZoneId
uint32_t getZoneId() const override
Return the unique stable zoneId.
Definition: BasicZoneProcessor.h:210
+
ace_time::BasicZoneProcessorTemplate::printTargetNameTo
void printTargetNameTo(Print &printer) const override
Print the full identifier (e.g.
Definition: BasicZoneProcessor.h:317
+
ace_time::BasicZoneProcessor
A specific implementation of BasicZoneProcessorTemplate that uses ZoneXxxBrokers which read from zone...
Definition: BasicZoneProcessor.h:928
+
ace_time::BasicZoneProcessor::kTypeBasic
static const uint8_t kTypeBasic
Unique TimeZone type identifier for BasicZoneProcessor.
Definition: BasicZoneProcessor.h:932
ace_time::Epoch::currentEpochYear
static int16_t currentEpochYear()
Get the current epoch year.
Definition: Epoch.h:27
ace_time::FindResult
Result of a search for transition at a specific epochSeconds or a specific LocalDateTime.
Definition: ZoneProcessor.h:23
ace_time::FindResult::stdOffsetSeconds
int32_t stdOffsetSeconds
STD offset of the resulting OffsetDateTime.
Definition: ZoneProcessor.h:79
@@ -783,19 +779,19 @@
ace_time::zoneinfolow::ZoneInfoStore< ZoneContext, ZoneInfo, ZoneEra, ZonePolicy, ZoneRule >
common.h
Identifiers used by implementation code which need to be publically exported.
ace_time::acetime_t
int32_t acetime_t
Type for the number of seconds from epoch.
Definition: common.h:24
-
ace_time::basic::TransitionTemplate
Data structure that defines the start of a specific UTC offset as described by the matching ZoneEra a...
Definition: BasicZoneProcessor.h:60
-
ace_time::basic::TransitionTemplate::month
uint8_t month
Month of the transition.
Definition: BasicZoneProcessor.h:100
-
ace_time::basic::TransitionTemplate::startEpochSeconds
acetime_t startEpochSeconds
The calculated transition time of the given rule.
Definition: BasicZoneProcessor.h:80
-
ace_time::basic::TransitionTemplate::rule
ZRB rule
The Zone transition rule that matched for the the given year.
Definition: BasicZoneProcessor.h:77
-
ace_time::basic::TransitionTemplate::era
ZEB era
The ZoneEra that matched the given year.
Definition: BasicZoneProcessor.h:66
-
ace_time::basic::TransitionTemplate::log
void log() const
Used only for debugging.
Definition: BasicZoneProcessor.h:112
-
ace_time::basic::TransitionTemplate::year
int16_t year
Year of the Transition.
Definition: BasicZoneProcessor.h:93
-
ace_time::basic::TransitionTemplate::offsetMinutes
int16_t offsetMinutes
The total effective UTC offset minutes at the start of transition, including DST offset.
Definition: BasicZoneProcessor.h:87
-
ace_time::basic::TransitionTemplate::abbrev
char abbrev[internal::kAbbrevSize]
The calculated effective time zone abbreviation, e.g.
Definition: BasicZoneProcessor.h:109
-
ace_time::basic::TransitionTemplate::deltaMinutes
int16_t deltaMinutes
The deltaMinutes from "standard time" at the start of transition.
Definition: BasicZoneProcessor.h:90
-
ace_time::zoneinfolow::ZoneContext::kSuffixS
static const uint8_t kSuffixS
Represents 's' or standard time.
Definition: ZoneInfoLow.h:65
-
ace_time::zoneinfolow::ZoneContext::kSuffixW
static const uint8_t kSuffixW
Represents 'w' or wall time.
Definition: ZoneInfoLow.h:62
-
ace_time::zoneinfolow::ZoneInfo
Representation of a given time zone, implemented as an array of ZoneEra records.
Definition: ZoneInfoLow.h:302
+
ace_time::basic::TransitionTemplate
Data structure that defines the start of a specific UTC offset as described by the matching ZoneEra a...
Definition: BasicZoneProcessor.h:59
+
ace_time::basic::TransitionTemplate::month
uint8_t month
Month of the transition.
Definition: BasicZoneProcessor.h:98
+
ace_time::basic::TransitionTemplate::startEpochSeconds
acetime_t startEpochSeconds
The calculated transition time of the given rule.
Definition: BasicZoneProcessor.h:79
+
ace_time::basic::TransitionTemplate::rule
ZRB rule
The Zone transition rule that matched for the the given year.
Definition: BasicZoneProcessor.h:76
+
ace_time::basic::TransitionTemplate::era
ZEB era
The ZoneEra that matched the given year.
Definition: BasicZoneProcessor.h:65
+
ace_time::basic::TransitionTemplate::log
void log() const
Used only for debugging.
Definition: BasicZoneProcessor.h:110
+
ace_time::basic::TransitionTemplate::year
int16_t year
Year of the Transition.
Definition: BasicZoneProcessor.h:91
+
ace_time::basic::TransitionTemplate::offsetMinutes
int16_t offsetMinutes
The standard time offset minutes at the start of transition, not including DST offset.
Definition: BasicZoneProcessor.h:85
+
ace_time::basic::TransitionTemplate::abbrev
char abbrev[internal::kAbbrevSize]
The calculated effective time zone abbreviation, e.g.
Definition: BasicZoneProcessor.h:107
+
ace_time::basic::TransitionTemplate::deltaMinutes
int16_t deltaMinutes
The deltaMinutes from "standard time" at the start of transition.
Definition: BasicZoneProcessor.h:88
+
ace_time::zoneinfolow::ZoneContext::kSuffixS
static const uint8_t kSuffixS
Represents 's' or standard time.
Definition: ZoneInfoLow.h:83
+
ace_time::zoneinfolow::ZoneContext::kSuffixW
static const uint8_t kSuffixW
Represents 'w' or wall time.
Definition: ZoneInfoLow.h:80
+
ace_time::zoneinfolow::ZoneInfo
Representation of a given time zone, implemented as an array of ZoneEra records.
Definition: ZoneInfoLow.h:320