6 #ifndef ACE_TIME_EXTENDED_ZONE_PROCESSOR_H
7 #define ACE_TIME_EXTENDED_ZONE_PROCESSOR_H
11 #include <AceCommon.h>
14 #include "internal/ZonePolicy.h"
15 #include "internal/ZoneInfo.h"
17 #include "common/logging.h"
18 #include "TimeOffset.h"
19 #include "LocalDate.h"
20 #include "ZoneProcessor.h"
21 #include "Transition.h"
23 #ifndef ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG
24 #define ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG 0
27 class ExtendedZoneProcessorTest_compareEraToYearMonth;
28 class ExtendedZoneProcessorTest_compareEraToYearMonth2;
29 class ExtendedZoneProcessorTest_createMatchingEra;
30 class ExtendedZoneProcessorTest_findMatches_simple;
31 class ExtendedZoneProcessorTest_findMatches_named;
32 class ExtendedZoneProcessorTest_findCandidateTransitions;
33 class ExtendedZoneProcessorTest_createTransitionsFromNamedMatch;
34 class ExtendedZoneProcessorTest_getTransitionTime;
35 class ExtendedZoneProcessorTest_createTransitionForYear;
36 class ExtendedZoneProcessorTest_normalizeDateTuple;
37 class ExtendedZoneProcessorTest_expandDateTuple;
38 class ExtendedZoneProcessorTest_calcInteriorYears;
39 class ExtendedZoneProcessorTest_getMostRecentPriorYear;
40 class ExtendedZoneProcessorTest_compareTransitionToMatchFuzzy;
41 class ExtendedZoneProcessorTest_compareTransitionToMatch;
42 class ExtendedZoneProcessorTest_processTransitionMatchStatus;
43 class ExtendedZoneProcessorTest_fixTransitionTimes_generateStartUntilTimes;
44 class ExtendedZoneProcessorTest_createAbbreviation;
45 class ExtendedZoneProcessorTest_setZoneKey;
46 class ExtendedTransitionValidation;
93 template <
typename BF,
typename ZIB,
typename ZEB,
typename ZPB,
typename ZRB>
127 return ! mZoneInfoBroker.targetInfo().isNull();
131 return mZoneInfoBroker.zoneId();
149 if (transitionForDateTime.
num == 1) {
150 transition = transitionForDateTime.
curr;
151 result.
type = FindResult::kTypeExact;
155 if (transitionForDateTime.
prev ==
nullptr
156 || transitionForDateTime.
curr ==
nullptr) {
158 transition =
nullptr;
159 result.
type = FindResult::kTypeNotFound;
161 if (transitionForDateTime.
num == 0) {
162 result.
type = FindResult::kTypeGap;
163 if (ldt.
fold() == 0) {
167 transitionForDateTime.
prev->offsetMinutes;
169 transitionForDateTime.
prev->deltaMinutes;
172 transition = transitionForDateTime.
curr;
177 transitionForDateTime.
curr->offsetMinutes;
179 transitionForDateTime.
curr->deltaMinutes;
182 transition = transitionForDateTime.
prev;
185 transition = (ldt.
fold() == 0)
186 ? transitionForDateTime.
prev
187 : transitionForDateTime.
curr;
188 result.
type = FindResult::kTypeOverlap;
218 if (!success)
return result;
223 if (!transition)
return result;
230 result.
fold = transitionForSeconds.
fold;
231 if (transitionForSeconds.
num == 2) {
232 result.
type = FindResult::kTypeOverlap;
234 result.
type = FindResult::kTypeExact;
240 mZoneInfoBroker.printNameTo(printer);
244 mZoneInfoBroker.printShortNameTo(printer);
249 mZoneInfoBroker.targetInfo().printNameTo(printer);
255 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
256 logging::printf(
"ExtendedZoneProcessor:\n");
257 logging::printf(
" mYear: %d\n", mYear);
258 logging::printf(
" mNumMatches: %d\n", mNumMatches);
259 for (
int i = 0; i < mNumMatches; i++) {
260 logging::printf(
" Match %d: ", i);
262 logging::printf(
"\n");
264 mTransitionStorage.
log();
279 if (! mBrokerFactory)
return;
280 if (mZoneInfoBroker.equals(zoneKey))
return;
282 mZoneInfoBroker = mBrokerFactory->createZoneInfoBroker(zoneKey);
290 return mZoneInfoBroker.equals(zoneKey);
300 mBrokerFactory = brokerFactory;
320 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
321 logging::printf(
"initForYear(): %d\n", year);
326 mTransitionStorage.
init();
328 if (year < mZoneInfoBroker.zoneContext()->startYear - 1
329 || mZoneInfoBroker.zoneContext()->untilYear < year) {
330 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
332 "initForYear(): Year %d out of valid range [%d, %d)\n",
334 mZoneInfoBroker.zoneContext()->startYear,
335 mZoneInfoBroker.zoneContext()->untilYear);
346 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
347 logging::printf(
"==== Step 1: findMatches()\n");
349 mNumMatches = findMatches(mZoneInfoBroker, startYm, untilYm, mMatches,
351 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
log(); }
354 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
355 logging::printf(
"==== Step 2: createTransitions()\n");
357 createTransitions(mTransitionStorage, mMatches, mNumMatches);
358 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
log(); }
361 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
362 logging::printf(
"==== Step 3: fixTransitionTimes()\n");
364 Transition** begin = mTransitionStorage.getActivePoolBegin();
365 Transition** end = mTransitionStorage.getActivePoolEnd();
366 fixTransitionTimes(begin, end);
367 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
log(); }
370 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
371 logging::printf(
"==== Step 4: generateStartUntilTimes()\n");
373 generateStartUntilTimes(begin, end);
374 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
log(); }
377 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
378 logging::printf(
"==== Step 5: calcAbbreviations()\n");
380 calcAbbreviations(begin, end);
381 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
log(); }
400 const BF* brokerFactory ,
404 mBrokerFactory(brokerFactory)
410 friend class ::ExtendedZoneProcessorTest_compareEraToYearMonth;
411 friend class ::ExtendedZoneProcessorTest_compareEraToYearMonth2;
412 friend class ::ExtendedZoneProcessorTest_createMatchingEra;
413 friend class ::ExtendedZoneProcessorTest_findMatches_simple;
414 friend class ::ExtendedZoneProcessorTest_findMatches_named;
415 friend class ::ExtendedZoneProcessorTest_findCandidateTransitions;
416 friend class ::ExtendedZoneProcessorTest_createTransitionsFromNamedMatch;
417 friend class ::ExtendedZoneProcessorTest_getTransitionTime;
418 friend class ::ExtendedZoneProcessorTest_createTransitionForYear;
419 friend class ::ExtendedZoneProcessorTest_normalizeDateTuple;
420 friend class ::ExtendedZoneProcessorTest_expandDateTuple;
421 friend class ::ExtendedZoneProcessorTest_calcInteriorYears;
422 friend class ::ExtendedZoneProcessorTest_getMostRecentPriorYear;
423 friend class ::ExtendedZoneProcessorTest_compareTransitionToMatchFuzzy;
424 friend class ::ExtendedZoneProcessorTest_compareTransitionToMatch;
425 friend class ::ExtendedZoneProcessorTest_processTransitionMatchStatus;
426 friend class ::ExtendedZoneProcessorTest_fixTransitionTimes_generateStartUntilTimes;
427 friend class ::ExtendedZoneProcessorTest_createAbbreviation;
428 friend class ::ExtendedZoneProcessorTest_setZoneKey;
429 friend class ::ExtendedTransitionValidation;
441 static const uint8_t kMaxMatches = 4;
447 static const uint8_t kMaxInteriorYears = 4;
450 return mZoneInfoBroker.equals(
461 static uint8_t findMatches(
463 const extended::YearMonthTuple& startYm,
464 const extended::YearMonthTuple& untilYm,
468 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
469 logging::printf(
"findMatches()\n");
473 for (uint8_t iEra = 0; iEra < zoneInfo.numEras(); iEra++) {
474 const ZEB era = zoneInfo.era(iEra);
475 if (eraOverlapsInterval(prevMatch, era, startYm, untilYm)) {
476 if (iMatch < maxMatches) {
477 matches[iMatch] = createMatchingEra(
478 prevMatch, era, startYm, untilYm);
479 prevMatch = &matches[iMatch];
498 static bool eraOverlapsInterval(
501 const extended::YearMonthTuple& startYm,
502 const extended::YearMonthTuple& untilYm) {
503 return (prevMatch ==
nullptr || compareEraToYearMonth(
504 prevMatch->era, untilYm.year, untilYm.month) < 0)
505 && compareEraToYearMonth(era, startYm.year, startYm.month) > 0;
509 static int8_t compareEraToYearMonth(
const ZEB& era,
510 int16_t year, uint8_t month) {
511 if (era.untilYear() < year)
return -1;
512 if (era.untilYear() > year)
return 1;
513 if (era.untilMonth() < month)
return -1;
514 if (era.untilMonth() > month)
return 1;
515 if (era.untilDay() > 1)
return 1;
517 if (era.untilTimeMinutes() > 0)
return 1;
530 const extended::YearMonthTuple& startYm,
531 const extended::YearMonthTuple& untilYm) {
535 extended::DateTuple startDate = (prevMatch ==
nullptr)
536 ? extended::DateTuple{
543 : extended::DateTuple{
544 prevMatch->era.untilYear(),
545 prevMatch->era.untilMonth(),
546 prevMatch->era.untilDay(),
547 (int16_t) prevMatch->era.untilTimeMinutes(),
548 prevMatch->era.untilTimeSuffix()
550 extended::DateTuple lowerBound{
557 if (startDate < lowerBound) {
558 startDate = lowerBound;
561 extended::DateTuple untilDate{
565 (int16_t) era.untilTimeMinutes(),
566 era.untilTimeSuffix()
568 extended::DateTuple upperBound{
575 if (upperBound < untilDate) {
576 untilDate = upperBound;
579 return {startDate, untilDate, era, prevMatch, 0, 0};
586 static void createTransitions(
589 uint8_t numMatches) {
590 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
591 logging::printf(
"createTransitions()\n");
594 for (uint8_t i = 0; i < numMatches; i++) {
595 createTransitionsForMatch(transitionStorage, &matches[i]);
600 static void createTransitionsForMatch(
603 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
604 logging::printf(
"== createTransitionsForMatch()\n");
606 const ZPB policy = match->era.zonePolicy();
607 if (policy.isNull()) {
608 createTransitionsFromSimpleMatch(transitionStorage, match);
610 createTransitionsFromNamedMatch(transitionStorage, match);
615 static void createTransitionsFromSimpleMatch(
618 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
619 logging::printf(
"== createTransitionsFromSimpleMatch()\n");
622 Transition* freeTransition = transitionStorage.getFreeAgent();
623 createTransitionForYear(freeTransition, 0 ,
625 freeTransition->matchStatus = extended::MatchStatus::kExactMatch;
626 match->lastOffsetMinutes = freeTransition->offsetMinutes;
627 match->lastDeltaMinutes = freeTransition->deltaMinutes;
628 transitionStorage.addFreeAgentToActivePool();
629 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
630 transitionStorage.log();
635 static void createTransitionsFromNamedMatch(
638 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
639 logging::printf(
"== createTransitionsFromNamedMatch()\n");
642 transitionStorage.resetCandidatePool();
643 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
644 match->log(); logging::printf(
"\n");
648 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
649 logging::printf(
"---- Pass 1: findCandidateTransitions()\n");
651 findCandidateTransitions(transitionStorage, match);
652 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
653 transitionStorage.log();
658 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
659 logging::printf(
"---- Pass 2: fixTransitionTimes()\n");
662 transitionStorage.getCandidatePoolBegin(),
663 transitionStorage.getCandidatePoolEnd());
667 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
668 logging::printf(
"---- Pass 3: selectActiveTransitions()\n");
670 selectActiveTransitions(
671 transitionStorage.getCandidatePoolBegin(),
672 transitionStorage.getCandidatePoolEnd());
673 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
674 transitionStorage.log();
677 transitionStorage.addActiveCandidatesToActivePool();
678 match->lastOffsetMinutes = lastTransition->offsetMinutes;
679 match->lastDeltaMinutes = lastTransition->deltaMinutes;
680 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
681 transitionStorage.log();
686 static void findCandidateTransitions(
689 using extended::MatchStatus;
691 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
692 logging::printf(
"findCandidateTransitions(): \n");
694 logging::printf(
"\n");
696 const ZPB policy = match->era.zonePolicy();
697 uint8_t numRules = policy.numRules();
698 int16_t startY = match->startDateTime.year;
699 int16_t endY = match->untilDateTime.year;
704 Transition** prior = transitionStorage.reservePrior();
705 (*prior)->isValidPrior =
false;
706 for (uint8_t r = 0; r < numRules; r++) {
707 const ZRB rule = policy.rule(r);
710 int16_t interiorYears[kMaxInteriorYears];
711 uint8_t numYears = calcInteriorYears(interiorYears, kMaxInteriorYears,
712 rule.fromYear(), rule.toYear(), startY, endY);
713 for (uint8_t y = 0; y < numYears; y++) {
714 int16_t year = interiorYears[y];
715 Transition* t = transitionStorage.getFreeAgent();
716 createTransitionForYear(t, year, rule, match);
717 MatchStatus status = compareTransitionToMatchFuzzy(t, match);
718 if (status == MatchStatus::kPrior) {
719 transitionStorage.setFreeAgentAsPriorIfValid();
720 }
else if (status == MatchStatus::kWithinMatch) {
721 transitionStorage.addFreeAgentToCandidatePool();
729 int16_t priorYear = getMostRecentPriorYear(
730 rule.fromYear(), rule.toYear(), startY, endY);
732 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
734 "findCandidateTransitions(): priorYear: %d\n", priorYear);
736 Transition* t = transitionStorage.getFreeAgent();
737 createTransitionForYear(t, priorYear, rule, match);
738 transitionStorage.setFreeAgentAsPriorIfValid();
744 if ((*prior)->isValidPrior) {
745 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
747 "findCandidateTransitions(): adding prior to Candidate pool\n");
748 logging::printf(
" ");
750 logging::printf(
"\n");
752 transitionStorage.addPriorToCandidatePool();
775 static uint8_t calcInteriorYears(
776 int16_t* interiorYears,
777 uint8_t maxInteriorYears,
778 int16_t fromYear, int16_t toYear,
779 int16_t startYear, int16_t endYear) {
781 for (int16_t year = startYear; year <= endYear; year++) {
782 if (fromYear <= year && year <= toYear) {
783 interiorYears[i] = year;
785 if (i >= maxInteriorYears)
break;
797 static void createTransitionForYear(
804 t->offsetMinutes = match->era.offsetMinutes();
805 t->letterBuf[0] =
'\0';
807 if (! rule.isNull()) {
808 t->transitionTime = getTransitionTime(year, rule);
809 t->deltaMinutes = rule.deltaMinutes();
811 char letter = rule.letter();
815 t->letterBuf[0] = letter;
816 t->letterBuf[1] =
'\0';
826 t->transitionTime = match->startDateTime;
827 t->deltaMinutes = match->era.deltaMinutes();
843 static int16_t getMostRecentPriorYear(
844 int16_t fromYear, int16_t toYear,
845 int16_t startYear, int16_t ) {
847 if (fromYear < startYear) {
848 if (toYear < startYear) {
851 return startYear - 1;
862 static extended::DateTuple getTransitionTime(
863 int16_t year,
const ZRB& rule) {
865 internal::MonthDay monthDay = internal::calcStartDayOfMonth(
869 rule.onDayOfMonth());
874 (int16_t) rule.atTimeMinutes(),
889 static extended::MatchStatus compareTransitionToMatchFuzzy(
891 return compareDateTupleFuzzy(
893 match->startDateTime,
894 match->untilDateTime);
906 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
907 logging::printf(
"fixTransitionTimes(): START; #transitions=%d\n",
908 (
int) (end - begin));
915 for (
Transition** iter = begin; iter != end; ++iter) {
918 &curr->transitionTime,
921 &curr->transitionTime,
922 &curr->transitionTimeS,
923 &curr->transitionTimeU);
926 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
927 logging::printf(
"fixTransitionTimes(): FIXED\n");
929 logging::printf(
"fixTransitionTimes(): END\n");
938 static void expandDateTuple(
939 const extended::DateTuple* tt,
940 int16_t offsetMinutes,
941 int16_t deltaMinutes,
942 extended::DateTuple* ttw,
943 extended::DateTuple* tts,
944 extended::DateTuple* ttu) {
948 *ttu = {tt->year, tt->month, tt->day,
949 (int16_t) (tt->minutes - offsetMinutes),
951 *ttw = {tt->year, tt->month, tt->day,
952 (int16_t) (tt->minutes + deltaMinutes),
956 *tts = {tt->year, tt->month, tt->day,
957 (int16_t) (tt->minutes + offsetMinutes),
959 *ttw = {tt->year, tt->month, tt->day,
960 (int16_t) (tt->minutes + (offsetMinutes + deltaMinutes)),
966 *tts = {tt->year, tt->month, tt->day,
967 (int16_t) (tt->minutes - deltaMinutes),
969 *ttu = {tt->year, tt->month, tt->day,
970 (int16_t) (tt->minutes - (deltaMinutes + offsetMinutes)),
974 extended::normalizeDateTuple(ttw);
975 extended::normalizeDateTuple(tts);
976 extended::normalizeDateTuple(ttu);
984 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
985 logging::printf(
"selectActiveTransitions(): #candidates: %d\n",
986 (
int) (end - begin));
990 for (
Transition** iter = begin; iter != end; ++iter) {
992 processTransitionMatchStatus(transition, &prior);
998 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
1000 "selectActiveTransitions(): found latest prior\n");
1002 #if ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG
1003 prior->originalTransitionTime = prior->transitionTime;
1005 prior->transitionTime = prior->match->startDateTime;
1015 static void processTransitionMatchStatus(
1018 using extended::MatchStatus;
1020 MatchStatus status = compareTransitionToMatch(
1021 transition, transition->match);
1022 transition->matchStatus = status;
1024 if (status == MatchStatus::kExactMatch) {
1026 (*prior)->matchStatus = MatchStatus::kFarPast;
1028 (*prior) = transition;
1029 }
else if (status == MatchStatus::kPrior) {
1031 if ((*prior)->transitionTimeU <= transition->transitionTimeU) {
1032 (*prior)->matchStatus = MatchStatus::kFarPast;
1033 (*prior) = transition;
1035 transition->matchStatus = MatchStatus::kFarPast;
1038 (*prior) = transition;
1051 static extended::MatchStatus compareTransitionToMatch(
1056 int16_t prevMatchOffsetMinutes;
1057 int16_t prevMatchDeltaMinutes;
1058 if (match->prevMatch) {
1059 prevMatchOffsetMinutes = match->prevMatch->lastOffsetMinutes;
1060 prevMatchDeltaMinutes = match->prevMatch->lastDeltaMinutes;
1062 prevMatchOffsetMinutes = match->era.offsetMinutes();
1063 prevMatchDeltaMinutes = 0;
1067 extended::DateTuple stw;
1068 extended::DateTuple sts;
1069 extended::DateTuple stu;
1071 &match->startDateTime,
1072 prevMatchOffsetMinutes,
1073 prevMatchDeltaMinutes,
1079 const extended::DateTuple& ttw = transition->transitionTime;
1080 const extended::DateTuple& tts = transition->transitionTimeS;
1081 const extended::DateTuple& ttu = transition->transitionTimeU;
1086 if (ttw == stw || tts == sts || ttu == stu) {
1087 return extended::MatchStatus::kExactMatch;
1091 return extended::MatchStatus::kPrior;
1099 const extended::DateTuple& matchUntil = match->untilDateTime;
1100 const extended::DateTuple* transitionTime;
1102 transitionTime = &tts;
1104 transitionTime = &ttu;
1106 transitionTime = &ttw;
1108 if (*transitionTime < matchUntil) {
1109 return extended::MatchStatus::kWithinMatch;
1111 return extended::MatchStatus::kFarFuture;
1120 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
1122 "generateStartUntilTimes(): #transitions=%d\n",
1123 (
int) (end - begin));
1128 if (begin == end)
return;
1131 bool isAfterFirst =
false;
1133 for (
Transition** iter = begin; iter != end; ++iter) {
1137 const extended::DateTuple& tt = t->transitionTime;
1139 prev->untilDateTime = tt;
1145 int16_t minutes = tt.minutes + (
1146 - prev->offsetMinutes - prev->deltaMinutes
1147 + t->offsetMinutes + t->deltaMinutes);
1148 t->startDateTime = {tt.year, tt.month, tt.day, minutes, tt.suffix};
1149 extended::normalizeDateTuple(&t->startDateTime);
1161 const extended::DateTuple& st = t->startDateTime;
1163 * (st.minutes - (t->offsetMinutes + t->deltaMinutes));
1165 t->startEpochSeconds = ld.toEpochSeconds() + offsetSeconds;
1168 isAfterFirst =
true;
1172 extended::DateTuple untilTimeW;
1173 extended::DateTuple untilTimeS;
1174 extended::DateTuple untilTimeU;
1176 &prev->match->untilDateTime,
1177 prev->offsetMinutes,
1182 prev->untilDateTime = untilTimeW;
1189 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
1190 logging::printf(
"calcAbbreviations(): #transitions: %d\n",
1191 (
int) (end - begin));
1193 for (
Transition** iter = begin; iter != end; ++iter) {
1195 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
1197 "calcAbbreviations(): format:%s, deltaMinutes:%d, letter:%s\n",
1198 t->format(), t->deltaMinutes, t->letter());
1202 internal::kAbbrevSize,
1217 static void createAbbreviation(
1221 uint16_t deltaMinutes,
1222 const char* letterString) {
1225 if (strchr(format,
'%') !=
nullptr) {
1227 if (letterString ==
nullptr) {
1228 strncpy(dest, format, destSize - 1);
1229 dest[destSize - 1] =
'\0';
1231 ace_common::copyReplaceString(
1232 dest, destSize, format,
'%', letterString);
1236 const char* slashPos = strchr(format,
'/');
1237 if (slashPos !=
nullptr) {
1238 if (deltaMinutes == 0) {
1239 uint8_t headLength = (slashPos - format);
1240 if (headLength >= destSize) headLength = destSize - 1;
1241 memcpy(dest, format, headLength);
1242 dest[headLength] =
'\0';
1244 uint8_t tailLength = strlen(slashPos+1);
1245 if (tailLength >= destSize) tailLength = destSize - 1;
1246 memcpy(dest, slashPos+1, tailLength);
1247 dest[tailLength] =
'\0';
1251 strncpy(dest, format, destSize - 1);
1252 dest[destSize - 1] =
'\0';
1258 const BF* mBrokerFactory;
1259 ZIB mZoneInfoBroker;
1262 mutable uint8_t mNumMatches = 0;
1273 extended::BrokerFactory,
1274 extended::ZoneInfoBroker,
1275 extended::ZoneEraBroker,
1276 extended::ZonePolicyBroker,
1277 extended::ZoneRuleBroker> {
1285 extended::BrokerFactory,
1286 extended::ZoneInfoBroker,
1287 extended::ZoneEraBroker,
1288 extended::ZonePolicyBroker,
1289 extended::ZoneRuleBroker>(
The classes provide a thin layer of indirection for accessing the zoneinfo files stored in the zonedb...
An implementation of ZoneProcessor that supports for all zones defined by the TZ Database.
uint32_t getZoneId() const override
Return the unique stable zoneId.
FindResult findByLocalDateTime(const LocalDateTime &ldt) const override
Return the search results at given LocalDateTime.
bool initForEpochSeconds(acetime_t epochSeconds) const
Initialize using the epochSeconds.
void setBrokerFactory(const BF *brokerFactory)
Set the broker factory at runtime.
extended::TransitionForDateTimeTemplate< ZEB, ZPB, ZRB > TransitionForDateTime
Exposed only for testing purposes.
extended::TransitionStorageTemplate< kMaxTransitions, ZEB, ZPB, ZRB > TransitionStorage
Exposed only for testing purposes.
bool initForYear(int16_t year) const
Initialize the zone rules cache, keyed by the "current" year.
bool equalsZoneKey(uintptr_t zoneKey) const override
Return true if ZoneProcessor is associated with the given opaque zoneKey.
extended::TransitionForSecondsTemplate< ZEB, ZPB, ZRB > TransitionForSeconds
Exposed only for testing purposes.
bool isLink() const override
Return true if timezone is a Link entry pointing to a Zone entry.
void resetTransitionAllocSize()
Reset the TransitionStorage high water mark.
void printShortNameTo(Print &printer) const override
Print a short human-readable identifier (e.g.
void printTargetNameTo(Print &printer) const override
Print the full identifier (e.g.
static const uint8_t kMaxTransitions
Max number of Transitions required for all Zones supported by this class.
extended::TransitionTemplate< ZEB, ZPB, ZRB > Transition
Exposed only for testing purposes.
void setZoneKey(uintptr_t zoneKey) override
Set the opaque zoneKey of this object to a new value, reseting any internally cached information.
FindResult findByEpochSeconds(acetime_t epochSeconds) const override
ExtendedZoneProcessorTemplate(uint8_t type, const BF *brokerFactory, uintptr_t zoneKey)
Constructor.
void log() const
Used only for debugging.
void printNameTo(Print &printer) const override
Print a human-readable identifier (e.g.
uint8_t getTransitionAllocSize() const
Get the largest allocation size of TransitionStorage.
extended::MatchingEraTemplate< ZEB > MatchingEra
Exposed only for testing purposes.
A specific implementation of ExtendedZoneProcessorTemplate that uses ZoneXxxBrokers which read from z...
static const uint8_t kTypeExtended
Unique TimeZone type identifier for ExtendedZoneProcessor.
Result of a search for transition at a specific epochSeconds or a specific LocalDateTime.
uint8_t fold
For findByLocalDateTime(), when type==kTypeOverlap, this is a copy of the requested LocalDateTime::fo...
int16_t dstOffsetMinutes
DST offset of the resulting OffsetDateTime.
int16_t reqStdOffsetMinutes
STD offset of the Transition which matched the epochSeconds requested by findByEpochSeconds(),...
int16_t stdOffsetMinutes
STD offset of the resulting OffsetDateTime.
int16_t reqDstOffsetMinutes
DST offset of the Transition which matched the epochSeconds requested by findByEpochSeconds(),...
const char * abbrev
Pointer to the abbreviation stored in the transient Transition::abbrev variable.
uint8_t type
Result of the findByEpochSeconds() or findByLocalDateTime() search methods.
Class that holds the date-time as the components (year, month, day, hour, minute, second) without reg...
uint8_t fold() const
Return the fold.
int16_t year() const
Return the year.
The date (year, month, day) representing the date without regards to time zone.
static LocalDate forComponents(int16_t year, uint8_t month, uint8_t day)
Factory method using separated year, month and day fields.
int16_t year() const
Return the year.
static LocalDate forEpochSeconds(acetime_t epochSeconds)
Factory method using the number of seconds since the current epoch year given by currentEpochYear().
static const int16_t kInvalidYear
Sentinel year which indicates one or more of the following conditions:
Base interface for ZoneProcessor classes.
bool isFilled(int16_t year) const
Check if the Transition cache is filled for the given year.
A factory that creates a basic::ZoneInfoBroker.
void resetAllocSize()
Reset the current allocation size.
void init()
Initialize all pools to 0 size, usually when a new year is initialized.
uint8_t getAllocSize() const
Return the maximum number of transitions which was allocated.
TransitionForDateTime findTransitionForDateTime(const LocalDateTime &ldt) const
Return the candidate Transitions matching the given dateTime.
TransitionForSeconds findTransitionForSeconds(acetime_t epochSeconds) const
Return the Transition matching the given epochSeconds.
void log() const
Verify that the indexes are valid.
int32_t acetime_t
Type for the number of seconds from epoch.
Macros and definitions that provide a consistency layer among the various Arduino boards for compatib...
Internal identifiers used by implementation code, not intended to be publically exported.
Data structure that captures the matching ZoneEra and its ZoneRule transitions for a given year.
The result of the findTransitionForDateTime(const LocalDatetime& ldt) method which can return 0,...
uint8_t num
Number of matches: 0, 1, 2.
const TransitionTemplate< ZEB, ZPB, ZRB > * prev
The previous transition.
const TransitionTemplate< ZEB, ZPB, ZRB > * curr
The matching transition, or null if not found or in gap.
Tuple of a matching Transition and its 'fold'.
uint8_t fold
1 if corresponding datetime occurred the second time
const TransitionTemplate< ZEB, ZPB, ZRB > * curr
The matching transition, or null if not found.
uint8_t num
Number of occurrences of the resulting LocalDateTime: 0, 1, or 2.
Represents an interval of time where the time zone obeyed a certain UTC offset and DST delta.
static void printTransitions(const char *prefix, const TransitionTemplate *const *begin, const TransitionTemplate *const *end)
Print an iterable of Transitions from 'begin' to 'end'.
int16_t offsetMinutes
The base offset minutes, not the total effective UTC offset.
char abbrev[internal::kAbbrevSize]
The calculated effective time zone abbreviation, e.g.
int16_t deltaMinutes
The DST delta minutes.
A simple tuple to represent a year/month pair.
static const uint8_t kSuffixW
Represents 'w' or wall time.
static const uint8_t kSuffixS
Represents 's' or standard time.
static const uint8_t kSuffixU
Represents 'u' or UTC time.