diff --git a/CHANGELOG.md b/CHANGELOG.md index fb2a9375..2e65f6d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Changelog - unreleased +- 4.1.0 (2025-11-17, TZDB version 2025b) + - **Breaking** Replace `uint8_t ZonedExtra.type()` with `Resolved + ZonedExtra.resolved()` + - `ZonedExtra::resolved()` has the same behavior and semantics as + `ZonedDateTime.resolved()` - 4.0.0 (2025-10-21, TZDB version 2025b) - See [MIGRATING.md](MIGRATING.md) on breaking API changes, and how to migrate. diff --git a/MIGRATING.md b/MIGRATING.md index ecee8e4f..ea931e67 100644 --- a/MIGRATING.md +++ b/MIGRATING.md @@ -2,16 +2,31 @@ ## Table of Contents -* [Migrating to v4.0.0](#MigratingToVersion400) -* [Migrating to v3.0.0](#MigratingToVersion300) -* [Migrating to v2.3.0](#MigratingToVersion220) -* [Migrating to v2.2.0](#MigratingToVersion220) -* [Migrating to v2.1.0](#MigratingToVersion210) -* [Migrating to v2.0.0](#MigratingToVersion200) -* [Migrating to v1.9.0](#MigratingToVersion190) -* [Migrating to v1.8.0](#MigratingToVersion180) - - +* [Migrating to v4.1.0](#migrating-to-v410) +* [Migrating to v4.0.0](#migrating-to-v400) +* [Migrating to v3.0.0](#migrating-to-v300) +* [Migrating to v2.3.0](#migrating-to-v230) +* [Migrating to v2.2.0](#migrating-to-v220) +* [Migrating to v2.1.0](#migrating-to-v210) +* [Migrating to v2.0.0](#migrating-to-v200) +* [Migrating to v1.9.0](#migrating-to-v190) +* [Migrating to v1.8.0](#migrating-to-v180) + +## Migrating to v4.1.0 + +The `uint8_t ZonedExtra::type()` function is replaced with `Resolved +ZonedExtra::resolved()` which returns an enum of type `Resolved`. The new +function has exactly the same behavior and semantics as +`ZonedDateTime::resolved()` which simplifies the implementation and the usage of +the library. + +Here is the mapping from the old values to the new enum: + +- `kTypeNotFound` -> `Resolved::kError` +- `kTypeExact` -> `Resolved::kUnique` +- `kTypeGap` -> `Resolved::kGapEarlier` or `Resolved::kGapLater` +- `kTypeOverlap` -> `Resolved::kOverlapEarlier` or `Resolved::kOverlapLater` + ## Migrating to v4.0.0 These changes were originally intended for 3.0.0, but I ran out of time, so I @@ -93,7 +108,6 @@ the `resolved` parameter which is an enum type of `Resolved`. It has 5 options: If the calling code does not care about how an ambiguity was resolved, then this parameter can be ignored. - ## Migrating to v3.0.0 ### Info Container Class @@ -126,7 +140,6 @@ which may have leaked out is `ace_time::internal::kAbbrevSize` which is the size of the string buffer needed to hold the longest TimeZone abbreviation (e.g. "PST"). This constant is now at `ace_time::kAbbrevSize`. - ## Migrating to v2.3.0 The internal implementation details of various classes have changed @@ -210,7 +223,6 @@ we can be confident that all algorithms (`BasicZoneProcessor`, `zonedbx`, `zonedbc`) in the AceTime library are consistent with these third party libraries. - ## Migrating to v2.2 ### Immutable TimeZone class @@ -250,10 +262,8 @@ TimeZone newTz = TimeZone::forTimeOffset( ZonedDateTime newDt = zdt.convertToTimeZone(newTz); ``` - ## Migrating to v2.1 - ### Unified Links Over the years, I implemented 4 different versions of the Link entries: @@ -307,7 +317,6 @@ only 2 methods which apply only to Link time zones: * Prints the name of the target Zone if the current zone is a link. * It prints nothing is `isLink()` is false. - ### ZonedExtra The `ZonedExtra` class was created to replace 3 ad-hoc query methods on the @@ -333,10 +342,8 @@ The `ZonedExtra` object provides access to other meta-information about the time zone at that particular time. See the [ZonedExtra](USER_GUIDE.md#ZonedExtra) section in the `USER_GUIDE.md` for more detailed information about this class. - ## Migrating to v2.0 - ### High Level The primary purpose of AceTime v2 is to extend the range of years supported by @@ -390,7 +397,6 @@ increase of 2.5-3.5 kiB of flash memory would be negligible on those processors. Some backwards incompatible changes were necessary from v1 to v2. These are explained in detail in the next section. - ### Details AceTime v2 implements the following major changes and features: @@ -491,7 +497,6 @@ number of options: The next time the device is rebooted, the date and time will use the new epoch year instead of the old epoch year. - ### Background Motivation Using 32-bit integer field for epochSeconds gives a range of about 136 years. @@ -515,13 +520,11 @@ The updated AceTime v2 is designed to support a 100-year interval from range needs to extended even further in the future, the "current epoch year" is made adjustable by the client application. - ## Migrating to v1.9.0 The `ZoneManager` hierarchy (containing `ManualZoneManager`, `BasicZoneManager`, and `ExtendedZoneManager`) was refactored from v1.8.0 to v1.9.0. - ### Configuring the Zone Managers In v1.8, the `ZoneManager` was an abstract interface class with 7 pure virtual @@ -588,7 +591,6 @@ ExtendedoneManager zoneManager( zoneProcessorCache); ``` - ### Using the Zone Managers In v1.8, the `ZoneManager` was the parent interface class of all polymorphic @@ -652,7 +654,6 @@ It is assumed that most applications will hard code either the `BasicZoneManager` or the `ExtendedZoneManager`, and will not need this level of configuration. - ### Link Managers In v1.8, the `LinkManager` was an interface class with pure virtual methods: @@ -684,7 +685,6 @@ The `BasicLinkManager` and `ExtendedLinkManager` should be used directly, instead of through the `LinkManager` interface. Since Link Managers were introduced only in v1.8, I expect almost no one to be affected by this. - ## Migrating to v1.8.0 Three breaking changes were made from v1.7.5 to v1.8.0: @@ -708,7 +708,6 @@ Three breaking changes were made from v1.7.5 to v1.8.0: The following subsections show how to migrate client application from AceTime v1.7.5 to AceTime v1.8.0. - ### Migrating to AceTimeClock For AceTime v1.8.0, the clock classes under the `ace_time::clock` namespace have @@ -738,7 +737,6 @@ using namespace ace_time; using namespace ace_time::clock; ``` - ### Migrating the DS3231Clock For AceTime v1.8.0, the `DS3231Clock` class was converted into a template class @@ -834,7 +832,6 @@ consumption by 1500 bytes on an AVR processor. The flash consumption can be reduced by 2000 bytes if the "fast" version `SimpleWireFastInterface` is used instead. - ### Migrating to LinkManagers In v1.7.5, [thin links](USER_GUIDE.md#ThinLinks) were activated by adding the diff --git a/README.md b/README.md index 91f6f298..92eb2ac2 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,18 @@ epoch of 1970-01-01 is provided through conversion functions of the `time_t` type. Only the 64-bit version of the `time_t` type is supported to avoid the [Year 2038 Problem](https://en.wikipedia.org/wiki/Year_2038_problem). +The library does *not* support [leap +seconds](https://en.wikipedia.org/wiki/Leap_second) and ignores them. Instead it +uses [UNIX time](https://en.wikipedia.org/wiki/Unix_time) (aka POSIX time) where +the *POSIX second* is variable in duration compared to the [SI +second](https://en.wikipedia.org/wiki/Second). During a leap second, a POSIX +second is conceptually equal to 2 SI seconds, and the POSIX clock changes from +`23:59:58` to `23:59:59`, then is held for 2 seconds before rolling over to +`00:00:00`. Most real-time clock (RTC) chips do not support leap seconds either, +so the final `23:59:59` second will be held for only one second instead of two, +so a clock using AceTime with such an RTC chip will be off by one second after a +leap second compared to the atomic UTC clock. + The companion library [AceTimeClock](https://github.com/bxparks/AceTimeClock) provides Clock classes to retrieve the time from more accurate sources, such as an [NTP](https://en.wikipedia.org/wiki/Network_Time_Protocol) server, or a @@ -81,14 +93,14 @@ This library can be an alternative to the Arduino Time (https://github.com/JChristensen/Timezone) libraries. **Major Changes in v4.0**: Rename `LocalDate` to `PlainDate`; `LocalTime` to -`PlainTime`; `LocalDateTime` to `PlainDateTime. Backwards compatible macros are +`PlainTime`; `LocalDateTime` to `PlainDateTime`. Backwards compatible macros are provided, so most existing programs should still compile. See [Migrating to v4.0](MIGRATING.md#MigratingToVersion400) for more details. Add `zonedb2025` and `zonedbx2025` databases which contain DST transitions for year >= 2025, which reduces flash memory size. Replace `fold` parameter with `disambiguate` (input) and `resolved` (output) parameters. -**Version**: 4.0.0 (2025-10-21, TZDB 2025b) \ +**Version**: 4.1.0 (2025-11-17, TZDB 2025b) \ **Changelog**: [CHANGELOG.md](CHANGELOG.md) \ **Migration**: [MIGRATING.md](MIGRATING.md) \ **User Guide**: [USER_GUIDE.md](USER_GUIDE.md) @@ -509,6 +521,7 @@ until 2200. - [C++11/14/17 Hinnant date](https://github.com/HowardHinnant/date) library - [GNU libc time](https://www.gnu.org/software/libc/libc.html) library - [C# Noda Time](https://nodatime.org) library +- [Python whenever](https://pypi.org/project/whenever/) - [acetimec](https://github.com/bxparks/acetimec) - C version of AceTime - [acetimego](https://github.com/bxparks/acetimego) - Go or TinyGo version of AceTime diff --git a/USER_GUIDE.md b/USER_GUIDE.md index 670be20b..7d38db0e 100644 --- a/USER_GUIDE.md +++ b/USER_GUIDE.md @@ -19,7 +19,7 @@ The IANA TZ database is programmatically generated into 5 predefined databases: ranges, and are designed to work with different `ZoneProcessor` and `ZoneManager` classes. -**Version**: 4.0.0 (2025-10-21, TZDB 2025b) +**Version**: 4.1.0 (2025-11-17, TZDB 2025b) **Related Documents**: @@ -1616,7 +1616,7 @@ class ZonedExtra { const char* abbrev); bool isError() const; - uint8_t type() const; + Resolved resolved() const; TimeOffset timeOffset() const; // stdOffset + dstOffset TimeOffset stdOffset() const; @@ -1640,9 +1640,10 @@ methods on the `ZonedExtra` class: uint8_t hour, uint8_t minute, uint8_t second, const TimeZone& tz, Disambiguate disambiguate = Disambiguate::kCompatible)` -Often the `ZonedDateTime` will be created first from the epochSeconds, then the -`ZonedExtra` will be created to access additional information about the time -zone at that particular epochSeconds (e.g. abbreviation): +Often the `ZonedDateTime` will be created first using the `forComponents()` or +`forEpochSeconds()` function, then the `ZonedExtra` will be created to access +additional information about the time zone at that particular epochSeconds or +components (e.g. abbreviation): ```C++ ExtendedZoneProcessor zoneProcessor; @@ -1654,9 +1655,11 @@ ZonedDateTime zdt = ZonedDateTime::forEpochSeconds(epochSeconds, tz); ZonedExtra ze = ZonedExtra::forEpochSeconds(epochSeconds, tz); ``` -The `ZonedExtra::type()` parameter identifies whether the given time instant -corresponded to a DST gap, or a DST overlap, or an exact match with no -duplicates. +The `ZonedExtra::resolved()` parameter indicates how `forComponents()` function +resolved a gap or an overlap according to the `disambiguate` parameter. For the +`forEpochSeconds()` function, the resolved parameter will always be +`Resolved::kUnique`. If the `ZonedExtra` instance is an error, then `resolved()` +will return `Resolved::kError`. The `ZonedExtra::stdOffset()` is the standard offset of the timezone at the given time instant. For example, for `America/Los_Angeles` this will return @@ -1683,10 +1686,12 @@ abbreviation is 6 characters long. The `ZonedExtra::reqStdOffset()` and `ZonedExtra::reqDstOffset()` are relevant and different from the corresponding `stdOffset()` and `dstOffset()` only if the -`type()` is `kTypeGap`. This occurs only if the `ZonedExtra::forComponents()` -factory method is used. The `reqStdOffset()` and `reqDstOffset()` are -derived from the transition line that is used to select the earlier or later -`PlainDateTime` instance to `epochSeconds`. +requested `PlainDateTime` was in a gap. In other words, if the +`ZonedExtra::resolved()` is `Resolved::kGapBefore` or `Resolved::kGapAfter`. +This occurs only if the `ZonedExtra::forComponents()` factory method is used. +The `reqStdOffset()` and `reqDstOffset()` are derived from the transition line +that is used to select the earlier or later `PlainDateTime` instance to +`epochSeconds`. The `isError()` method returns true if the given `PlainDateTime` or `epochSeconds` represents an error condition. @@ -2155,10 +2160,11 @@ by JavaScript Temporal and the Python whenever libraries. #### Factory Methods with Disambiguation -There are 2 main factory methods on `ZonedDateTime`: `forEpochSeconds()` and -`forComponents()`. The `disambiguate` parameter applies to only the -`forComponents()` method. The `forEpochSeconds()` function always corresponds to -a unique `ZonedDateTime` object and does not need a `disambiguate` argument. +The `ZonedDateTime` and `ZonedExtra` classes have 2 factory methods: +`forEpochSeconds()` and `forComponents()`. The `disambiguate` parameter applies +to only the `forComponents()` method. The `forEpochSeconds()` function always +corresponds to a unique `ZonedDateTime` object and does not need a +`disambiguate` argument. The `disambiguate` parameter is an enum type that takes 4 values: @@ -2178,12 +2184,14 @@ then the `disambiguate` parameter has no effect, because it maps to a unique #### Resolved Disambiguation -When the `forComponents()` method returns a `ZonedDateTime`, it is sometimes -useful to know how the `disambiguate` parameter selected the result. The -`ZonedDateTime` object exposes a `ZonedDateTime::resolved()` variable. It -takes 5 values: +The `ZonedDateTime::forComponents()` method and the +`ZonedExtra::forComponents()` functions accept the `disambiguate` parameter to +control what happens during a gap or an overlap. The resulting `ZonedDateTime` +or `ZonedExtra` exposes a `resolved()` function that returns an enum of type +`Resolved` which takes 6 values: -- `Resolved::kUnique` - the ZonedDateTime is unique +- `Resolved::kError` - the result was not found or an error occurred +- `Resolved::kUnique` - the ZonedDateTime or ZonedExtra is unique - `Resolved::kOverlapEarlier` - the earlier time in an overlap was selected - `Resolved::kOverlapLater` - the later time in an overlap was selected - `Resolved::kGapEarlier` - the earlier time in a gap was selected diff --git a/docs/README.md b/docs/README.md index 55209555..90222aa0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,24 @@ # Documentation -* The `html` directory contains the programmatically generated - [Doxygen docs](https://bxparks.github.io/AceTime/html/) which are viewable on - GitHub Pages. -* The other files are various subsections of the User Guide which are linked - from the main [README.md](../README.md). +The main [README.md](../README.md) and [USER_GUIDE.md](../USER_GUIDE.md) +contain the majority of the documentation. + +This directory contains scripts to generate [doxygen](https://www.doxygen.nl/) +documentation from the embedded docstrings in the code. + +First, install doxygen and GNU Make if you don't already have them, with +something like the following on an Ubuntu Linux machine: + +``` +$ sudo apt install doxygen make +``` + +Second, run the `make` command to generate the HTML files under the `html` +directory: + +``` +$ cd docs +$ make +``` + +Third, open the `./docs/html/index.html` file in your web browser. diff --git a/docs/doxygen.cfg b/docs/doxygen.cfg index b6e5ed10..d6185fa8 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 = 3.0.0 +PROJECT_NUMBER = 4.1.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/examples/AutoBenchmark/Benchmark.cpp b/examples/AutoBenchmark/Benchmark.cpp index 6d21cb3b..1fefb636 100644 --- a/examples/AutoBenchmark/Benchmark.cpp +++ b/examples/AutoBenchmark/Benchmark.cpp @@ -127,7 +127,7 @@ void disableOptimization(uint32_t value) { } void disableOptimization(const ZonedExtra& extra) { - guard ^= extra.type() & 0xff; + guard ^= (uint8_t)extra.resolved() & 0xff; guard ^= extra.timeOffset().toMinutes() & 0xff; guard ^= *extra.abbrev(); } diff --git a/library.properties b/library.properties index 0cd36656..c1734ead 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=AceTime -version=4.0.0 +version=4.1.0 author=Brian T. Park maintainer=Brian T. Park sentence=Date, time, timezone classes for Arduino supporting the full IANA TZ Database to convert epoch seconds to date and time components in different time zones. diff --git a/src/AceTime.h b/src/AceTime.h index 37c2fdfd..eee6a055 100644 --- a/src/AceTime.h +++ b/src/AceTime.h @@ -77,7 +77,7 @@ #include "zonedbc/zone_registry.h" // Version format: xxyyzz == "xx.yy.zz" -#define ACE_TIME_VERSION 40000 -#define ACE_TIME_VERSION_STRING "4.0.0" +#define ACE_TIME_VERSION 40100 +#define ACE_TIME_VERSION_STRING "4.1.0" #endif diff --git a/src/ace_time/PlainTime.h b/src/ace_time/PlainTime.h index ddbfa857..0f146664 100644 --- a/src/ace_time/PlainTime.h +++ b/src/ace_time/PlainTime.h @@ -60,18 +60,21 @@ class PlainTime { */ static PlainTime forSeconds(acetime_t seconds) { uint8_t second, minute, hour; + Resolved resolved; if (seconds == kInvalidSeconds) { second = minute = hour = kInvalidValue; // causes isError() to be true + resolved = Resolved::kError; } else { second = seconds % 60; uint16_t minutes = seconds / 60; minute = minutes % 60; hour = minutes / 60; + resolved = Resolved::kUnique; } // Return a single object to allow return value optimization. - return PlainTime(hour, minute, second); + return PlainTime(hour, minute, second, resolved); } /** @@ -98,7 +101,9 @@ class PlainTime { * condition. The isError() method will return true. */ static PlainTime forError() { - return PlainTime(kInvalidValue, kInvalidValue, kInvalidValue); + return PlainTime( + kInvalidValue, kInvalidValue, kInvalidValue, Resolved::kError + ); } /** Default constructor does nothing. */ diff --git a/src/ace_time/TimeZone.h b/src/ace_time/TimeZone.h index 9b49b56f..bf9f5110 100644 --- a/src/ace_time/TimeZone.h +++ b/src/ace_time/TimeZone.h @@ -317,7 +317,7 @@ class TimeZone { abbrev = (mDstOffsetMinutes != 0) ? "DST" : "STD"; } return ZonedExtra( - ZonedExtra::kTypeExact, + Resolved::kUnique, mStdOffsetMinutes * 60, mDstOffsetMinutes * 60, mStdOffsetMinutes * 60, @@ -330,8 +330,10 @@ class TimeZone { if (result.type == FindResult::kTypeNotFound) { return ZonedExtra::forError(); } + Resolved resolved = + resolveForResultTypeAndFold(result.type, result.fold); return ZonedExtra( - result.type, // ZonedExtra::type is identical to FindResult::type + resolved, result.stdOffsetSeconds, result.dstOffsetSeconds, result.reqStdOffsetSeconds, @@ -356,7 +358,7 @@ class TimeZone { abbrev = (mDstOffsetMinutes != 0) ? "DST" : "STD"; } return ZonedExtra( - ZonedExtra::kTypeExact, + Resolved::kUnique, mStdOffsetMinutes * 60, mDstOffsetMinutes * 60, mStdOffsetMinutes * 60, @@ -370,7 +372,7 @@ class TimeZone { return ZonedExtra::forError(); } return ZonedExtra( - result.type, // ZonedExtra::type is identical to FindResult::type + Resolved::kUnique, result.stdOffsetSeconds, result.dstOffsetSeconds, result.reqStdOffsetSeconds, diff --git a/src/ace_time/ZonedDateTime.h b/src/ace_time/ZonedDateTime.h index abebfa64..999c84ae 100644 --- a/src/ace_time/ZonedDateTime.h +++ b/src/ace_time/ZonedDateTime.h @@ -215,7 +215,7 @@ class ZonedDateTime { /** Set the second. */ void second(uint8_t second) { mOffsetDateTime.second(second); } - /** Return the resolved. */ + /** Return how disambiguate was resolved. */ Resolved resolved() const { return mOffsetDateTime.resolved(); } /** Set the resolved. */ diff --git a/src/ace_time/ZonedExtra.h b/src/ace_time/ZonedExtra.h index 224c7117..daced094 100644 --- a/src/ace_time/ZonedExtra.h +++ b/src/ace_time/ZonedExtra.h @@ -21,37 +21,6 @@ class ZonedExtra { /** Size of char buffer needed to hold the largest abbreviation. */ static const uint8_t kAbbrevSize = ace_time::kAbbrevSize; - /** - * The epochSeconds or PlainDateTime was not found because it was outside - * the range of the zoneinfo database (too far past, or too far in the - * future). - */ - static const uint8_t kTypeNotFound = 0; - - /** - * The given PlainDateTime matches a single epochSeconds. - * The given epochSeconds matches a single PlainDateTime. - */ - static const uint8_t kTypeExact = 1; - - /** - * The given PlainDateTime occurs in a gap and does not match any - * epochSeconds. - * - * A given epochSeconds will never return this because it will always match - * a unique PlainDateTime. - */ - static const uint8_t kTypeGap = 2; - - /** - * The given PlainDateTime matches 2 possible epochSeconds, which is - * disambiguated by the 'disambiguate' parameter in the lookup function. - * - * A look up using epochSeconds will never return this because it will - * always match a unique PlainDateTime. - */ - static const uint8_t kTypeOverlap = 3; - /** Return an instance that indicates an error. */ static ZonedExtra forError() { return ZonedExtra(); @@ -97,17 +66,17 @@ class ZonedExtra { /** Constructor */ explicit ZonedExtra( - uint8_t type, + Resolved resolved, int32_t stdOffsetSeconds, int32_t dstOffsetSeconds, int32_t reqStdOffsetSeconds, int32_t reqDstOffsetSeconds, const char* abbrev) - : mStdOffsetSeconds(stdOffsetSeconds) + : mResolved(resolved) + , mStdOffsetSeconds(stdOffsetSeconds) , mDstOffsetSeconds(dstOffsetSeconds) , mReqStdOffsetSeconds(reqStdOffsetSeconds) , mReqDstOffsetSeconds(reqDstOffsetSeconds) - , mType(type) { strncpy(mAbbrev, abbrev, kAbbrevSize - 1); mAbbrev[kAbbrevSize - 1] = '\0'; @@ -115,10 +84,11 @@ class ZonedExtra { /** Indicates that the PlainDateTime or epochSeconds was not found. */ bool isError() const { - return mStdOffsetSeconds == kInvalidSeconds; + return mResolved == Resolved::kError; } - uint8_t type() const { return mType; } + /** Return how disambiguate was resolved. */ + Resolved resolved() const { return mResolved; } /** STD offset of the resulting OffsetDateTime. */ TimeOffset stdOffset() const { @@ -180,11 +150,11 @@ class ZonedExtra { private: static const int32_t kInvalidSeconds = INT32_MIN; + Resolved mResolved = Resolved::kError; int32_t mStdOffsetSeconds = kInvalidSeconds; int32_t mDstOffsetSeconds = kInvalidSeconds; int32_t mReqStdOffsetSeconds = kInvalidSeconds; int32_t mReqDstOffsetSeconds = kInvalidSeconds; - uint8_t mType = kTypeNotFound; char mAbbrev[kAbbrevSize] = ""; }; diff --git a/src/ace_time/common/common.h b/src/ace_time/common/common.h index 4ac87f1a..7a546bec 100644 --- a/src/ace_time/common/common.h +++ b/src/ace_time/common/common.h @@ -77,36 +77,39 @@ enum class Disambiguate : uint8_t { }; /** - * These are the ways that a given PlainDateTime was resolved to a - * ZonedDateTime, depending on whether the PlainDateTime occurred in an overlap, - * a gap, or was a unique mapping. + * The ways that a given PlainDateTime was resolved to a ZonedDateTime or + * ZonedExtra through the `disambiguate` parameter, depending on whether the + * PlainDateTime occurred in an overlap, a gap, or was a unique mapping. */ enum class Resolved : uint8_t { + /** PlainDateTime could not be resolved. */ + kError = 0, + /** PlainDateTime was resolved to a unique ZonedDateTime. */ - kUnique = 0, + kUnique = 1, /** PlainDateTime was in an overlap, and resolved to the earlier * ZonedDateTime. */ - kOverlapEarlier = 1, + kOverlapEarlier = 2, /** PlainDateTime was in an overlap, and resolved to the later ZonedDateTime. */ - kOverlapLater = 2, + kOverlapLater = 3, /** * PlainDateTime was in a gap, and resolved to the earlier ZonedDateTime that * would have matched if we had extended the later transition rule backwards * in time. */ - kGapEarlier = 3, + kGapEarlier = 4, /** * PlainDateTime was in a gap, and resolved to the later ZonedDateTime * that would have matched if we had extended the earlier transition rule * forwards in time. */ - kGapLater = 4, + kGapLater = 5, }; } // ace_time diff --git a/tests/TimeZoneTest/TimeZoneTest.ino b/tests/TimeZoneTest/TimeZoneTest.ino index ffb5bd5d..0652b7da 100644 --- a/tests/TimeZoneTest/TimeZoneTest.ino +++ b/tests/TimeZoneTest/TimeZoneTest.ino @@ -69,7 +69,7 @@ test(TimeZoneTest, forUtc) { ZonedExtra ze = tz.getZonedExtra(0); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(0, ze.stdOffset().toMinutes()); assertEqual(0, ze.dstOffset().toMinutes()); assertEqual(0, ze.reqStdOffset().toMinutes()); @@ -96,7 +96,7 @@ test(TimeZoneTest, forTimeOffset_no_dst) { ZonedExtra ze = tz.getZonedExtra(0); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -126,7 +126,7 @@ test(TimeZoneTest, forTimeOffset_dst) { ZonedExtra ze = tz.getZonedExtra(0); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -196,7 +196,7 @@ test(TimeZoneBasicTest, getZonedExtra) { pdt = PlainDateTime::forComponents(2018, 3, 11, 1, 59, 59); ze = tz.getZonedExtra(pdt, Disambiguate::kCompatible); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -208,7 +208,7 @@ test(TimeZoneBasicTest, getZonedExtra) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -219,7 +219,7 @@ test(TimeZoneBasicTest, getZonedExtra) { pdt = PlainDateTime::forComponents(2018, 3, 11, 2, 0, 0); ze = tz.getZonedExtra(pdt, Disambiguate::kCompatible); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeGap, ze.type()); + assertEqual((uint8_t)Resolved::kGapLater, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -231,7 +231,7 @@ test(TimeZoneBasicTest, getZonedExtra) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -267,7 +267,7 @@ test(TimeZoneBasicTest, link) { // 01:59:59 is before gap pdt = PlainDateTime::forComponents(2018, 3, 11, 1, 59, 59); ze = tz.getZonedExtra(pdt, Disambiguate::kCompatible); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -279,7 +279,7 @@ test(TimeZoneBasicTest, link) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -290,7 +290,7 @@ test(TimeZoneBasicTest, link) { pdt = PlainDateTime::forComponents(2018, 3, 11, 2, 0, 0); ze = tz.getZonedExtra(pdt, Disambiguate::kCompatible); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeGap, ze.type()); + assertEqual((uint8_t)Resolved::kGapLater, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -302,7 +302,7 @@ test(TimeZoneBasicTest, link) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -404,7 +404,7 @@ test(TimeZoneExtendedTest, getZoneExtra) { pdt = PlainDateTime::forComponents(2018, 3, 11, 1, 59, 59); ze = tz.getZonedExtra(pdt, Disambiguate::kCompatible); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -416,7 +416,7 @@ test(TimeZoneExtendedTest, getZoneExtra) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -427,7 +427,7 @@ test(TimeZoneExtendedTest, getZoneExtra) { pdt = PlainDateTime::forComponents(2018, 3, 11, 2, 0, 0); ze = tz.getZonedExtra(pdt, Disambiguate::kCompatible); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeGap, ze.type()); + assertEqual((uint8_t)Resolved::kGapLater, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -439,7 +439,7 @@ test(TimeZoneExtendedTest, getZoneExtra) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -450,7 +450,7 @@ test(TimeZoneExtendedTest, getZoneExtra) { pdt = PlainDateTime::forComponents(2018, 11, 4, 0, 59, 0); ze = tz.getZonedExtra(pdt, Disambiguate::kCompatible); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -462,7 +462,7 @@ test(TimeZoneExtendedTest, getZoneExtra) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -473,7 +473,7 @@ test(TimeZoneExtendedTest, getZoneExtra) { pdt = PlainDateTime::forComponents(2018, 11, 4, 1, 0, 0); ze = tz.getZonedExtra(pdt, Disambiguate::kCompatible); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeOverlap, ze.type()); + assertEqual((uint8_t)Resolved::kOverlapEarlier, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -485,7 +485,7 @@ test(TimeZoneExtendedTest, getZoneExtra) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeOverlap, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -496,7 +496,7 @@ test(TimeZoneExtendedTest, getZoneExtra) { pdt = PlainDateTime::forComponents(2018, 11, 4, 1, 0, 0); ze = tz.getZonedExtra(pdt, Disambiguate::kReversed); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeOverlap, ze.type()); + assertEqual((uint8_t)Resolved::kOverlapLater, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -508,7 +508,7 @@ test(TimeZoneExtendedTest, getZoneExtra) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeOverlap, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -519,7 +519,7 @@ test(TimeZoneExtendedTest, getZoneExtra) { pdt = PlainDateTime::forComponents(2018, 11, 4, 2, 0, 0); ze = tz.getZonedExtra(pdt, Disambiguate::kCompatible); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -531,7 +531,7 @@ test(TimeZoneExtendedTest, getZoneExtra) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -568,7 +568,7 @@ test(TimeZoneExtendedTest, link) { pdt = PlainDateTime::forComponents(2018, 3, 11, 1, 59, 59); ze = tz.getZonedExtra(pdt, Disambiguate::kCompatible); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -580,7 +580,7 @@ test(TimeZoneExtendedTest, link) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -591,7 +591,7 @@ test(TimeZoneExtendedTest, link) { pdt = PlainDateTime::forComponents(2018, 3, 11, 2, 0, 0); ze = tz.getZonedExtra(pdt, Disambiguate::kCompatible); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeGap, ze.type()); + assertEqual((uint8_t)Resolved::kGapLater, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -603,7 +603,7 @@ test(TimeZoneExtendedTest, link) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -647,7 +647,7 @@ test(TimeZoneCompleteTest, getZoneExtra) { pdt = PlainDateTime::forComponents(2018, 3, 11, 1, 59, 59); ze = tz.getZonedExtra(pdt, Disambiguate::kCompatible); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -659,7 +659,7 @@ test(TimeZoneCompleteTest, getZoneExtra) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -670,7 +670,7 @@ test(TimeZoneCompleteTest, getZoneExtra) { pdt = PlainDateTime::forComponents(2018, 3, 11, 2, 0, 0); ze = tz.getZonedExtra(pdt, Disambiguate::kCompatible); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeGap, ze.type()); + assertEqual((uint8_t)Resolved::kGapLater, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -682,7 +682,7 @@ test(TimeZoneCompleteTest, getZoneExtra) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -693,7 +693,7 @@ test(TimeZoneCompleteTest, getZoneExtra) { pdt = PlainDateTime::forComponents(2018, 11, 4, 0, 59, 0); ze = tz.getZonedExtra(pdt, Disambiguate::kCompatible); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -705,7 +705,7 @@ test(TimeZoneCompleteTest, getZoneExtra) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -716,7 +716,7 @@ test(TimeZoneCompleteTest, getZoneExtra) { pdt = PlainDateTime::forComponents(2018, 11, 4, 1, 0, 0); ze = tz.getZonedExtra(pdt, Disambiguate::kCompatible); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeOverlap, ze.type()); + assertEqual((uint8_t)Resolved::kOverlapEarlier, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -728,7 +728,7 @@ test(TimeZoneCompleteTest, getZoneExtra) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeOverlap, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -739,7 +739,7 @@ test(TimeZoneCompleteTest, getZoneExtra) { pdt = PlainDateTime::forComponents(2018, 11, 4, 1, 0, 0); ze = tz.getZonedExtra(pdt, Disambiguate::kReversed); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeOverlap, ze.type()); + assertEqual((uint8_t)Resolved::kOverlapLater, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -751,7 +751,7 @@ test(TimeZoneCompleteTest, getZoneExtra) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeOverlap, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -762,7 +762,7 @@ test(TimeZoneCompleteTest, getZoneExtra) { pdt = PlainDateTime::forComponents(2018, 11, 4, 2, 0, 0); ze = tz.getZonedExtra(pdt, Disambiguate::kCompatible); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -774,7 +774,7 @@ test(TimeZoneCompleteTest, getZoneExtra) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -811,7 +811,7 @@ test(TimeZoneCompleteTest, link) { pdt = PlainDateTime::forComponents(2018, 3, 11, 1, 59, 59); ze = tz.getZonedExtra(pdt, Disambiguate::kCompatible); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -823,7 +823,7 @@ test(TimeZoneCompleteTest, link) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(0*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -834,7 +834,7 @@ test(TimeZoneCompleteTest, link) { pdt = PlainDateTime::forComponents(2018, 3, 11, 2, 0, 0); ze = tz.getZonedExtra(pdt, Disambiguate::kCompatible); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeGap, ze.type()); + assertEqual((uint8_t)Resolved::kGapLater, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); @@ -846,7 +846,7 @@ test(TimeZoneCompleteTest, link) { epochSeconds = dt.toEpochSeconds(); ze = tz.getZonedExtra(epochSeconds); assertFalse(ze.isError()); - assertEqual(ZonedExtra::kTypeExact, ze.type()); + assertEqual((uint8_t)Resolved::kUnique, (uint8_t)ze.resolved()); assertEqual(-8*60, ze.stdOffset().toMinutes()); assertEqual(1*60, ze.dstOffset().toMinutes()); assertEqual(-8*60, ze.reqStdOffset().toMinutes()); diff --git a/tests/ZonedExtraTest/ZonedExtraTest.ino b/tests/ZonedExtraTest/ZonedExtraTest.ino index e041c789..026ef424 100644 --- a/tests/ZonedExtraTest/ZonedExtraTest.ino +++ b/tests/ZonedExtraTest/ZonedExtraTest.ino @@ -14,18 +14,11 @@ test(ZonedExtra, isError) { assertTrue(ze.isError()); } -test(ZonedExtra, type) { - assertEqual(ZonedExtra::kTypeNotFound, FindResult::kTypeNotFound); - assertEqual(ZonedExtra::kTypeExact, FindResult::kTypeExact); - assertEqual(ZonedExtra::kTypeGap, FindResult::kTypeGap); - assertEqual(ZonedExtra::kTypeOverlap, FindResult::kTypeOverlap); -} - test(ZonedExtra, accessors) { const char s[] = "test"; - ZonedExtra ze(1, 2, 3, 4, 5, s); + ZonedExtra ze(Resolved::kUnique, 2, 3, 4, 5, s); - assertEqual(ze.type(), 1); + assertEqual((uint8_t)ze.resolved(), (uint8_t)Resolved::kUnique); assertEqual(ze.stdOffset().toSeconds(), 2); assertEqual(ze.dstOffset().toSeconds(), 3); assertEqual(ze.timeOffset().toSeconds(), 2+3);