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);