Skip to content

Commit

Permalink
Merge pull request #20 from bxparks/develop
Browse files Browse the repository at this point in the history
0.8.1 - update SystemClockCoroutine for compatibility with AceRoutine v0.3
  • Loading branch information
bxparks authored Aug 27, 2019
2 parents 5f6d640 + f778ba8 commit 1f00841
Show file tree
Hide file tree
Showing 14 changed files with 101 additions and 100 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Changelog

* Unreleased
* 0.8.1
* Update `SystemClockCoroutine` to be compatible with
`COROUTINE_DELAY_SECONDS()` API changed in AceRoutine v0.3.
* Fix typos and grammar errors in `USER_GUIDE.md` and `README.md`.
* Remove `YearMonth` abstraction in `BasicZoneProcessor`, saving 12 bytes
of flash in WorldClock.
* 0.8
* Handle `Fri<=1` correctly in various python scripts. (#17)
* Improve resolution of zonedb files and ZoneProcessor classes. (#18)
Expand Down
23 changes: 12 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,21 +73,22 @@ C++ namespaces:
The "date and time" classes provide an abstraction layer to make it easier
to use and manipulate date and time fields. For example, each of the
`LocalDateTime`, `OffsetDateTime` and `ZonedDateTime` classes provide the
`toEpochSeconds()` which returns the number of seconds from a epoch date, the
`forEpochSeconds()` which constructs the date and time fields from the epoch
seconds, the `forComponents()` method which constructs the object from the
individual (year, month, day, hour, minute, second) components, and the
`toEpochSeconds()` method which returns the number of seconds from an epoch
date, the `forEpochSeconds()` method which constructs the date and time fields
from the epoch seconds, the `forComponents()` method which constructs the object
from the individual (year, month, day, hour, minute, second) components, and the
`dayOfWeek()` method which returns the day of the week of the given date.

The Epoch in AceTime is defined to be 2000-01-01T00:00:00Z, in contrast to the
Epoch in Unix which is 1970-01-01T00:00:00Z. Internally, the current time is
represented as "seconds from Epoch" stored as a 32-bit signed integer
(`acetime_t` aliased to `int32_t`). The smallest 32-bit signed
integer (`-2^31`) is used to indicate an internal Error condition, so the
range of valid `acetime_t` value is `-2^31+1` to `2^31-1`.
Therefore, the range of dates that the `acetime_t` type can handle is
1931-12-13T20:45:53Z to 2068-01-19T03:14:07Z (inclusive). (In contrast, the
32-bit Unix `time_t` range is 1901-12-13T20:45:52Z to 2038-01-19T03:14:07Z).
(`acetime_t` aliased to `int32_t`). The smallest 32-bit signed integer (`-2^31`)
is used to indicate an internal Error condition, so the range of valid
`acetime_t` value is `-2^31+1` to `2^31-1`. Therefore, the range of dates that
the `acetime_t` type can handle is 1931-12-13T20:45:53Z to 2068-01-19T03:14:07Z
(inclusive). (In contrast, the 32-bit Unix `time_t` range is
1901-12-13T20:45:52Z to 2038-01-19T03:14:07Z which is the cause of the [Year
2038 Problem](https://en.wikipedia.org/wiki/Year_2038_problem)).

The various date classes (`LocalDate`, `LocalDateTime`, `OffsetDateTime`,
`ZonedDateTime`) store the year component internally as a signed 8-bit integer
Expand Down Expand Up @@ -208,7 +209,7 @@ Conversion from an epochSeconds to date-time components including timezone
* 2.8 microseconds on an ESP32,
* 6 microseconds on a Teensy 3.2.

**Version**: 0.8 (2019-08-19, TZ DB version 2019b, beta)
**Version**: 0.8.1 (2019-08-26, TZ DB version 2019b, beta)

**Status**: Supports 1-minute resolution for all Extended TimeZones, and
validated against Hinnant date library from 1975 until 2050. I think this will
Expand Down
62 changes: 33 additions & 29 deletions USER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

See the [README.md](README.md) for introductory background.

Version: 0.8 (2019-08-19, TZ DB version 2019b, beta)
Version: 0.8.1 (2019-08-26, TZ DB version 2019b, beta)

## Installation

Expand Down Expand Up @@ -152,7 +152,7 @@ application, and it will instantly use the new transition rules, without the
developer needing to create a new POSIX string. To address the memory constraint
problem, the AceTime library is designed to load only of the smallest subset of
the TZ Database that is required to support the selected timezones (1 to 3 have
fully been tested). Dynamic lookup of the time zone is possible using the
been extensively tested). Dynamic lookup of the time zone is possible using the
`ZoneManager`, and the app develop can customize it with the list of zones that
are compiled into the app. On microcontrollers with more than about 32kB of
flash memory (e.g. ESP8266, ESP32, Teensy 3.2) and depending on the size of the
Expand Down Expand Up @@ -638,7 +638,7 @@ observing Daylight Saving Time (DST).

An `OffsetDateTime` is an object that can represent a `LocalDateTime` which is
offset from the UTC time zone by a fixed amount. Internally the `OffsetDateTime`
is a aggregation of `LocalDateTime` and `TimeOffset`. Use this class for
is an aggregation of `LocalDateTime` and `TimeOffset`. Use this class for
creating and writing timestamps for events which are destined for logging for
example. This class does not know about Daylight Saving Time transitions.

Expand Down Expand Up @@ -743,9 +743,9 @@ be encoded with (relatively) simple rules from the TZ Database
* `TimeZone::kTypeExtended`: utilizes a `ExtendedZoneProcessor` which can
handle all zones in the TZ Database
* `TimeZone::kTypeBasicManaged`: same as `kTypeBasic` but the
`BasicZoneProcessor` is managed by the `ZoneManager
`BasicZoneProcessor` is managed by the `ZoneManager`
* `TimeZone::kTypeExtendedManaged`: same as `kTypeExtended` but the
`ExtendedZoneProcessor` is managed by the `ZoneManager
`ExtendedZoneProcessor` is managed by the `ZoneManager`

The class hierarchy of `TimeZone` is shown below, where the arrow means
"is-subclass-of" and the diamond-line means "is-aggregation-of". This is an
Expand All @@ -760,8 +760,8 @@ hold a reference to:
`kTypeExtendedManaged`).

```
.------------------------------.
<>' 0..1 \ 0..1
.-------------------------------.
<> 0..1 \ 0..1
TimeZone <>-------- ZoneProcessor ------- ZoneProcessorCache
^ ^
| |
Expand Down Expand Up @@ -910,7 +910,7 @@ void someFunction() {

The zoneinfo files were generated by a script using the TZ Database. This header
file is already included in `<AceTime.h>` so you don't have to explicitly
include it. As of version 2019a of the database, it contains 270 Zone and 182
include it. As of version 2019b of the database, it contains 270 Zone and 182
Link entries and whose time change rules are simple enough to be supported by
`BasicZoneProcessor`. The bottom of the `zone_infos.h` header file lists 117
zones whose zone rules are too complicated for `BasicZoneProcessor`.
Expand Down Expand Up @@ -987,7 +987,7 @@ namespace. Although the data structures in the 2 namespaces are identical
currently (v0.8) but the *values* inside the data structure fields are not
the same, and they are interpreted differently.)

As of version 2019a of TZ Database, *all* 387 Zone and 205 Link entries from the
As of version 2019b of TZ Database, *all* 387 Zone and 205 Link entries from the
following TZ files are supported: `africa`, `antarctica`, `asia`, `australasia`,
`backward`, `etcetera`, `europe`, `northamerica`, `southamerica`. There are 3
files which are not processed (`backzone`, `systemv`, `factory`) because they
Expand Down Expand Up @@ -1465,18 +1465,19 @@ is a `BasicZoneManager` with only 4 zones from the `zonedb::` data set:
#include <AceTime.h>
using namespace ace_time;
...
static const basic::ZoneInfo* const kBasicZoneRegistry[] ACE_TIME_PROGMEM = {
static const basic::ZoneInfo* const kZoneRegistry[] ACE_TIME_PROGMEM = {
&zonedb::kZoneAmerica_Los_Angeles,
&zonedb::kZoneAmerica_Denver,
&zonedb::kZoneAmerica_Chicago,
&zonedb::kZoneAmerica_New_York,
};

static const uint16_t kZoneRegistrySize =
sizeof(Controller::kZoneRegistry) / sizeof(basic::ZoneInfo*);
sizeof(kZoneRegistry) / sizeof(basic::ZoneInfo*);

static const uint16_t NUM_ZONES = 2;
static BasicZoneManager<NUM_ZONES> zoneManager(kZoneRegistrySize, kZoneRegistry);
static const uint16_t CACHE_SIZE = 2;
static BasicZoneManager<CACHE_SIZE> zoneManager(
kZoneRegistrySize, kZoneRegistry);
```
Here is the equivalent `ExtendedZoneManager` with 4 zones from the `zonedbx::`
Expand All @@ -1494,10 +1495,11 @@ static const extended::ZoneInfo* const kZoneRegistry[] ACE_TIME_PROGMEM = {
};
static const uint16_t kZoneRegistrySize =
sizeof(Controller::kZoneRegistry) / sizeof(extended::ZoneInfo*);
sizeof(kZoneRegistry) / sizeof(extended::ZoneInfo*);
static const uint16_t NUM_ZONES = 2;
static ExtendedZoneManager<NUM_ZONES> zoneManager(kZoneRegistrySize, kZoneRegistry);
static const uint16_t CACHE_SIZE = 2;
static ExtendedZoneManager<CACHE_SIZE> zoneManager(
kZoneRegistrySize, kZoneRegistry);
```

The `ACE_TIME_PROGMEM` macro is defined in
Expand All @@ -1510,7 +1512,7 @@ according to this macro.
See [CommandLineClock](examples/CommandLineClock/) for an example of how these
custom registries can be created and used.

#### createForZoneName
#### createForZoneName()

The `ZoneManager` allows creation of a `TimeZone` using the fully qualified
zone name:
Expand Down Expand Up @@ -1539,7 +1541,7 @@ I think the only time the `createForZoneName()` might be useful is if
the user was allowed to type in the zone name, and you wanted to create a
`TimeZone` from the string typed in by the user.

#### createForZoneId
#### createForZoneId()

Each zone in the `zonedb::` and `zonedbx::` database is given a unique
and stable zoneId. This can be retrieved from the `TimeZone` object using:
Expand Down Expand Up @@ -1600,21 +1602,21 @@ check for this, and substitute a reasonable default TimeZone when this happens.
This situation is not unique to the zoneId. The same problem would occur if the
fully qualified zone name was used.

#### createForZoneIndex
#### createForZoneIndex()

The `ZoneManager::createForZoneIndex()` creates a `TimeZone` from its integer
index into the Zone registry, from 0 to `registrySize - 1`. This is useful when
you want to show the user with a menu of zones from the `ZoneManager` and allow
the user to select one of the options.

The `ZoneManager::indexForZoneNmae()` and `ZoneManager::indexForZoneId()` are
The `ZoneManager::indexForZoneName()` and `ZoneManager::indexForZoneId()` are
two useful methods to convert an arbitrary time zone reference (either
by zoneName or zoneId) into an index into the registry.

### TZ Database Version

The IANA TZ Database is updated continually. As of this writing, the latest
stable version is 2019a. When a new version of the database is released, it is
stable version is 2019b. When a new version of the database is released, it is
relatively easy to regenerate the `zonedb/` and `zonedbx/` zoneinfo files.
However, it is likely that I would delay the release of a new version until the
corresponding `pytz` package is updated to the latest TZ database version, so
Expand Down Expand Up @@ -2420,8 +2422,8 @@ library for all timezones from 2000 to 2049 (inclusive):
* [BasicValidationUsingHinnantDateTest](tests/validation/BasicValidationUsingHinnantDateTest/)
* [ExtendedValidationUsingHinnantDateTest](tests/validation/ExtendedValidationUsingHinnantDateTest/)
I have validated the AceTime library against the following versions against
the Hinnant date library:
I have validated the AceTime library with the following TZ versions against
the Hinnant date library with the same TZ version:
* TZ Database: 2019a
* TZ Database: 2019b
Expand Down Expand Up @@ -2649,19 +2651,21 @@ some time to take a closer look in the future.
* This library does not support
[leap seconds](https://en.wikipedia.org/wiki/Leap_second) and will
probably never do so.
* The library does not implement TAI (International Atomic Time).
* The library does not implement
[TAI (International Atomic Time)](https://en.wikipedia.org/wiki/International_Atomic_Time).
* The `epochSeconds` is like `unixSeconds` in that it is unaware of
leap seconds. When a leap seconds occurs the `epochSeconds` is repeated
over 2 seconds, just like `unixSeconds`.
leap seconds. When a leap seconds occurs, the `epochSeconds` is held
constant over 2 seconds, just like `unixSeconds`.
* The `SystemClock` is unaware of leap seconds so it will continue
to increment `epochSeconds` through the leap second. In other words,
the SystemClock will be 1 second ahead of UTC.
the SystemClock will be 1 second ahead of UTC after the leap second
occurs.
* If the referenceClock is the `NtpClock`, that clock happens to
be leap second aware, and the `epochSeconds` will bounce back one
second upon the next synchronization, becoming synchronized to UTC.
* If the referenceClock is the `DS3231Clock`, that clock is *not*
leap second aware, so the `epochSeconds` will continue to be ahead of
UTC by one second.
UTC by one second even after synchronization.
* `acetime_t`
* AceTime uses an epoch of 2000-01-01T00:00:00Z.
The `acetime_t` type is a 32-bit signed integer whose smallest value
Expand Down Expand Up @@ -2821,7 +2825,7 @@ some time to take a closer look in the future.
* The SAMD21 microcontroller does *not* provide any EEPROM. Therefore,
this feature is disabled in the apps under `examples` (e.g.
`CommandLineClock`, `OledClock`, and `WorldClock`) which use this feature.
* The `MKR Zero` board generates *far* faster code (30%?) than the `SparkFun
* The `MKR Zero` board generates far faster code (30%?) than the `SparkFun
SAMD21 Mini Breakout` board. The `MKR Zero` could be using a different
(more recent?) version of the GCC tool chain. I have not investigated
this.
6 changes: 3 additions & 3 deletions examples/OledClock/OledClock.ino
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ void setup() {
#endif

#if ENABLE_SERIAL == 1
SERIAL_PORT_MONITOR.begin(115200); // ESP8266 default of 74880 not supported on Linux
while (!SERIAL_PORT_MONITOR); // Wait until SERIAL_PORT_MONITOR is ready - Leonardo/Micro
SERIAL_PORT_MONITOR.begin(115200);
while (!SERIAL_PORT_MONITOR); // Leonardo/Micro
SERIAL_PORT_MONITOR.println(F("setup(): begin"));
SERIAL_PORT_MONITOR.print(F("sizeof(ClockInfo): "));
SERIAL_PORT_MONITOR.println(sizeof(ClockInfo));
Expand Down Expand Up @@ -204,7 +204,7 @@ void setup() {
controller.setup();
persistentStore.setup();

systemClock.setupCoroutine(F("systemClock"));
systemClock.setupCoroutine(F("clock"));
CoroutineScheduler::setup();

#if ENABLE_SERIAL == 1
Expand Down
17 changes: 4 additions & 13 deletions examples/OledClock/Presenter.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,7 @@ class Presenter {
mOled.setFont(fixed_bold10x15);
const ZonedDateTime& dateTime = mRenderingInfo.dateTime;
if (dateTime.isError()) {
mOled.println(F("9999-99-99"));
mOled.println(F("99:99:99 "));
mOled.println(F("Error "));
mOled.println(F("<Error>"));
return;
}

Expand Down Expand Up @@ -198,16 +196,12 @@ class Presenter {
typeString = F("manual");
break;
case TimeZone::kTypeBasic:
case TimeZone::kTypeBasicManaged:
typeString = F("basic");
break;
case TimeZone::kTypeExtended:
typeString = F("extd");
break;
case TimeZone::kTypeBasicManaged:
typeString = F("bas-man");
break;
case TimeZone::kTypeExtendedManaged:
typeString = F("extd-man");
typeString = F("extd");
break;
default:
typeString = F("unknown");
Expand Down Expand Up @@ -266,15 +260,12 @@ class Presenter {
#if ENABLE_SERIAL == 1
SERIAL_PORT_MONITOR.println(F("displayAbout()"));
#endif
mOled.setFont(SystemFont5x7);

// Use F() macros for these longer strings. Seems to save both
// flash memory and RAM.
mOled.print(F("OledClock: "));
mOled.println(CLOCK_VERSION_STRING);
mOled.print(F("TZ: "));
mOled.println(zonedb::kTzDatabaseVersion);
mOled.print(F("AceTime: "));
mOled.print(F("AT: "));
mOled.print(ACE_TIME_VERSION_STRING);
}

Expand Down
4 changes: 4 additions & 0 deletions examples/OledClock/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
#define TIME_SOURCE_TYPE TIME_SOURCE_TYPE_DS3231
#define OLED_REMAP false
#elif defined(AUNITER_MICRO) || defined(AUNITER_MICRO_MINDER)
// Pro Micro does not have enough Flash to use Basic TimeZone
// (28884 bytes) so use Manual TimeZone (23984 bytes).
#undef TIME_ZONE_TYPE
#define TIME_ZONE_TYPE TIME_ZONE_TYPE_MANUAL
#define MODE_BUTTON_PIN 8
#define CHANGE_BUTTON_PIN 9
#define TIME_SOURCE_TYPE TIME_SOURCE_TYPE_DS3231
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=AceTime
version=0.8
version=0.8.1
author=Brian T. Park <brian@xparks.net>
maintainer=Brian T. Park <brian@xparks.net>
sentence=Date, time, clock, and TZ Database timezones for Arduino.
Expand Down
4 changes: 2 additions & 2 deletions src/AceTime.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
#include "ace_time/clock/SystemClockCoroutine.h"

// Version format: xxyyzz == "xx.yy.zz"
#define ACE_TIME_VERSION 800
#define ACE_TIME_VERSION_STRING "0.8"
#define ACE_TIME_VERSION 801
#define ACE_TIME_VERSION_STRING "0.8.1"

#endif
Loading

0 comments on commit 1f00841

Please sign in to comment.