Skip to content

Commit 1a98be0

Browse files
authored
Merge pull request #93 from bxparks/develop
merge v1.10.0 into master
2 parents 02ff26c + 1dbb0b3 commit 1a98be0

File tree

541 files changed

+10549
-6774
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

541 files changed

+10549
-6774
lines changed

.github/workflows/aunit_tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on: [push]
99
jobs:
1010
build:
1111

12-
runs-on: ubuntu-18.04
12+
runs-on: ubuntu-20.04
1313

1414
steps:
1515
- uses: actions/checkout@v2

.github/workflows/validation.yml

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
# https://github.com/actions/checkout#Checkout-multiple-repos-side-by-side,
1616
# but it looks like GITHUB_WORKSPACE is set to
1717
# /home/runner/work/AceTime/AceTime, so if path is set to 'main' as
18-
# suggested in the article, then the repos is set to
18+
# suggested in the article, then the repo location is set to
1919
# /home/runner/work/Acetime/AceTime/main/AceTime, which is really
2020
# confusing. Instead, use 'cd ..' to go up a level and call 'git clone'
2121
# manually.
@@ -57,16 +57,13 @@ jobs:
5757
sudo apt update
5858
sudo apt install -y libcurl4-openssl-dev
5959
60-
- name: Build compare_cpp
61-
run: |
62-
make -C ../AceTimeTools/compare_cpp
63-
6460
# Run the validations from AceTimeValidations (BasicHinnantDateTest,
6561
# ExtendedHinnantDateTest, BasicAcetzTest, ExtendedAcetzTest). We don't run
66-
# the others because when a new TZDB version comes out, the Python pytz,
67-
# dateutil, and Java validation tests will fail because they depend
68-
# on the obsolete TZ database on the host Operating System.
69-
62+
# the others because when a new TZDB version comes out, the Python
63+
# zoneinfo, Python pytz, Python dateutil, and Java validation tests will
64+
# fail because they depend on the obsolete TZ database on the host
65+
# Operating System. The 'make validations' will also compile the binary in
66+
# AceTimeValidation/compare_cpp/ as necessary.
7067
- name: AceTimeValidation
7168
run: |
7269
cd ../AceTimeValidation

CHANGELOG.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,39 @@
11
# Changelog
22

