22
33## Table of Contents
44
5+ * [ Migrating to v2.0.0] ( #MigratingToVersion200 )
6+ * [ High Level] ( #HighLevel200 )
7+ * [ Details] ( #Details200 )
8+ * [ Background Motivation] ( #Motivation200 )
59* [ Migrating to v1.9.0] ( #MigratingToVersion190 )
610 * [ Configuring the Zone Managers] ( #ConfiguringZoneManagers )
711 * [ Using the Zone Managers] ( #UsingZoneManagers )
1115 * [ Migrating the DS3231Clock] ( #MigratingTheDS3231Clock )
1216 * [ Migrating to LinkManagers] ( #MigratingToLinkManagers )
1317
18+ <a name =" MigratingToVersion200 " ></a >
19+ ## Migrating to v2.0
20+
21+ <a name =" HighLevel200 " ></a >
22+ ### High Level
23+
24+ The primary purpose of AceTime v2 is to extend the range of years supported by
25+ the library from ` [2000,2050) ` to ` [2000,10000) ` , while remaining compact enough
26+ to be useful on resource constrained environments like 8-bit AVR processors.
27+ AceTime uses a 32-bit integer to represent the "epoch seconds". This means that
28+ it has a range about 136 years. In version v1, the epoch was hardcoded to be
29+ 2000-01-01T00:00:00, which allowed the "epoch seconds" to support years from
30+ about 1950 to 2050, which got truncated to about 2000 to 2050 for simplicity.
31+ However, in the year 2022, the upper limit of 2050 seems too close for comfort
32+ to use in embedded devices which could last more than 25 years.
33+
34+ One solution for extending the range of the "epoch seconds" is to use a 64-bit
35+ integer instead of a 32-bit integer. This solution is used by many other time
36+ zone libraries. However, 64-bit operations are extremely resource intensive on
37+ 8-bit processors in terms of both flash memory and CPU cycles, and did not seem
38+ appropriate for AceTime which hopes to remain usable on 8-bit processors.
39+
40+ The solution used by AceTime v2 is to keep the "epoch seconds" as a 32-bit
41+ integer, but allow the ** epoch year** to be adjustable instead of being
42+ hardcoded to the year 2000. Downstream applications can select an epoch year
43+ that is appropriate for their use case, allowing AceTime to be valid over
44+ roughly a 100-year interval straddling the epoch year. For example, if the epoch
45+ year is set to 2100 (so that the epoch is 2100-01-01T00:00:00), AceTime will
46+ work for the years 2050 to 2150. The assumption is that a 100-year interval is
47+ sufficient for most embedded applications.
48+
49+ With the epoch year being adjustable, it becomes necessary to decouple the
50+ various ` year ` fields in the TZDB database (implemented by the ` zonedb ` and
51+ ` zonedbx ` packages) from the ` year ` fields in the AceTime library code itself.
52+ Previously in v1, the ` year ` fields were encoded as 8-bit ` int8_t ` integers
53+ which were interpreted to be offsets from the hardcoded epoch year of 2000. To
54+ allow the zone databases to be valid until the year 10000, the internal ` year `
55+ fields are changed from an ` int8_t ` to a 16-bit ` int16_t ` type. The AceTime API
56+ hides most of the impact of this change from client applications, so the biggest
57+ noticeable change may be the increase in flash size of the ` zonedb ` and
58+ ` zonedbx ` databases which are now 2.5 kiB to 3.5 kiB larger.
59+
60+ The increase in flash size for ` zonedb ` and ` zonedbx ` seems acceptable for the
61+ following reasons: The full impact of the size increase would be felt only if
62+ the application incorporated the entire ` zonedb ` or ` zonedbx ` database to
63+ support all 595 time zones in the TZDB database. But most 8-bit processors do
64+ not have enough flash memory to use the full database (e.g. 23 kiB for ` zonedb ` ,
65+ 38 kiB for ` zonedbx ` ), so it is likely that these 8-bit applications would use
66+ only a small subset (1-10) of the timezones available in those databases. The
67+ flash size increase would be far smaller when using only small number of time
68+ zones. On 32-bit processors where the full database would likely be used, they
69+ often have far more flash memory (0.5 MiB to 4 MiB on ESP8266 or ESP32), so the
70+ increase of 2.5-3.5 kiB of flash memory would be negligible on those processors.
71+
72+ Some backwards incompatible changes were necessary from v1 to v2. These are
73+ explained in detail in the next section.
74+
75+ <a name =" Details200 " ></a >
76+ ### Details
77+
78+ AceTime v2 implements the following major changes and features:
79+
80+ * the internal ` year ` field in various classes (` LocalDate ` , ` LocalDateTime ` ,
81+ ` OffsetDateTime ` , ` ZonedDateTime ` ) changes from ` int8_t ` to an ` int16_t `
82+ * the range increases from ` [1873,2127] ` to ` [1,9999] `
83+ * the various ` year() ` methods in these classes were already using ` int16_t `
84+ so this internal change should be mostly invisible to client applications
85+ * the ` year ` fields in the ` zonedb ` and ` zonedbx ` databases also change from
86+ ` int8_t ` to ` int16_t `
87+ * the year range increases from ` [2000,2049] ` to ` [2000,9999] `
88+ * decouples the TZ database from the adjustable current epoch year
89+ * removed constants
90+ * ` LocalDate::kEpochYear `
91+ * replacement: ` Epoch::currentEpochYear() ` function
92+ * reason: no longer a constant
93+ * ` LocalDate::kSecondsSinceUnixEpoch `
94+ * purpose: number of seconds from 1970 to the AceTime epoch (2000-01-01
95+ in v1, but adjustable in v2)
96+ * replacement: ` Epoch::secondsToCurrentEpochFromUnixEpoch64() `
97+ * reasons:
98+ * ` int32_t ` seconds can overflow, so use ` int64_t `
99+ * epoch year is now adjustable, not a constant
100+ * ` LocalDate::kDaysSinceUnixEpoch `
101+ * purpose: number of days from 1970-01-01 to AceTime epoch (2000-01-01
102+ in v1, but adjustable in v2)
103+ * replacement: ` Epoch::daysToCurrentEpochFromUnixEpoch() `
104+ * reason: epoch is now adjustable, so must become a function
105+ * ` LocalDate::kMinYearTiny `
106+ * replacement: ` LocalDate::kMinYear `
107+ * reason: 8-bit offset no longer used, replaced by 16-bit integer
108+ * ` LocalDate::kMaxYearTiny `
109+ * replacement: ` LocalDate::kMaxYear `
110+ * reason: 8-bit offset no longer used, replaced by 16-bit integer
111+ * ` LocalDate::kInvalidUnixDays `
112+ * replacement: ` kInvalidEpochDays `
113+ * reason: simplification, both had the same value ` INT32_MIN `
114+ * ` LocalDate::kInvalidUnixSeconds `
115+ * replacement: ` LocalDate::kInvalidUnixSeconds64 `
116+ * reason: 32-bit versions of ` toUnixSeconds() ` removed
117+ * removed functions
118+ * ` LocalDate::toUnixSeconds() `
119+ * reason: 32-bit Unix seconds will overflow in the year 2038
120+ * replacement: ` LocalDate::toUnixSeconds64() `
121+ * ` LocalDate::forUnixSeconds() `
122+ * reason: 32-bit Unix seconds will overflow in the year 2038
123+ * replacement: ` LocalDate::forUnixSeconds64() `
124+ * ` LocalDate::yearTiny() `
125+ * reason: ` int8_t ` year fields replaced by ` int16_t ` type
126+ * ` LocalDate::forTinyComponents() ` (undocumented)
127+ * reason: ` int8_t ` year fields replaced by ` int16_t ` type
128+ * ` OffsetDateTime::toUnixSeconds() `
129+ * ` OffsetDateTime::forUnixSeconds() `
130+ * ` OffsetDateTime::yearTiny() `
131+ * ` ZonedDateTime::toUnixSeconds() `
132+ * ` ZonedDateTime::forUnixSeconds() `
133+ * ` ZonedDateTime::yearTiny() `
134+ * new functions
135+ * ` Epoch::currentEpochYear(epochYear) `
136+ * purpose: set the current epoch year
137+ * ` Epoch::currentEpochYear() `
138+ * purpose: get the current epoch year
139+ * ` Epoch::daysToCurrentEpochFromUnixEpoch() `
140+ * purpose: number of days from Unix epoch (1970-01-01) to
141+ the current epoch ({yyyy}-01-01) where ` yyyy ` is set by
142+ ` currentEpochYear(yyyy) `
143+ * ` Epoch::daysToCurrentEpochFromConverterEpoch() `
144+ * purpose: number of days from the converter epoch
145+ (2000-01-01T00:00:00) to the current epoch ({yyyy}-01-01T00:00:00)
146+ where ` yyyy ` is set by ` currentEpochYear(yyyy) `
147+ * comment: should not normally be needed by client applications
148+ * ` Epoch::secondsToCurrentEpochFromUnixEpoch64() `
149+ * purpose: number of seconds from the Unix epoch (1970-01-01T00:00:00)
150+ to the current epoch ({yyyy}-01-01T00:00:00)
151+ * comment: useful for converting between AceTime epoch and Unix epoch
152+ * ` Epoch::epochValidYearLower() `
153+ * purpose: defines lower limit of valid years (` valid_year >= lower ` )
154+ for features related to epochSeconds and timezones
155+ * ` Epoch::epochValidYearUpper() `
156+ * purpose: defines upper limit of valid years (` valid_year < upper ` )
157+ for features related to epochSeconds and timezones
158+
159+ The epochSeconds that was generated by AceTime v1 using the epoch year of 2000
160+ will be incompatible with AceTime v2 using a different epoch year. Client
161+ applications which need read old epochSeconds value using AceTime v2 have a
162+ number of options:
163+
164+ 1 ) Call ` Epoch::currentEpochYear(2000) ` at the beginning of the application,
165+ so that the v2 epoch year is the same as the v1 epoch year. The disadvantage
166+ is that the 32-bit epochSeconds will stop working with this library sometime
167+ around the year 2065-2066.
168+ 2 ) Perform a conversion of the v1 epochSeconds to the v2 epochSeconds by
169+ setting ` Epoch::currentEpochYear(year) ` first, then calculating the new
170+ epochSeconds using `newEpochSeconds = oldEpochSeconds -
171+ Epoch::daysToCurrentEpochFromConverterEpoch() * 86400`.
172+ 3 ) Do no conversion. Just reset the date and time using the new epoch year.
173+ The next time the device is rebooted, the date and time will use the
174+ new epoch year instead of the old epoch year.
175+
176+ <a name =" Motivation200 " ></a >
177+ ### Background Motivation
178+
179+ Using 32-bit integer field for epochSeconds gives a range of about 136 years.
180+ This is the cause of the famous Unix [ Year 2038
181+ problem] ( https://en.wikipedia.org/wiki/Year_2038_problem ) which uses a 32-bit
182+ signed integer starting from the epoch year of 1970 (1970-01-01 00:00:00 UTC).
183+
184+ When the AceTime project started in 2018, using the year 2000 as the epoch year
185+ pushed the theoretical maximum year of epochSeconds to about 2068 which seemed
186+ sufficiently far enough away. The epoch year of 2000 also seemed convenient
187+ because it is the same value used by the [ AVR
188+ libc] ( https://avr-libc.nongnu.org/ ) in its
189+ [ time.h] ( https://avr-libc.nongnu.org/user-manual/group__avr__time.html )
190+ implementation. The actual upper limit was restricted to 2050 to provide some
191+ headroom before calculations would overflow in the year 2068.
192+
193+ Now in the year 2022, the upper limit of 2050 feels too low, since embedded
194+ devices could be reasonably expected to keep working for the next 25 years.
195+ The updated AceTime v2 is designed to support a 100-year interval from
196+ ` [2000,2100) ` by default. To prevent the need to change the source code when the
197+ range needs to extended even further in the future, the "current epoch year" is
198+ made adjustable by the client application.
199+
14200<a name =" MigratingToVersion190 " ></a >
15201## Migrating to v1.9.0
16202
@@ -34,7 +220,7 @@ design consumed an extra 1100-1300 bytes of flash.
34220In v1.9, several changes were made to reduce the flash memory size:
35221
362221 . All virtual methods were removed from the ` ZoneManager ` and its
37- subclasses.
223+ subclasses.
382242 . The ` BasicZoneManager ` and ` ExtendedZoneManager ` classes are no longer
39225 template classes, making them easier to use (e.g. in the ` ZoneSorterByName `
40226 and ` ZoneSorterByOffsetAndName ` classes).
0 commit comments