6 #ifndef ACE_TIME_EXTENDED_ZONE_PROCESSOR_H 7 #define ACE_TIME_EXTENDED_ZONE_PROCESSOR_H 12 #include "internal/ZonePolicy.h" 13 #include "internal/ZoneInfo.h" 14 #include "common/logger.h" 15 #include "TimeOffset.h" 16 #include "LocalDate.h" 17 #include "OffsetDateTime.h" 18 #include "ZoneProcessor.h" 19 #include "BasicZoneProcessor.h" 20 #include "local_date_mutation.h" 24 class ExtendedZoneProcessorTest_compareEraToYearMonth;
25 class ExtendedZoneProcessorTest_compareEraToYearMonth2;
26 class ExtendedZoneProcessorTest_createMatch;
27 class ExtendedZoneProcessorTest_findMatches_simple;
28 class ExtendedZoneProcessorTest_findMatches_named;
29 class ExtendedZoneProcessorTest_findCandidateTransitions;
30 class ExtendedZoneProcessorTest_findTransitionsFromNamedMatch;
31 class ExtendedZoneProcessorTest_getTransitionTime;
32 class ExtendedZoneProcessorTest_createTransitionForYear;
33 class ExtendedZoneProcessorTest_normalizeDateTuple;
34 class ExtendedZoneProcessorTest_expandDateTuple;
35 class ExtendedZoneProcessorTest_calcInteriorYears;
36 class ExtendedZoneProcessorTest_getMostRecentPriorYear;
37 class ExtendedZoneProcessorTest_compareTransitionToMatchFuzzy;
38 class ExtendedZoneProcessorTest_compareTransitionToMatch;
39 class ExtendedZoneProcessorTest_processActiveTransition;
40 class ExtendedZoneProcessorTest_fixTransitionTimes_generateStartUntilTimes;
41 class ExtendedZoneProcessorTest_createAbbreviation;
42 class ExtendedZoneProcessorTest_setZoneInfo;
43 class TransitionStorageTest_getFreeAgent;
44 class TransitionStorageTest_getFreeAgent2;
45 class TransitionStorageTest_addFreeAgentToActivePool;
46 class TransitionStorageTest_reservePrior;
47 class TransitionStorageTest_addFreeAgentToCandidatePool;
48 class TransitionStorageTest_setFreeAgentAsPrior;
49 class TransitionStorageTest_addActiveCandidatesToActivePool;
50 class TransitionStorageTest_resetCandidatePool;
54 template<u
int8_t SIZE, u
int8_t TYPE,
typename ZS,
typename ZI,
typename ZIB>
55 class ZoneProcessorCacheImpl;
73 logging::print(
"DateTuple(%d-%u-%uT%d'%c')",
80 if (a.yearTiny < b.yearTiny)
return true;
81 if (a.yearTiny > b.yearTiny)
return false;
82 if (a.month < b.month)
return true;
83 if (a.month > b.month)
return false;
84 if (a.day < b.day)
return true;
85 if (a.day > b.day)
return false;
86 if (a.timeCode < b.timeCode)
return true;
87 if (a.timeCode > b.timeCode)
return false;
105 return a.yearTiny == b.yearTiny
106 && a.month == b.month
108 && a.timeCode == b.timeCode
109 && a.modifier == b.modifier;
133 logging::print(
"ZoneMatch(");
134 logging::print(
"Start:"); startDateTime.
log();
135 logging::print(
"; Until:"); untilDateTime.
log();
136 logging::print(
"; Era: %snull", (era.isNotNull()) ?
"!" :
"");
222 char abbrev[kAbbrevSize];
258 const char* format()
const {
259 return match->
era.format();
275 char letter = rule.letter();
284 uint8_t numLetters = policy.numLetters();
285 if (letter >= numLetters) {
293 return policy.letter(letter);
298 logging::print(
"Transition(");
299 if (
sizeof(acetime_t) ==
sizeof(
int)) {
300 logging::print(
"sE: %d", startEpochSeconds);
302 logging::print(
"sE: %ld", startEpochSeconds);
304 logging::print(
"; match: %snull", (match) ?
"!" :
"");
305 logging::print(
"; era: %snull",
306 (match && match->
era.isNotNull()) ?
"!" :
"");
307 logging::print(
"; oCode: %d", offsetCode);
308 logging::print(
"; dCode: %d", deltaCode);
309 logging::print(
"; tt: "); transitionTime.
log();
310 if (rule.isNotNull()) {
311 logging::print(
"; R.fY: %d", rule.fromYearTiny());
312 logging::print(
"; R.tY: %d", rule.toYearTiny());
313 logging::print(
"; R.M: %d", rule.inMonth());
314 logging::print(
"; R.dow: %d", rule.onDayOfWeek());
315 logging::print(
"; R.dom: %d", rule.onDayOfMonth());
346 template<u
int8_t SIZE>
354 for (uint8_t i = 0; i < SIZE; i++) {
355 mTransitions[i] = &mPool[i];
358 mIndexCandidates = 0;
381 mIndexCandidates = mIndexPrior;
382 mIndexFree = mIndexPrior;
386 return &mTransitions[mIndexCandidates];
389 return &mTransitions[mIndexFree];
392 Transition** getActivePoolBegin() {
return &mTransitions[0]; }
393 Transition** getActivePoolEnd() {
return &mTransitions[mIndexFree]; }
403 if (mIndexFree > mHighWater) {
404 mHighWater = mIndexFree;
407 if (mIndexFree < SIZE) {
408 return mTransitions[mIndexFree];
410 return mTransitions[SIZE - 1];
422 if (mIndexFree >= SIZE)
return;
424 mIndexPrior = mIndexFree;
425 mIndexCandidates = mIndexFree;
436 return &mTransitions[mIndexPrior];
441 swap(&mTransitions[mIndexPrior], &mTransitions[mIndexFree]);
460 if (mIndexFree >= SIZE)
return;
461 for (uint8_t i = mIndexFree; i > mIndexCandidates; i--) {
465 mTransitions[i] = prev;
466 mTransitions[i - 1] = curr;
476 if (DEBUG) logging::println(
"addActiveCandidatesToActivePool()");
477 uint8_t iActive = mIndexPrior;
478 uint8_t iCandidate = mIndexCandidates;
479 for (; iCandidate < mIndexFree; iCandidate++) {
480 if (mTransitions[iCandidate]->active) {
481 if (iActive != iCandidate) {
482 swap(&mTransitions[iActive], &mTransitions[iCandidate]);
487 mIndexPrior = iActive;
488 mIndexCandidates = iActive;
489 mIndexFree = iActive;
501 if (DEBUG) logging::println(
502 "findTransition(): mIndexFree: %d", mIndexFree);
505 for (uint8_t i = 0; i < mIndexFree; i++) {
506 const Transition* candidate = mTransitions[i];
538 if (DEBUG) logging::println(
539 "findTransitionForDateTime(): mIndexFree: %d", mIndexFree);
544 (int8_t) (ldt.
hour() * 4 + ldt.
minute() / 15),
'w' };
546 for (uint8_t i = 0; i < mIndexFree; i++) {
547 const Transition* candidate = mTransitions[i];
556 logging::println(
"TransitionStorage:");
557 logging::println(
" mIndexPrior: %d", mIndexPrior);
558 logging::println(
" mIndexCandidates: %d", mIndexCandidates);
559 logging::println(
" mIndexFree: %d", mIndexFree);
560 if (mIndexPrior != 0) {
561 logging::println(
" Actives:");
562 for (uint8_t i = 0; i < mIndexPrior; i++) {
563 mTransitions[i]->log();
567 if (mIndexPrior != mIndexCandidates) {
568 logging::print(
" Prior: ");
569 mTransitions[mIndexPrior]->log();
572 if (mIndexCandidates != mIndexFree) {
573 logging::println(
" Candidates:");
574 for (uint8_t i = mIndexCandidates; i < mIndexFree; i++) {
575 mTransitions[i]->log();
592 friend class ::TransitionStorageTest_getFreeAgent;
593 friend class ::TransitionStorageTest_getFreeAgent2;
594 friend class ::TransitionStorageTest_addFreeAgentToActivePool;
595 friend class ::TransitionStorageTest_reservePrior;
596 friend class ::TransitionStorageTest_addFreeAgentToCandidatePool;
597 friend class ::TransitionStorageTest_setFreeAgentAsPrior;
598 friend class ::TransitionStorageTest_addActiveCandidatesToActivePool;
599 friend class ::TransitionStorageTest_resetCandidatePool;
602 Transition* getTransition(uint8_t i) {
return mTransitions[i]; }
607 uint8_t mIndexCandidates;
611 uint8_t mHighWater = 0;
653 mZoneInfo(zoneInfo) {}
657 return mZoneInfo.zoneInfo();
660 uint32_t
getZoneId()
const override {
return mZoneInfo.zoneId(); }
663 bool success = init(epochSeconds);
673 bool success = init(epochSeconds);
679 const char*
getAbbrev(acetime_t epochSeconds)
const override {
680 bool success = init(epochSeconds);
681 if (!success)
return "";
683 return transition->
abbrev;
691 mTransitionStorage.findTransitionForDateTime(ldt);
692 offset = (transition)
711 acetime_t epochSeconds = odt.toEpochSeconds();
713 mTransitionStorage.findTransition(epochSeconds);
714 offset = (transition)
722 void printTo(Print& printer)
const override;
724 void printShortTo(Print& printer)
const override;
728 logging::println(
"ExtendedZoneProcessor:");
729 logging::println(
" mYear: %d", mYear);
730 logging::println(
" mNumMatches: %d", mNumMatches);
731 for (
int i = 0; i < mNumMatches; i++) {
732 logging::print(
" Match %d: ", i);
736 mTransitionStorage.log();
741 mTransitionStorage.resetHighWater();
746 return mTransitionStorage.getHighWater();
750 friend class ::ExtendedZoneProcessorTest_compareEraToYearMonth;
751 friend class ::ExtendedZoneProcessorTest_compareEraToYearMonth2;
752 friend class ::ExtendedZoneProcessorTest_createMatch;
753 friend class ::ExtendedZoneProcessorTest_findMatches_simple;
754 friend class ::ExtendedZoneProcessorTest_findMatches_named;
755 friend class ::ExtendedZoneProcessorTest_findCandidateTransitions;
756 friend class ::ExtendedZoneProcessorTest_findTransitionsFromNamedMatch;
757 friend class ::ExtendedZoneProcessorTest_getTransitionTime;
758 friend class ::ExtendedZoneProcessorTest_createTransitionForYear;
759 friend class ::ExtendedZoneProcessorTest_normalizeDateTuple;
760 friend class ::ExtendedZoneProcessorTest_expandDateTuple;
761 friend class ::ExtendedZoneProcessorTest_calcInteriorYears;
762 friend class ::ExtendedZoneProcessorTest_getMostRecentPriorYear;
763 friend class ::ExtendedZoneProcessorTest_compareTransitionToMatchFuzzy;
764 friend class ::ExtendedZoneProcessorTest_compareTransitionToMatch;
765 friend class ::ExtendedZoneProcessorTest_processActiveTransition;
766 friend class ::ExtendedZoneProcessorTest_fixTransitionTimes_generateStartUntilTimes;
767 friend class ::ExtendedZoneProcessorTest_createAbbreviation;
768 friend class ::ExtendedZoneProcessorTest_setZoneInfo;
770 template<u
int8_t SIZE, u
int8_t TYPE,
typename ZS,
typename ZI,
typename ZIB>
781 static const uint8_t kMaxMatches = 4;
790 static const uint8_t kMaxTransitions = 8;
796 static const uint8_t kMaxInteriorYears = 4;
807 void setZoneInfo(
const void* zoneInfo)
override {
808 if (mZoneInfo.zoneInfo() == zoneInfo)
return;
822 return mTransitionStorage.findTransition(epochSeconds);
826 bool init(acetime_t epochSeconds)
const {
836 int16_t year = ld.
year();
837 if (isFilled(year))
return true;
838 if (DEBUG) logging::println(
"init(): %d", year);
842 mTransitionStorage.init();
844 if (year < mZoneInfo.startYear() - 1 || mZoneInfo.untilYear() < year) {
853 mNumMatches = findMatches(mZoneInfo, startYm, untilYm, mMatches,
856 findTransitions(mTransitionStorage, mMatches, mNumMatches);
859 fixTransitionTimes(begin, end);
860 generateStartUntilTimes(begin, end);
861 calcAbbreviations(begin, end);
868 bool isFilled(int16_t year)
const {
869 return mIsFilled && (year == mYear);
883 if (DEBUG) logging::println(
"findMatches()");
886 for (uint8_t iEra = 0; iEra < zoneInfo.numEras(); iEra++) {
888 if (eraOverlapsInterval(prev, era, startYm, untilYm)) {
889 if (iMatch < maxMatches) {
890 matches[iMatch] = createMatch(prev, era, startYm, untilYm);
909 static bool eraOverlapsInterval(
914 return compareEraToYearMonth(prev, untilYm.yearTiny, untilYm.month) < 0
915 && compareEraToYearMonth(era, startYm.yearTiny, startYm.month) > 0;
920 int8_t yearTiny, uint8_t month) {
921 if (era.untilYearTiny() < yearTiny)
return -1;
922 if (era.untilYearTiny() > yearTiny)
return 1;
923 if (era.untilMonth() < month)
return -1;
924 if (era.untilMonth() > month)
return 1;
925 if (era.untilDay() > 1)
return 1;
927 if (era.untilTimeCode() > 0)
return 1;
943 prev.untilYearTiny(), prev.untilMonth(), prev.untilDay(),
944 (int8_t) prev.untilTimeCode(), prev.untilTimeModifier()
947 startYm.yearTiny, startYm.month, 1, 0,
'w' 949 if (startDate < lowerBound) {
950 startDate = lowerBound;
954 era.untilYearTiny(), era.untilMonth(), era.untilDay(),
955 (int8_t) era.untilTimeCode(), era.untilTimeModifier()
958 untilYm.yearTiny, untilYm.month, 1, 0,
'w' 960 if (upperBound < untilDate) {
961 untilDate = upperBound;
964 return {startDate, untilDate, era};
971 static void findTransitions(
974 uint8_t numMatches) {
975 if (DEBUG) logging::println(
"findTransitions()");
976 for (uint8_t i = 0; i < numMatches; i++) {
977 findTransitionsForMatch(transitionStorage, &matches[i]);
982 static void findTransitionsForMatch(
985 if (DEBUG) logging::println(
"findTransitionsForMatch()");
987 if (policy.isNull()) {
988 findTransitionsFromSimpleMatch(transitionStorage, match);
990 findTransitionsFromNamedMatch(transitionStorage, match);
994 static void findTransitionsFromSimpleMatch(
997 if (DEBUG) logging::println(
"findTransitionsFromSimpleMatch()");
999 createTransitionForYear(freeTransition, 0 ,
1004 static void findTransitionsFromNamedMatch(
1007 if (DEBUG) logging::println(
"findTransitionsFromNamedMatch()");
1009 if (DEBUG) { match->log(); logging::println(); }
1010 findCandidateTransitions(transitionStorage, match);
1011 if (DEBUG) { transitionStorage.
log(); logging::println(); }
1013 transitionStorage.getCandidatePoolBegin(),
1014 transitionStorage.getCandidatePoolEnd());
1015 selectActiveTransitions(transitionStorage, match);
1016 if (DEBUG) { transitionStorage.
log(); logging::println(); }
1019 if (DEBUG) { transitionStorage.
log(); logging::println(); }
1022 static void findCandidateTransitions(
1026 logging::print(
"findCandidateTransitions(): ");
1031 uint8_t numRules = policy.numRules();
1036 (*prior)->
active =
false;
1037 for (uint8_t r = 0; r < numRules; r++) {
1041 int8_t interiorYears[kMaxInteriorYears];
1042 uint8_t numYears = calcInteriorYears(interiorYears, kMaxInteriorYears,
1043 rule.fromYearTiny(), rule.toYearTiny(), startY, endY);
1044 for (uint8_t y = 0; y < numYears; y++) {
1045 int8_t year = interiorYears[y];
1047 createTransitionForYear(t, year, rule, match);
1048 int8_t status = compareTransitionToMatchFuzzy(t, match);
1050 setAsPriorTransition(transitionStorage, t);
1051 }
else if (status == 1) {
1057 int8_t priorYear = getMostRecentPriorYear(
1058 rule.fromYearTiny(), rule.toYearTiny(), startY, endY);
1060 if (DEBUG) logging::println(
1061 "findCandidateTransitions(): priorYear: %d", priorYear);
1063 createTransitionForYear(t, priorYear, rule, match);
1064 setAsPriorTransition(transitionStorage, t);
1070 if ((*prior)->active) {
1071 if (DEBUG) logging::println(
1072 "findCandidateTransitions(): adding prior to Candidate pool");
1081 static uint8_t calcInteriorYears(int8_t* interiorYears,
1082 uint8_t maxInteriorYears, int8_t fromYear, int8_t toYear,
1083 int8_t startYear, int8_t endYear) {
1085 for (int8_t year = startYear; year <= endYear; year++) {
1086 if (fromYear <= year && year <= toYear) {
1087 interiorYears[i] = year;
1089 if (i >= maxInteriorYears)
break;
1109 if (rule.isNotNull()) {
1113 char letter = rule.letter();
1116 if (letter !=
'-') {
1136 static int8_t getMostRecentPriorYear(int8_t fromYear, int8_t toYear,
1137 int8_t startYear, int8_t ) {
1138 if (fromYear < startYear) {
1139 if (toYear < startYear) {
1142 return startYear - 1;
1153 rule.onDayOfMonth());
1154 return {yearTiny, monthDay.month, monthDay.day,
1155 (int8_t) rule.atTimeCode(), rule.atTimeModifier()};
1168 static int8_t compareTransitionToMatchFuzzy(
1173 int16_t matchStartMonths = match->
startDateTime.yearTiny * 12
1175 if (ttMonths < matchStartMonths - 1)
return -1;
1177 int16_t matchUntilMonths = match->
untilDateTime.yearTiny * 12
1179 if (matchUntilMonths + 2 <= ttMonths)
return 2;
1185 static void setAsPriorTransition(
1188 if (DEBUG) logging::println(
"setAsPriorTransition()");
1209 static void fixTransitionTimes(
1211 if (DEBUG) logging::println(
"fixTransitionTimes(): #transitions: %d;",
1212 (
int) (end - begin));
1220 logging::println(
"fixTransitionTimes(): LOOP");
1229 if (DEBUG) logging::println(
"fixTransitionTimes(): END");
1239 int8_t offsetCode, int8_t deltaCode) {
1240 if (DEBUG) logging::println(
"expandDateTuple()");
1241 if (tt->modifier ==
's') {
1243 *ttu = {tt->yearTiny, tt->month, tt->day,
1244 (int8_t) (tt->timeCode - offsetCode),
'u'};
1245 *tt = {tt->yearTiny, tt->month, tt->day,
1246 (int8_t) (tt->timeCode + deltaCode),
'w'};
1247 }
else if (tt->modifier ==
'u') {
1249 *tts = {tt->yearTiny, tt->month, tt->day,
1250 (int8_t) (tt->timeCode + offsetCode),
's'};
1251 *tt = {tt->yearTiny, tt->month, tt->day,
1252 (int8_t) (tt->timeCode + offsetCode + deltaCode),
'w'};
1256 *tts = {tt->yearTiny, tt->month, tt->day,
1257 (int8_t) (tt->timeCode - deltaCode),
's'};
1258 *ttu = {tt->yearTiny, tt->month, tt->day,
1259 (int8_t) (tt->timeCode - deltaCode - offsetCode),
'u'};
1262 if (DEBUG) logging::println(
"expandDateTuple(): normalizeDateTuple(): 1");
1263 normalizeDateTuple(tt);
1264 if (DEBUG) logging::println(
"expandDateTuple(): normalizeDateTuple(): 2");
1265 normalizeDateTuple(tts);
1266 if (DEBUG) logging::println(
"expandDateTuple(): normalizeDateTuple(): 3");
1267 normalizeDateTuple(ttu);
1272 const int8_t kOneDayAsCode = 4 * 24;
1273 if (dt->timeCode <= -kOneDayAsCode) {
1275 dt->yearTiny, dt->month, dt->day);
1276 local_date_mutation::decrementOneDay(ld);
1278 dt->month = ld.
month();
1280 dt->timeCode += kOneDayAsCode;
1281 }
else if (kOneDayAsCode <= dt->timeCode) {
1283 dt->yearTiny, dt->month, dt->day);
1284 local_date_mutation::incrementOneDay(ld);
1286 dt->month = ld.
month();
1288 dt->timeCode -= kOneDayAsCode;
1298 static void selectActiveTransitions(
1303 if (DEBUG) logging::println(
"selectActiveTransitions(): #candidates: %d",
1304 (
int) (end - begin));
1308 processActiveTransition(match, transition, &prior);
1314 if (DEBUG) logging::println(
1315 "selectActiveTransitions(): found latest prior");
1328 static void processActiveTransition(
1332 int8_t status = compareTransitionToMatch(transition, match);
1334 transition->
active =
false;
1335 }
else if (status == 1) {
1336 transition->
active =
true;
1337 }
else if (status == 0) {
1339 (*prior)->active =
false;
1341 transition->
active =
true;
1342 (*prior) = transition;
1346 (*prior)->
active =
false;
1347 transition->
active =
true;
1348 (*prior) = transition;
1351 transition->
active =
true;
1352 (*prior) = transition;
1371 static int8_t compareTransitionToMatch(
1377 if (matchStart.modifier ==
's') {
1379 }
else if (matchStart.modifier ==
'u') {
1384 if (*transitionTime < matchStart)
return -1;
1385 if (*transitionTime == matchStart)
return 0;
1388 if (matchUntil.modifier ==
's') {
1390 }
else if (matchUntil.modifier ==
'u') {
1395 if (*transitionTime < matchUntil)
return 1;
1404 static void generateStartUntilTimes(
1406 if (DEBUG) logging::println(
1407 "generateStartUntilTimes(): #transitions: %d;",
1408 (
int) (end - begin));
1411 bool isAfterFirst =
false;
1427 t->
startDateTime = {tt.yearTiny, tt.month, tt.day, code, tt.modifier};
1441 const acetime_t offsetSeconds = (acetime_t) 900
1444 st.yearTiny, st.month, st.day);
1448 isAfterFirst =
true;
1455 expandDateTuple(&untilTime, &untilTimeS, &untilTimeU,
1463 static void calcAbbreviations(
1465 if (DEBUG) logging::println(
"calcAbbreviations(): #transitions: %d;",
1466 (
int) (end - begin));
1469 if (DEBUG) logging::println(
1470 "calcAbbreviations(): format:%s, deltaCode:%d, letter:%s",
1511 static void createAbbreviation(
char* dest, uint8_t destSize,
1512 const char* format, uint8_t deltaCode,
const char* letterString) {
1515 if (letterString ==
nullptr) {
1516 strncpy(dest, format, destSize);
1517 dest[destSize - 1] =
'\0';
1522 if (strchr(format,
'%') !=
nullptr) {
1523 copyAndReplace(dest, destSize, format,
'%', letterString);
1526 const char* slashPos = strchr(format,
'/');
1527 if (slashPos !=
nullptr) {
1528 if (deltaCode == 0) {
1529 uint8_t headLength = (slashPos - format);
1530 if (headLength >= destSize) headLength = destSize - 1;
1531 memcpy(dest, format, headLength);
1532 dest[headLength] =
'\0';
1534 uint8_t tailLength = strlen(slashPos+1);
1535 if (tailLength >= destSize) tailLength = destSize - 1;
1536 memcpy(dest, slashPos+1, tailLength);
1537 dest[tailLength] =
'\0';
1541 strncpy(dest, format, destSize);
1542 dest[destSize - 1] =
'\0';
1552 static void copyAndReplace(
char* dst, uint8_t dstSize,
const char* src,
1553 char oldChar,
const char* newString) {
1554 while (*src !=
'\0' && dstSize > 0) {
1555 if (*src == oldChar) {
1556 while (*newString !=
'\0' && dstSize > 0) {
1557 *dst++ = *newString++;
1575 mutable int16_t mYear = 0;
1576 mutable bool mIsFilled =
false;
1578 mutable uint8_t mNumMatches = 0;
void addFreeAgentToActivePool()
Immediately add the free agent Transition at index mIndexFree to the Active pool. ...
static TimeOffset forError()
Return an error indicator.
Base interface for ZoneProcessor classes.
ZoneEraBroker era
The ZoneEra that matched the given year.
A heap manager which is specialized and tuned to manage a collection of Transitions, keeping track of unused, used, and active states, using a fixed array of Transitions.
uint8_t minute() const
Return the minute.
void addActiveCandidatesToActivePool()
Add active candidates into the Active pool, and collapse the Candidate pool.
DateTuple transitionTimeU
Version of transitionTime in 'u' mode, using the UTC offset of the previous transition.
void resetCandidatePool()
Empty the Candidate pool by resetting the various indexes.
char letterBuf[2]
Storage for the single letter 'letter' field if 'rule' is not null.
int8_t yearTiny() const
Return the single-byte year offset from year 2000.
DateTuple startDateTime
The effective start time of the matching ZoneEra.
Transition * getFreeAgent()
Return a pointer to the first Transition in the free pool.
A cache of ZoneProcessors that provides a ZoneProcessor to the TimeZone upon request.
static const uint8_t kAbbrevSize
Longest abbreviation currently seems to be 5 characters (https://www.timeanddate.com/time/zones/) but...
const ZoneMatch * match
The match which generated this Transition.
uint8_t getHighWater() const
Return the high water mark.
bool isError() const
Return true if this TimeOffset represents an error.
TransitionStorage()
Constructor.
static OffsetDateTime forLocalDateTimeAndOffset(const LocalDateTime &localDateTime, TimeOffset timeOffset)
Factory method from LocalDateTime and TimeOffset.
DateTuple originalTransitionTime
If the transition is shifted to the beginning of a ZoneMatch, this is set to the transitionTime for d...
uint8_t day() const
Return the day of the month.
int8_t yearTiny() const
Return the single-byte year offset from year 2000.
The result of calcStartDayOfMonth().
virtual const void * getZoneInfo() const =0
Return the opaque zoneInfo.
Represents an interval of time where the time zone obeyed a certain UTC offset and DST delta...
void log() const
Verify that the indexes are valid.
const void * getZoneInfo() const override
Return the underlying ZoneInfo.
void addPriorToCandidatePool()
Add the current prior into the Candidates pool.
const char * getAbbrev(acetime_t epochSeconds) const override
Return the time zone abbreviation at epochSeconds.
Representation of a given time zone, implemented as an array of ZoneEra records.
void setFreeAgentAsPrior()
Swap the Free agrent transition with the current Prior transition.
Transition * getPrior()
Return the current prior transition.
static LocalDate forTinyComponents(int8_t yearTiny, uint8_t month, uint8_t day)
Factory method using components with an int8_t yearTiny.
TimeOffset getUtcOffset(acetime_t epochSeconds) const override
Return the total UTC offset at epochSeconds, including DST offset.
char abbrev[kAbbrevSize]
The calculated effective time zone abbreviation, e.g.
const char * letter() const
Return the letter string.
An entry in ZoneInfo which describes which ZonePolicy was being followed during a particular time per...
uint8_t day() const
Return the day of the month.
uint8_t month() const
Return the month with January=1, December=12.
void init()
Initialize all pools.
static OffsetDateTime forEpochSeconds(acetime_t epochSeconds, TimeOffset timeOffset)
Factory method.
void addFreeAgentToCandidatePool()
Add the free agent Transition at index mIndexFree to the Candidate pool, sorted by transitionTime...
DateTuple transitionTime
The original transition time, usually 'w' but sometimes 's' or 'u'.
acetime_t toEpochSeconds() const
Return the number of seconds since AceTime epoch (2000-01-01 00:00:00).
const LocalDate & localDate() const
Return the LocalDate.
static const uint8_t kAbbrevSize
Size of the timezone abbreviation.
An implementation of ZoneProcessor that works for all zones defined by the TZ Database (with some zon...
const Transition * findTransitionForDateTime(const LocalDateTime &ldt) const
Return the Transition matching the given dateTime.
uint8_t hour() const
Return the hour.
TimeOffset getDeltaOffset(acetime_t epochSeconds) const override
Return the DST delta offset at epochSeconds.
DateTuple transitionTimeS
Version of transitionTime in 's' mode, using the UTC offset of the previous Transition.
acetime_t startEpochSeconds
The calculated transition time of the given rule.
A simple tuple to represent a year/month pair.
static LocalDate forEpochSeconds(acetime_t epochSeconds)
Factory method using the number of seconds since AceTime epoch of 2000-01-01.
static TimeOffset forOffsetCode(int8_t offsetCode)
Create TimeOffset from the offset code.
void resetTransitionHighWater()
Reset the TransitionStorage high water mark.
bool active
Flag used for 2 slightly different meanings at different stages of init() processing.
uint32_t getZoneId() const override
Return the unique stable zoneId.
The date (year, month, day), time (hour, minute, second) and offset from UTC (timeOffset).
void log() const
Used only for debugging.
Transition ** reservePrior()
Allocate one Transition just after the Active pool, but before the Candidate pool, to keep the most recent prior Transition.
static const int8_t kInvalidYearTiny
Sentinel yearTiny which indicates an error condition or sometimes a year that 'does not exist'...
void resetHighWater()
Reset the high water mark.
void log() const
Used only for debugging.
A thin wrapper that represents a time offset from a reference point, usually 00:00 at UTC...
int8_t deltaCode
The DST delta code.
void swap(Transition **a, Transition **b)
Swap 2 transitions.
The date (year, month, day) representing the date without regards to time zone.
DateTuple untilDateTime
Until time expressed using the UTC offset of the current Transition.
void log() const
Used only for debugging.
ExtendedZoneProcessor(const extended::ZoneInfo *zoneInfo=nullptr)
Constructor.
uint8_t getTransitionHighWater() const
Get the TransitionStorage high water mark.
static const int16_t kEpochYear
Base year of epoch.
DateTuple untilDateTime
The effective until time of the matching ZoneEra.
DateTuple startDateTime
Start time expressed using the UTC offset of the current Transition.
uint8_t month() const
Return the month with January=1, December=12.
int16_t year() const
Return the full year instead of just the last 2 digits.
static basic::MonthDay calcStartDayOfMonth(int16_t year, uint8_t month, uint8_t onDayOfWeek, int8_t onDayOfMonth)
Calculate the actual (month, day) of the expresssion (onDayOfWeek >= onDayOfMonth) or (onDayOfWeek <=...
A tuple that represents a date and time, using a timeCode that tracks the time component using 15-min...
Data broker for accessing ZonePolicy in PROGMEM.
const Transition * findTransition(acetime_t epochSeconds) const
Return the Transition matching the given epochSeconds.
OffsetDateTime getOffsetDateTime(const LocalDateTime &ldt) const override
Return the best estimate of the OffsetDateTime at the given LocalDateTime for the timezone of the cur...
int8_t offsetCode
The base offset code, not the total effective UTC offset.
ZoneRuleBroker rule
The Zone transition rule that matched for the the given year.
Data structure that captures the matching ZoneEra and its ZoneRule transitions for a given year...
Class that holds the date-time as the components (year, month, day, hour, minute, second) without reg...