33
* Unreleased
4+
* 1.10.0 (2022-01-18, TZDB 2021e)
5+
* MemoryBenchmark: Add memory consumption for `ZoneSorterByName` and
6+
`ZoneSorterByOffsetAndName`.
7+
* AVR: 180-530 bytes of flash
8+
* 32-bit: 120-600 bytes of flash
9+
* Rename internal `TransitionStorage::findTransition()` to
10+
`findTransitionForSeconds()` for better self-documentation.
11+
* Move third party SAMD21 boards to new Tier 3 (May work, but not supported)
12+
level.
13+
* I can no longer upload binaries to these boards using Arduino IDE
14+
1.8.19 and SparkFun SAMD Core 1.8.6.
15+
* Add support for `fold` parameter to control behavior around DST gaps
16+
and overlaps.
17+
* The semantics of the `fold` parameter is intended to be identical to
18+
[Python PEP 495](https://www.python.org/dev/peps/pep-0495).
19+
* Add `LocalTime::fold()`, `LocalDateTime::fold()`,
20+
`OffsetDateTime::fold()`, `ZonedDateTime::fold()`.
21+
* Update `ExtendedZoneProcessor::getOffsetDateTime(acetime_t)` to
22+
calculate the `OffsetDateTime::fold()` as an output parameter.
23+
* Update `ExtendedZoneProcessor::getOffsetDateTime(const
24+
LocalDateTime&)` to handle `LocalDateTime::fold()` as an input
25+
parameter.
26+
* Increases flash usage of `ExtendedZoneProcessor` by around 600 bytes
27+
on AVR, and 400-600 bytes on 32-bit processors.
28+
* Add `toUnixSeconds64()` and `forUnixSeconds64()` methods to
29+
`LocalDate`, `LocalDateTime`, `OffsetDateTime`, `ZonedDateTime`.
30+
* These use 64-bit `int64_t` integers, which allows Unix seconds to be
31+
used up to 2068-01-19T03:14:07Z (which is the limit of these
32+
various classes due to the internal use of 32-bit `acetime_t`).
33+
* These methods make it easier to interoperate with the `time_t` typedef
34+
for `int64_t` on the ESP8266 and ESP32 platforms.
35+
* Add [EspTime](examples/EspTime) app that shows how to integrate
36+
the SNTP client on the ESP8266 and ESP32 platforms with AceTime.
437
* 1.9.0 (2021-12-02, TZDB 2021e)
538
* Add `ZoneSorterByName` and `ZoneSorterByOffsetAndName` classes
639
to sort zone indexes, ids, or names according to 2 pre-defined sorting

DEVELOPER.md

Lines changed: 56 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Here is the dependency diagram among these projects.
3636
AceTimeTools --------
3737
^ ^ ^ \ artransformer.py
3838
creating / | \ creating \ -> bufestimator.py
39-
zonedb[x] / | \ zonedbpy \ -> zone_processor.py
39+
zonedb[x] / | \ zonedb \ -> zone_processor.py
4040
/ | \ v
4141
AceTime | AceTimePython
4242
^ ^ | ^
@@ -54,7 +54,7 @@ the buffer sizes needed by the C++ `ExtendedZoneProcessor` class. The
5454
module to calculate those buffer sizes.
5555

5656
On the other hand, AceTimePython needs AceTimeTools to generate the zoneinfo
57-
files under `AceTimePython/zonedbpy`, which are consumed by the `acetz.py`
57+
files under `AceTimePython/zonedb`, which are consumed by the `acetz.py`
5858
module. Fortunately, AceTimePython does *not* need AceTimeTools during runtime,
5959
so 3rd party consumers can incorporate AceTimePython without pulling in
6060
AceTimeTools.
@@ -289,31 +289,60 @@ SAVE (15-min resolution)
289289
<a name="ExtendedZoneProcessor"></a>
290290
## ExtendedZoneProcessor
291291

292-
To save memory, the `ExtendedZoneProcessor` class calculates the `Transition`
293-
objects on the fly when the `initForEpochSeconds(acetime_t)` or
294-
`initForYear(int16_t)` method is called. The alternative used by most Date-Time
295-
libraries to precalculate the Transitions for all Zones, for a certain range of
296-
years. Precalculation is definitely faster, and easier because the logic for
297-
calculating the Transition objects resides in only a single place. However, the
298-
expansion of the Transition objects consumes too much memory on an embedded
299-
microcontrollers.
300-
301-
When a request to create a `ZonedDateTime` object comes in, the
302-
`ExtendedZoneProcessor.findTransition(epochSeconds)` method is called. It scans
303-
the list of Transitions calculated above, looking for a match. The matching
304-
Transition object contains the relevant standard offset and DST offset of that
305-
Zone.
306-
307-
The calculation of the Transitions is very complex, and I find that I can no
308-
longer understand my own code after a few months away of this code base. So here
309-
are some notes to help my future-self. The code is in
310-
`Transition::initForYear(int16_t)` and is organized into 5 steps as described
311-
below.
292+
There are 2 fundamental ways that a `ZonedDateTime` can be constructed:
293+
294+
1) Using its human-readable components and its timezone through the
295+
`ZonedDateTime::forComponents()` factory method. The human-readable date can be:
296+
* An undefined time in a DST gap, or
297+
* A duplicate time during a DST overlap.
298+
2) Using the epochSeconds and its timezone through the
299+
`ZoneDateTime::forEpochSeconds()` factory method.
300+
* The epochSeconds always specifies a well-defined unique time.
301+
302+
The call stack of the first method looks like this:
303+
304+
```
305+
ZoneDateTime::forComponents()
306+
-> TimeZone::getOffsetDateTime(LocalDateTime&)
307+
-> ExtendeZoneProcessor::getOffsetDateTime(LocalDateTime&)
308+
-> TransitionStorage::findTransitionForDateTime(LocalDateTime&)
309+
```
310+
311+
The call stack of the second method looks like this:
312+
313+
```
314+
ZoneDateTime::forEpochSeconds(acetime_t)
315+
-> TimeZone::getUtcOffset(acetime_t)
316+
-> ExtendedZoneProcessor::getUtcOffset(acetime_t)
317+
-> TransitionStorage::findTransitionForSeconds(acetime_t)
318+
```
319+
320+
Both the `findTransitionForDateTime()` and `findTransitionForSeconds()` methods
321+
search the list of Transitions of the specified TimeZone for a matching
322+
Transition. Most Date-Time libraries precalculate these Transitions for all
323+
Zones, for a certain range of years. Precalculation is definitely faster, and
324+
easier because the logic for calculating the Transition objects resides in only
325+
a single place.
326+
327+
The precalculation of Transition objects for all zones and years consumes too
328+
much memory on an embedded microcontrollers. To save memory, the
329+
`ExtendedZoneProcessor` class in the AceTime library calculates the `Transition`
330+
objects lazily, for only a single zone and for a single year (technically, for a
331+
14-month interval covering the 12 months of the specified year) when the
332+
`initForEpochSeconds(acetime_t)` or `initForYear(int16_t)` method is called. The
333+
list of Transitions for a single year is cached, so that subsequent requests in
334+
the same year avoid the work of recalculating the Transitions.
335+
336+
The calculation of the Transitions for a given zone and year is very complex,
337+
and I find that I can no longer understand my own code after a few months away
338+
of this code base. So here are some notes to help my future-self. The code is in
339+
`ExtendedZoneProcessor::initForYear(int16_t)` and is organized into 5 steps as
340+
described below.
312341

313342
<a name="Step1FindMatches"></a>
314343
### Step 1: Find Matches
315344

316-
The `ExtendedZoneProcessor.findMatches()` finds all `ZoneEra` objects which
345+
The `ExtendedZoneProcessor::findMatches()` finds all `ZoneEra` objects which
317346
overlap with the 14-month interval from Dec 1 of the prior year until Feb 1 of
318347
the following year. For example, `initForYear(2010)` means that the interval is
319348
from 2009-12-01T00:00 until 2011-02-01T00:00.
@@ -574,12 +603,11 @@ available.
574603
* `$ make`
575604
* `$ ./ExtendedHinnantDateTest.out | grep failed`
576605
* There should be no failures.
577-
* Update the zoneinfo files for AceTimePython (needed by BasicAcetzTest and
606+
* Update the zonedb files for AceTimePython (needed by BasicAcetzTest and
578607
ExtendedAcetzTest):
579-
* ``zonedbpy`
580-
* `$ cd AceTimePython/src/acetime/zonedbpy`
581-
* Edit the `Makefile` and update the `TZ_VERSION`.
582-
* `$ make`
608+
* `$ cd AceTimePython/src/acetime/zonedb`
609+
* Edit the `Makefile` and update the `TZ_VERSION`.
610+
* `$ make`
583611
* Verify that the `AceTime` library and the `AceTimePython` library agree with
584612
each other using the same TZDB version. This requires going into the
585613
[AceTimeValidation](https://github.com/bxparks/AceTimeValidation) project.

0 commit comments

Comments
 (0)