6 #ifndef ACE_TIME_EXTENDED_ZONE_PROCESSOR_H
7 #define ACE_TIME_EXTENDED_ZONE_PROCESSOR_H
11 #include <AceCommon.h>
12 #include "../zoneinfo/compat.h"
13 #include "../zoneinfo/ZonePolicy.h"
14 #include "../zoneinfo/ZoneInfo.h"
15 #include "../zoneinfo/Brokers.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_processTransitionCompareStatus;
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_processTransitionCompareStatus;
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];
512 static bool eraOverlapsInterval(
515 const extended::YearMonthTuple& startYm,
516 const extended::YearMonthTuple& untilYm) {
517 return (prevMatch ==
nullptr || compareEraToYearMonth(
518 prevMatch->era, untilYm.year, untilYm.month) < 0)
519 && compareEraToYearMonth(era, startYm.year, startYm.month) > 0;
523 static int8_t compareEraToYearMonth(
const ZEB& era,
524 int16_t year, uint8_t month) {
525 if (era.untilYear() < year)
return -1;
526 if (era.untilYear() > year)
return 1;
527 if (era.untilMonth() < month)
return -1;
528 if (era.untilMonth() > month)
return 1;
529 if (era.untilDay() > 1)
return 1;
531 if (era.untilTimeMinutes() > 0)
return 1;
544 const extended::YearMonthTuple& startYm,
545 const extended::YearMonthTuple& untilYm) {
549 extended::DateTuple startDate = (prevMatch ==
nullptr)
550 ? extended::DateTuple{
557 : extended::DateTuple{
558 prevMatch->era.untilYear(),
559 prevMatch->era.untilMonth(),
560 prevMatch->era.untilDay(),
561 (int16_t) prevMatch->era.untilTimeMinutes(),
562 prevMatch->era.untilTimeSuffix()
564 extended::DateTuple lowerBound{
571 if (startDate < lowerBound) {
572 startDate = lowerBound;
575 extended::DateTuple untilDate{
579 (int16_t) era.untilTimeMinutes(),
580 era.untilTimeSuffix()
582 extended::DateTuple upperBound{
589 if (upperBound < untilDate) {
590 untilDate = upperBound;
593 return {startDate, untilDate, era, prevMatch, 0, 0};
600 static void createTransitions(
603 uint8_t numMatches) {
604 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
605 logging::printf(
"createTransitions()\n");
608 for (uint8_t i = 0; i < numMatches; i++) {
609 createTransitionsForMatch(transitionStorage, &matches[i]);
614 static void createTransitionsForMatch(
617 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
618 logging::printf(
"== createTransitionsForMatch()\n");
620 const ZPB policy = match->era.zonePolicy();
621 if (policy.isNull()) {
622 createTransitionsFromSimpleMatch(transitionStorage, match);
624 createTransitionsFromNamedMatch(transitionStorage, match);
629 static void createTransitionsFromSimpleMatch(
632 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
633 logging::printf(
"== createTransitionsFromSimpleMatch()\n");
636 Transition* freeTransition = transitionStorage.getFreeAgent();
637 createTransitionForYear(freeTransition, 0 ,
639 freeTransition->compareStatus = extended::CompareStatus::kExactMatch;
640 match->lastOffsetMinutes = freeTransition->offsetMinutes;
641 match->lastDeltaMinutes = freeTransition->deltaMinutes;
642 transitionStorage.addFreeAgentToActivePool();
643 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
644 transitionStorage.log();
649 static void createTransitionsFromNamedMatch(
652 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
653 logging::printf(
"== createTransitionsFromNamedMatch()\n");
656 transitionStorage.resetCandidatePool();
657 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
658 match->log(); logging::printf(
"\n");
662 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
663 logging::printf(
"---- Pass 1: findCandidateTransitions()\n");
665 findCandidateTransitions(transitionStorage, match);
666 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
667 transitionStorage.log();
672 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
673 logging::printf(
"---- Pass 2: fixTransitionTimes()\n");
676 transitionStorage.getCandidatePoolBegin(),
677 transitionStorage.getCandidatePoolEnd());
681 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
682 logging::printf(
"---- Pass 3: selectActiveTransitions()\n");
684 selectActiveTransitions(
685 transitionStorage.getCandidatePoolBegin(),
686 transitionStorage.getCandidatePoolEnd());
687 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
688 transitionStorage.log();
691 transitionStorage.addActiveCandidatesToActivePool();
692 match->lastOffsetMinutes = lastTransition->offsetMinutes;
693 match->lastDeltaMinutes = lastTransition->deltaMinutes;
694 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
695 transitionStorage.log();
700 static void findCandidateTransitions(
703 using extended::CompareStatus;
705 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
706 logging::printf(
"findCandidateTransitions(): \n");
708 logging::printf(
"\n");
710 const ZPB policy = match->era.zonePolicy();
711 uint8_t numRules = policy.numRules();
712 int16_t startY = match->startDateTime.year;
713 int16_t endY = match->untilDateTime.year;
718 Transition** prior = transitionStorage.reservePrior();
719 (*prior)->isValidPrior =
false;
720 for (uint8_t r = 0; r < numRules; r++) {
721 const ZRB rule = policy.rule(r);
724 int16_t interiorYears[kMaxInteriorYears];
725 uint8_t numYears = calcInteriorYears(interiorYears, kMaxInteriorYears,
726 rule.fromYear(), rule.toYear(), startY, endY);
727 for (uint8_t y = 0; y < numYears; y++) {
728 int16_t year = interiorYears[y];
729 Transition* t = transitionStorage.getFreeAgent();
730 createTransitionForYear(t, year, rule, match);
731 CompareStatus status = compareTransitionToMatchFuzzy(t, match);
732 if (status == CompareStatus::kPrior) {
733 transitionStorage.setFreeAgentAsPriorIfValid();
734 }
else if (status == CompareStatus::kWithinMatch) {
735 transitionStorage.addFreeAgentToCandidatePool();
743 int16_t priorYear = getMostRecentPriorYear(
744 rule.fromYear(), rule.toYear(), startY, endY);
746 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
748 "findCandidateTransitions(): priorYear: %d\n", priorYear);
750 Transition* t = transitionStorage.getFreeAgent();
751 createTransitionForYear(t, priorYear, rule, match);
752 transitionStorage.setFreeAgentAsPriorIfValid();
758 if ((*prior)->isValidPrior) {
759 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
761 "findCandidateTransitions(): adding prior to Candidate pool\n");
762 logging::printf(
" ");
764 logging::printf(
"\n");
766 transitionStorage.addPriorToCandidatePool();
789 static uint8_t calcInteriorYears(
790 int16_t* interiorYears,
791 uint8_t maxInteriorYears,
792 int16_t fromYear, int16_t toYear,
793 int16_t startYear, int16_t endYear) {
795 for (int16_t year = startYear; year <= endYear; year++) {
796 if (fromYear <= year && year <= toYear) {
797 interiorYears[i] = year;
799 if (i >= maxInteriorYears)
break;
810 static void createTransitionForYear(
816 t->offsetMinutes = match->era.offsetMinutes();
817 #if ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG
824 t->transitionTime = match->startDateTime;
825 t->deltaMinutes = match->era.deltaMinutes();
828 t->transitionTime = getTransitionTime(year, rule);
829 t->deltaMinutes = rule.deltaMinutes();
830 t->letter = rule.letter();
846 static int16_t getMostRecentPriorYear(
847 int16_t fromYear, int16_t toYear,
848 int16_t startYear, int16_t ) {
850 if (fromYear < startYear) {
851 if (toYear < startYear) {
854 return startYear - 1;
865 static extended::DateTuple getTransitionTime(
866 int16_t year,
const ZRB& rule) {
868 internal::MonthDay monthDay = internal::calcStartDayOfMonth(
872 rule.onDayOfMonth());
877 (int16_t) rule.atTimeMinutes(),
892 static extended::CompareStatus compareTransitionToMatchFuzzy(
894 return compareDateTupleFuzzy(
896 match->startDateTime,
897 match->untilDateTime);
909 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
910 logging::printf(
"fixTransitionTimes(): START; #transitions=%d\n",
911 (
int) (end - begin));
918 for (
Transition** iter = begin; iter != end; ++iter) {
921 &curr->transitionTime,
924 &curr->transitionTime,
925 &curr->transitionTimeS,
926 &curr->transitionTimeU);
929 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
930 logging::printf(
"fixTransitionTimes(): FIXED\n");
932 logging::printf(
"fixTransitionTimes(): END\n");
941 static void expandDateTuple(
942 const extended::DateTuple* tt,
943 int16_t offsetMinutes,
944 int16_t deltaMinutes,
945 extended::DateTuple* ttw,
946 extended::DateTuple* tts,
947 extended::DateTuple* ttu) {
951 *ttu = {tt->year, tt->month, tt->day,
952 (int16_t) (tt->minutes - offsetMinutes),
954 *ttw = {tt->year, tt->month, tt->day,
955 (int16_t) (tt->minutes + deltaMinutes),
959 *tts = {tt->year, tt->month, tt->day,
960 (int16_t) (tt->minutes + offsetMinutes),
962 *ttw = {tt->year, tt->month, tt->day,
963 (int16_t) (tt->minutes + (offsetMinutes + deltaMinutes)),
969 *tts = {tt->year, tt->month, tt->day,
970 (int16_t) (tt->minutes - deltaMinutes),
972 *ttu = {tt->year, tt->month, tt->day,
973 (int16_t) (tt->minutes - (deltaMinutes + offsetMinutes)),
977 extended::normalizeDateTuple(ttw);
978 extended::normalizeDateTuple(tts);
979 extended::normalizeDateTuple(ttu);
987 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
988 logging::printf(
"selectActiveTransitions(): #candidates: %d\n",
989 (
int) (end - begin));
993 for (
Transition** iter = begin; iter != end; ++iter) {
995 processTransitionCompareStatus(transition, &prior);
1001 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
1003 "selectActiveTransitions(): found latest prior\n");
1005 #if ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG
1006 prior->originalTransitionTime = prior->transitionTime;
1008 prior->transitionTime = prior->match->startDateTime;
1018 static void processTransitionCompareStatus(
1021 using extended::CompareStatus;
1023 CompareStatus status = compareTransitionToMatch(
1024 transition, transition->match);
1025 transition->compareStatus = status;
1027 if (status == CompareStatus::kExactMatch) {
1029 (*prior)->compareStatus = CompareStatus::kFarPast;
1031 (*prior) = transition;
1032 }
else if (status == CompareStatus::kPrior) {
1034 if ((*prior)->transitionTimeU <= transition->transitionTimeU) {
1035 (*prior)->compareStatus = CompareStatus::kFarPast;
1036 (*prior) = transition;
1038 transition->compareStatus = CompareStatus::kFarPast;
1041 (*prior) = transition;
1054 static extended::CompareStatus compareTransitionToMatch(
1059 int16_t prevMatchOffsetMinutes;
1060 int16_t prevMatchDeltaMinutes;
1061 if (match->prevMatch) {
1062 prevMatchOffsetMinutes = match->prevMatch->lastOffsetMinutes;
1063 prevMatchDeltaMinutes = match->prevMatch->lastDeltaMinutes;
1065 prevMatchOffsetMinutes = match->era.offsetMinutes();
1066 prevMatchDeltaMinutes = 0;
1070 extended::DateTuple stw;
1071 extended::DateTuple sts;
1072 extended::DateTuple stu;
1074 &match->startDateTime,
1075 prevMatchOffsetMinutes,
1076 prevMatchDeltaMinutes,
1082 const extended::DateTuple& ttw = transition->transitionTime;
1083 const extended::DateTuple& tts = transition->transitionTimeS;
1084 const extended::DateTuple& ttu = transition->transitionTimeU;
1089 if (ttw == stw || tts == sts || ttu == stu) {
1090 return extended::CompareStatus::kExactMatch;
1094 return extended::CompareStatus::kPrior;
1102 const extended::DateTuple& matchUntil = match->untilDateTime;
1103 const extended::DateTuple* transitionTime;
1105 transitionTime = &tts;
1107 transitionTime = &ttu;
1109 transitionTime = &ttw;
1111 if (*transitionTime < matchUntil) {
1112 return extended::CompareStatus::kWithinMatch;
1114 return extended::CompareStatus::kFarFuture;
1123 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
1125 "generateStartUntilTimes(): #transitions=%d\n",
1126 (
int) (end - begin));
1131 if (begin == end)
return;
1134 bool isAfterFirst =
false;
1136 for (
Transition** iter = begin; iter != end; ++iter) {
1140 const extended::DateTuple& tt = t->transitionTime;
1142 prev->untilDateTime = tt;
1148 int16_t minutes = tt.minutes + (
1149 - prev->offsetMinutes - prev->deltaMinutes
1150 + t->offsetMinutes + t->deltaMinutes);
1151 t->startDateTime = {tt.year, tt.month, tt.day, minutes, tt.suffix};
1152 extended::normalizeDateTuple(&t->startDateTime);
1164 const extended::DateTuple& st = t->startDateTime;
1166 * (st.minutes - (t->offsetMinutes + t->deltaMinutes));
1168 t->startEpochSeconds = ld.toEpochSeconds() + offsetSeconds;
1171 isAfterFirst =
true;
1175 extended::DateTuple untilTimeW;
1176 extended::DateTuple untilTimeS;
1177 extended::DateTuple untilTimeU;
1179 &prev->match->untilDateTime,
1180 prev->offsetMinutes,
1185 prev->untilDateTime = untilTimeW;
1192 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
1193 logging::printf(
"calcAbbreviations(): #transitions: %d\n",
1194 (
int) (end - begin));
1196 for (
Transition** iter = begin; iter != end; ++iter) {
1198 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
1200 "calcAbbreviations(): format:%s, deltaMinutes:%d, letter:%s\n",
1201 t->format(), t->deltaMinutes, t->letter);
1205 internal::kAbbrevSize,
1220 static void createAbbreviation(
1224 uint16_t deltaMinutes,
1225 const char* letterString) {
1228 if (strchr(format,
'%') !=
nullptr) {
1230 if (letterString ==
nullptr) {
1231 strncpy(dest, format, destSize - 1);
1232 dest[destSize - 1] =
'\0';
1234 ace_common::copyReplaceString(
1235 dest, destSize, format,
'%', letterString);
1239 const char* slashPos = strchr(format,
'/');
1240 if (slashPos !=
nullptr) {
1241 if (deltaMinutes == 0) {
1242 uint8_t headLength = (slashPos - format);
1243 if (headLength >= destSize) headLength = destSize - 1;
1244 memcpy(dest, format, headLength);
1245 dest[headLength] =
'\0';
1247 uint8_t tailLength = strlen(slashPos+1);
1248 if (tailLength >= destSize) tailLength = destSize - 1;
1249 memcpy(dest, slashPos+1, tailLength);
1250 dest[tailLength] =
'\0';
1254 strncpy(dest, format, destSize - 1);
1255 dest[destSize - 1] =
'\0';
1261 const BF* mBrokerFactory;
1262 ZIB mZoneInfoBroker;
1265 mutable uint8_t mNumMatches = 0;
1276 extended::BrokerFactory,
1277 extended::ZoneInfoBroker,
1278 extended::ZoneEraBroker,
1279 extended::ZonePolicyBroker,
1280 extended::ZoneRuleBroker> {
1288 extended::BrokerFactory,
1289 extended::ZoneInfoBroker,
1290 extended::ZoneEraBroker,
1291 extended::ZonePolicyBroker,
1292 extended::ZoneRuleBroker>(
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.
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.
Identifiers used by implementation code which need to be publically exported.
int32_t acetime_t
Type for the number of seconds from epoch.
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.