Giter Site home page Giter Site logo

bxparks / acetime Goto Github PK

View Code? Open in Web Editor NEW
74.0 6.0 15.0 60.53 MB

Date and time classes for Arduino supporting the IANA TZ Database time zones to convert epoch seconds to date and time components in different time zones.

License: MIT License

C 0.10% C++ 99.61% Makefile 0.29%

acetime's Introduction

AceTime

AUnit Tests Validation Tests

The AceTime library provides Date, Time, and TimeZone classes which can convert "epoch seconds" from the AceTime Epoch (default 2050-01-01 UTC) to human-readable local date and time fields. Those classes can also convert local date and time between different time zones defined by the IANA TZ database while accurately accounting for DST transitions.

The default AceTime epoch is 2050-01-01, but it can be adjusted by the client application at runtime. The epoch second has the type acetime_t which is a 32-bit signed integer, instead of a 64-bit signed integer. Using the smaller 32-bit integer allows the library to use less CPU and memory resources on 8-bit and 32-bit microcontrollers without native 64-bit integer instructions. The range of a 32-bit integer is about 136 years. To be safe, AceTime timezone functions should be kept well within the bounds of this interval, for example, straddling roughly +/- 60 years of the Epoch::currentEpochYear().

The library provides 3 pre-generated ZoneInfo Databases which are programmatically extracted from the IANA TZ database:

  • zonedb ("basic", not usually recommended)
    • accurate over the years [2000,10000)
    • contains a subset of zones (~450) compatible with BasicZoneProcessor and BasicZoneManager
  • zonedbx ("extended", recommended for most situations)
    • accurate over the years [2000,10000)
    • contains all zones and links (~600) in the IANA TZ database
    • compatible with ExtendedZoneProcessor and ExtendedZoneManager
  • zonedbc ("complete", mostly intended for validation testing, new in v2.3)
    • accurate over the years [0001,10000)
    • contains all zones and links (~600) the IANA TZ database
    • compatible with CompleteZoneProcessor and CompleteZoneManager

Client applications can choose to incorporate a subset of the zones provided by the above databases to save flash memory size of the application.

Support for Unix time using the Unix 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.

The companion library AceTimeClock provides Clock classes to retrieve the time from more accurate sources, such as an NTP server, or a DS3231 RTC chip. A special version of the Clock class called the SystemClock provides a fast and accurate "epoch seconds" across all Arduino compatible systems. This "epoch seconds" can be given to the classes in this library to convert it into human readable components in different timezones. On the ESP8266 and ESP32, the AceTime library can be used with the SNTP client and the C-library time() function through the 64-bit time_t value. See ESP8266 and ESP32 TimeZones below.

The primordial motivation for creating the AceTime library was to build a digital clock with an OLED or LED display, that would show the date and time of multiple timezones at the same time, while adjusting for any DST changes in the selected timezones automatically. Another major goal of the library is to keep the resource (flash and RAM) consumption as small as practical, to allow substantial portion of this library to run inside the 32kB of flash and 2kB of RAM limits of an Arduino Nano or a SparkFun Pro Micro dev board. To meet that goal, this library does not perform any dynamic allocation of memory. Everything it needs is allocated statically.

This library can be an alternative to the Arduino Time (https://github.com/PaulStoffregen/Time) and Arduino Timezone (https://github.com/JChristensen/Timezone) libraries.

Major Changes in v2.3: Add CompleteZoneProcessor, CompleteZoneManager, and the zonedbc database to support all timezones, for all transitions defined in the IANA TZ database ([1844,2087]), and extending the validity of timezone calculations from [2000,10000) to [0001,10000).

Version: 2.3.1 (2024-01-12, TZDB version 2023d)

Changelog: CHANGELOG.md

Migration: MIGRATING.md

User Guide: USER_GUIDE.md

See Also:

Table of Contents

Installation

The latest stable release is available in the Arduino Library Manager in the IDE. Search for "AceTime". Click install. The Library Manager should automatically install AceTime and its dependent libraries:

The development version can be installed by cloning the above repos manually. You can copy over the contents to the ./libraries directory used by the Arduino IDE. (The result is a set of directories named ./libraries/AceTime, ./libraries/AceCommon, ./libraries/AceSorting). Or you can create symlinks from ./libraries to these directories. Or you can git clone directly into the ./libraries directory.

The develop branch contains the latest development. The master branch contains the stable releases.

Source Code

The source files are organized as follows:

  • src/AceTime.h - main header file
  • main library code
    • src/ace_time/ - date and time classes (ace_time:: namespace)
    • src/ace_time/common/ - shared classes and utilities
    • src/ace_time/testing/ - files used in unit tests (ace_time::testing namespace)
    • src/zoneinfo - reading the zone databases, and normalizing the interface for accessing the data records
  • zone databases
    • src/zonedb/ - files generated from TZ Database for BasicZoneProcessor (ace_time::zonedb namespace)
    • src/zonedbtesting/ - limited subset of zonedb for unit tests
    • src/zonedbx/ - files generated from TZ Database for ExtendedZoneProcessor (ace_time::zonedbx namespace)
    • src/zonedbxtesting/ - limited subset of zonedbx for unit tests
    • src/zonedbc/ - files generated from TZ Database for CompleteZoneProcessor (ace_time::zonedbc namespace)
    • src/zonedbctesting/ - limited subset of zonedbc for unit tests
  • `tests/
  • examples/ - example programs and benchmarks
    • Simple
    • Intermediate
      • CustomZoneRegistry
        • Same as HelloZoneManager, but using a custom zone registry with only 7-8 timezones instead of the ~600 timezones in the full zonedbx registry.
    • Advanced
      • EspTime
        • Use AceTime with the built-in SNTP client of ESP8266 and ESP32.
    • Benchmarks
      • These are internal applications to benchmark various parts of this library. They are not meant to be examples for how to use the library.
      • MemoryBenchmark
        • determine flash and static memory consumption of various classes
      • AutoBenchmark
        • determine CPU usage of various features
      • ComparisonBenchmark
      • CompareAceTimeToHinnantDate
        • compare the performance of AceTime to Hinnant date library
        • AceTime seems to be about 90X faster
    • Debugging
      • DebugZoneProcessor
        • Command-line debugging tool for ExtenedZoneProcessor using the EpoxyDuino environment
      • ListZones
        • List the zones managed by the ExtendedZoneManager, sorted by name, or by UTC offset and name.
        • Used to debug the ZoneSorter classes.

Dependencies

The AceTime library depends on the following libraries:

Various programs in the examples/ directory have one or more of the following external dependencies. The comment section near the top of the *.ino file will usually have more precise dependency information:

If you want to run the unit tests or validation tests using a Linux or MacOS machine, you need:

Documentation

HelloDateTime

Here is a simple program (see examples/HelloDateTime) which demonstrates how to create and manipulate date and times in different time zones:

#include <Arduino.h>
#include <AceTime.h>

using namespace ace_time;

// ZoneProcessor instances should be created statically at initialization time.
static ExtendedZoneProcessor losAngelesProcessor;
static ExtendedZoneProcessor londonProcessor;

void setup() {
  delay(1000);
  Serial.begin(115200);
  while (!Serial); // Wait until Serial is ready - Leonardo/Micro

  // TimeZone objects are light-weight and can be created on the fly.
  TimeZone losAngelesTz = TimeZone::forZoneInfo(
      &zonedbx::kZoneAmerica_Los_Angeles,
      &losAngelesProcessor);
  TimeZone londonTz = TimeZone::forZoneInfo(
      &zonedbx::kZoneEurope_London,
      &londonProcessor);

  // Create from components. 2019-03-10T03:00:00 is just after DST change in
  // Los Angeles (2am goes to 3am).
  ZonedDateTime startTime = ZonedDateTime::forComponents(
      2019, 3, 10, 3, 0, 0, losAngelesTz);

  Serial.print(F("Epoch Seconds: "));
  acetime_t epochSeconds = startTime.toEpochSeconds();
  Serial.println(epochSeconds);

  Serial.print(F("Unix Seconds: "));
  int64_t unixSeconds = startTime.toUnixSeconds64();
  Serial.println((int32_t) unixSeconds);

  Serial.println(F("=== Los_Angeles"));
  ZonedDateTime losAngelesTime = ZonedDateTime::forEpochSeconds(
      epochSeconds, losAngelesTz);
  Serial.print(F("Time: "));
  losAngelesTime.printTo(Serial);
  Serial.println();

  Serial.print(F("Day of Week: "));
  Serial.println(
      DateStrings().dayOfWeekLongString(losAngelesTime.dayOfWeek()));

  // Print info about UTC offset
  TimeOffset offset = losAngelesTime.timeOffset();
  Serial.print(F("Total UTC Offset: "));
  offset.printTo(Serial);
  Serial.println();

  // Print info about the current time zone
  Serial.print(F("Zone: "));
  losAngelesTz.printTo(Serial);
  Serial.println();

  // Print the current time zone abbreviation, e.g. "PST" or "PDT"
  ZonedExtra ze = losAngelesTz.getZonedExtra(epochSeconds);
  Serial.print(F("Abbreviation: "));
  SERIAL_PORT_MONITOR.print(ze.abbrev());
  Serial.println();

  // Create from epoch seconds. London is still on standard time.
  ZonedDateTime londonTime = ZonedDateTime::forEpochSeconds(
      epochSeconds, londonTz);

  Serial.println(F("=== London"));
  Serial.print(F("Time: "));
  londonTime.printTo(Serial);
  Serial.println();

  // Print info about the current time zone
  Serial.print(F("Zone: "));
  londonTz.printTo(Serial);
  Serial.println();

  // Print the current time zone abbreviation, e.g. "GMT" or "BST"
  ze = londonTz.getZonedExtra(epochSeconds);
  Serial.print(F("Abbreviation: "));
  SERIAL_PORT_MONITOR.print(ze.abbrev());
  Serial.println();

  Serial.println(F("=== Compare ZonedDateTime"));
  Serial.print(F("losAngelesTime.compareTo(londonTime): "));
  Serial.println(losAngelesTime.compareTo(londonTime));
  Serial.print(F("losAngelesTime == londonTime: "));
  Serial.println((losAngelesTime == londonTime) ? "true" : "false");
}

void loop() {
}

Running this should produce the following on the Serial port:

Epoch Seconds: -972396000
Unix Seconds: 1552212000
=== Los Angeles
Time: 2019-03-10T03:00:00-07:00[America/Los_Angeles]
Day of Week: Sunday
Total UTC Offset: -07:00
Zone: America/Los_Angeles
Abbreviation: PDT
=== London
Time: 2019-03-10T10:00:00+00:00[Europe/London]
Zone: Europe/London
Abbreviation: GMT
=== Compare ZonedDateTime
losAngelesTime.compareTo(londonTime): 0
losAngelesTime == londonTime: false

(The default epoch for AceTime is 2050-01-01, so a date in 2019 will return a negative epoch seconds.)

HelloZoneManager

The examples/HelloZoneManager example shows how to load the entire zonedbx ZoneInfo Database into an ExtendedZoneManager, then create 3 time zones using 3 different ways: createForZoneInfo(), createForZoneName(), and createForZoneId(). This program requires a 32-bit microcontroller environment because the ExtendedZoneManager with the zonedbx::kZoneAndLinkRegistry consumes ~44 kB of flash which does not fit in the 32 kB flash memory capacity of an Arduino Nano. If the ExtendedZoneManager is replaced with the BasicZoneManager and the smaller kZoneRegistry is used instead, the flash size goes down to about ~24 kB. Depending on the code size of the rest of the application, this may fit inside an Arduino Nano.

#include <Arduino.h>
#include <AceTime.h>

using namespace ace_time;

// Create an ExtendedZoneManager with the entire TZ Database of Zone and Link
// entries. Cache size of 3 means that it can support 3 concurrent timezones
// without performance penalties.
static const int CACHE_SIZE = 3;
static ExtendedZoneProcessorCache<CACHE_SIZE> zoneProcessorCache;
static ExtendedZoneManager manager(
    zonedbx::kZoneAndLinkRegistrySize,
    zonedbx::kZoneAndLinkRegistry,
    zoneProcessorCache);

void setup() {
  Serial.begin(115200);
  while (!Serial); // Wait until ready - Leonardo/Micro

  // Create America/Los_Angeles timezone by ZoneInfo.
  TimeZone losAngelesTz = manager.createForZoneInfo(
        &zonedbx::kZoneAmerica_Los_Angeles);
  ZonedDateTime losAngelesTime = ZonedDateTime::forComponents(
      2019, 3, 10, 3, 0, 0, losAngelesTz);
  losAngelesTime.printTo(Serial);
  Serial.println();

  // Create Europe/London timezone by ZoneName.
  TimeZone londonTz = manager.createForZoneName("Europe/London");
  ZonedDateTime londonTime = losAngelesTime.convertToTimeZone(londonTz);
  londonTime.printTo(Serial);
  Serial.println();

  // Create Australia/Sydney timezone by ZoneId.
  TimeZone sydneyTz = manager.createForZoneId(zonedbx::kZoneIdAustralia_Sydney);
  ZonedDateTime sydneyTime = losAngelesTime.convertToTimeZone(sydneyTz);
  sydneyTime.printTo(Serial);
  Serial.println();
}

void loop() {
}

It produces the following output:

2019-03-10T03:00:00-07:00[America/Los_Angeles]
2019-03-10T10:00:00+00:00[Europe/London]
2019-03-10T21:00:00+11:00[Australia/Sydney]

WorldClock

Here is a photo of the WorldClock (https://github.com/bxparks/clocks/tree/master/WorldClock) that supports 3 OLED displays with 3 timezones, and automatically adjusts the DST transitions for all 3 zones:

WorldClock

User Guide

The full documentation of the following classes are given in the USER_GUIDE.md:

  • date and time classes and types
    • ace_time::acetime_t
    • ace_time::DateStrings
    • ace_time::LocalTime
    • ace_time::LocalDate
    • ace_time::LocalDateTime
    • ace_time::TimeOffset
    • ace_time::OffsetDateTime
    • ace_time::TimePeriod
    • mutation helpers
      • ace_time::local_date_mutation::
      • ace_time::time_offset_mutation::
      • ace_time::time_period_mutation::
      • ace_time::offset_date_time_mutation::
      • ace_time::zoned_date_time_mutation::
  • timezone classes
    • ace_time::ZoneProcessor
      • ace_time::BasicZoneProcessor
      • ace_time::ExtendedZoneProcessor
      • ace_time::CompleteZoneProcessor
    • ace_time::TimeZone
    • ace_time::ZonedDateTime
    • ace_time::ZoneManager
      • ace_time::BasicZoneManager
      • ace_time::ExtendedZoneManager
      • ace_time::CompleteZoneManager
      • ace_time::ManualZoneManager
  • ZoneInfo Database
    • 3 sets of timezone data are provided (Basic, Extended, Complete) which support slightly different sets of zones and years
    • programmatically generated from the IANA TZ Database files
    • each timezone is identified in multiple ways
      • ZoneInfo: (opaque) pointer to a ZoneInfo data structure
      • ZoneId: unique and stable uint32_t identifier (e.g. 0xb7f7e8f2)
      • ZoneName: unique human-readable string (e.g. "America/Los_Angeles")
    • Basic (not usually recommended)
      • 448 zones and links as of 2023c
      • ZoneInfo (const ace_time::basic::ZoneInfo*)
        • ace_time::zonedb::kZoneAfrica_Abidjan
        • ...
        • ace_time::zonedb::kZonePacific_Wallis
      • ZoneId (uint32_t)
        • ace_time::zonedb::kZoneIdAfrica_Abidjan
        • ...
        • ace_time::zonedb::kZoneIdPacific_Wallis
      • ZoneName (const char*)
        • "Africa/Abidjan"
        • ...
        • "Pacific/Wallis"
    • Extended (recommended for most cases)
      • 596 zones and links as of 2023c
      • ZoneInfo (const ace_time::extended::ZoneInfo*)
        • ace_time::zonedbx::kZoneAfrica_Abidjan
        • ...
        • ace_time::zonedbx::kZonePacific_Wallis
      • ZoneIds (uint32_t)
        • ace_time::zonedbx::kZoneIdAfrica_Abidjan
        • ...
        • ace_time::zonedbx::kZoneIdPacific_Wallis
      • ZoneName (const char*)
        • "Africa/Abidjan"
        • ...
        • "Pacific/Wallis"
    • Complete (useful when full range of years is necessary)
      • 596 zones and links as of 2023c
      • ZoneInfo (const ace_time::complete::ZoneInfo*)
        • ace_time::zonedbc::kZoneAfrica_Abidjan
        • ...
        • ace_time::zonedbc::kZonePacific_Wallis
      • ZoneId (uint32_t)
        • ace_time::zonedbc::kZoneIdAfrica_Abidjan
        • ...
        • ace_time::zonedbc::kZoneIdPacific_Wallis
      • ZoneName (const char*)
        • "Africa/Abidjan"
        • ...
        • "Pacific/Wallis"

Validation

The details of how the Date, Time and TimeZone classes are validated are given in AceTimeValidation.

The ZoneInfo Database and the algorithms in this library were tested against other date/time libraries written in different programming languages. The CompleteZoneProcessor configured with the zonedbc database was used for most of the validation testing, because this combination covers all zones and links valid over a 400-year interval [1800,2200). Some of these third party libraries match AceTime exactly over the 400 year interval. Other libraries contained bugs which prevented exact conformance with AceTime.

Conformant

These libraries match the AceTime library (using the CompleteZoneProcessor/CompleteZoneManager with the zonedbc database) exactly: every DST transition, DST offset, STD offset, the epochsecond of the transition, the converted data-time components, and the abbreviation. The match was verified for all time zones and links, from 1800 until 2200.

Non Conformant

These third party libraries match AceTime for the most part, but seem to contain bugs in some parts of their code. I have not had the time to look into the cause of these bugs in these third party libraries.

  • Python pytz library from the year 2000 until 2038
    • pytz cannot handle years after 2038
  • Python dateutil library from the year 2000 until 2037
    • dateutil cannot handle years after 2038
  • Python 3.9 zoneinfo library from the year 1800 until 2200
    • 31 zones produce incorrect DST offsets
  • Java JDK 11 java.time library from year 1800 until 2200
    • 3 IANA timezones are missing from java.time
    • ~100 zones seem to produce incorrect DST offsets
    • ~7 zones seem to produce incorrect epochSeconds
  • Go lang time package from 1800 to 2200
    • 23 zones produce incorrect results

Resource Consumption

SizeOf Classes

8-bit processors

Sizes of Objects:
sizeof(LocalDate): 4
sizeof(LocalTime): 4
sizeof(LocalDateTime): 8
sizeof(TimeOffset): 4
sizeof(OffsetDateTime): 12
sizeof(TimeZone): 5
sizeof(TimeZoneData): 5
sizeof(ZonedDateTime): 17
sizeof(ZonedExtra): 24
sizeof(TimePeriod): 4
Basic:
  sizeof(basic::ZoneContext): 20
  sizeof(basic::ZoneEra): 11
  sizeof(basic::ZoneInfo): 13
  sizeof(basic::ZoneRule): 9
  sizeof(basic::ZonePolicy): 3
  sizeof(basic::ZoneRegistrar): 5
  sizeof(BasicZoneProcessor): 143
  sizeof(BasicZoneProcessorCache<1>): 147
  sizeof(BasicZoneManager): 7
  sizeof(BasicZoneProcessor::Transition): 26
Extended:
  sizeof(extended::ZoneContext): 20
  sizeof(extended::ZoneEra): 11
  sizeof(extended::ZoneInfo): 13
  sizeof(extended::ZoneRule): 9
  sizeof(extended::ZonePolicy): 3
  sizeof(extended::ZoneRegistrar): 5
  sizeof(ExtendedZoneProcessor): 553
  sizeof(ExtendedZoneProcessorCache<1>): 557
  sizeof(ExtendedZoneManager): 7
  sizeof(ExtendedZoneProcessor::Transition): 49
  sizeof(ExtendedZoneProcessor::TransitionStorage): 412
  sizeof(ExtendedZoneProcessor::MatchingEra): 32
Complete:
  sizeof(complete::ZoneContext): 20
  sizeof(complete::ZoneEra): 15
  sizeof(complete::ZoneInfo): 13
  sizeof(complete::ZoneRule): 12
  sizeof(complete::ZonePolicy): 3
  sizeof(complete::ZoneRegistrar): 5
  sizeof(CompleteZoneProcessor): 553
  sizeof(CompleteZoneProcessorCache<1>): 557
  sizeof(CompleteZoneManager): 7
  sizeof(CompleteZoneProcessor::Transition): 49
  sizeof(CompleteZoneProcessor::TransitionStorage): 412
  sizeof(CompleteZoneProcessor::MatchingEra): 32

32-bit processors

Sizes of Objects:
sizeof(LocalDate): 4
sizeof(LocalTime): 4
sizeof(LocalDateTime): 8
sizeof(TimeOffset): 4
sizeof(OffsetDateTime): 12
sizeof(TimeZone): 12
sizeof(TimeZoneData): 8
sizeof(ZonedDateTime): 24
sizeof(ZonedExtra): 24
sizeof(TimePeriod): 4
Basic:
  sizeof(basic::ZoneContext): 28
  sizeof(basic::ZoneEra): 16
  sizeof(basic::ZoneInfo): 24
  sizeof(basic::ZoneRule): 9
  sizeof(basic::ZonePolicy): 8
  sizeof(basic::ZoneRegistrar): 8
  sizeof(BasicZoneProcessor): 208
  sizeof(BasicZoneProcessorCache<1>): 216
  sizeof(BasicZoneManager): 12
  sizeof(BasicZoneProcessor::Transition): 36
Extended:
  sizeof(extended::ZoneContext): 28
  sizeof(extended::ZoneEra): 16
  sizeof(extended::ZoneInfo): 24
  sizeof(extended::ZoneRule): 9
  sizeof(extended::ZonePolicy): 8
  sizeof(extended::ZoneRegistrar): 8
  sizeof(ExtendedZoneProcessor): 720
  sizeof(ExtendedZoneProcessorCache<1>): 728
  sizeof(ExtendedZoneManager): 12
  sizeof(ExtendedZoneProcessor::Transition): 60
  sizeof(ExtendedZoneProcessor::TransitionStorage): 516
  sizeof(ExtendedZoneProcessor::MatchingEra): 44
Complete:
  sizeof(complete::ZoneContext): 28
  sizeof(complete::ZoneEra): 20
  sizeof(complete::ZoneInfo): 24
  sizeof(complete::ZoneRule): 12
  sizeof(complete::ZonePolicy): 8
  sizeof(complete::ZoneRegistrar): 8
  sizeof(CompleteZoneProcessor): 720
  sizeof(CompleteZoneProcessorCache<1>): 728
  sizeof(CompleteZoneManager): 12
  sizeof(CompleteZoneProcessor::Transition): 60
  sizeof(CompleteZoneProcessor::TransitionStorage): 516
  sizeof(CompleteZoneProcessor::MatchingEra): 44

Zone DB Size

The ZoneInfo Database entries are stored in flash memory (using the PROGMEM compiler directive) if the microcontroller allows it (e.g. AVR, ESP8266) so that they do not consume static RAM. The examples/MemoryBenchmark program shows the flash memory consumption for the ZoneInfo data files are:

  • BasicZoneProcessor (all zones and links)
    • 25 kB (8-bit processor)
    • 32 kB (32-bit processor)
  • ExtendedZoneProcessor (all zones and links)
    • 40 kB (8-bit processor)
    • 51 kB (32-bit processor)
  • CompleteZoneProcessor (all zones and links)
    • too large (8-bit processor)
    • 100 kB (32-bit processor)

An example of more complex application is the WorldClock (https://github.com/bxparks/clocks/tree/master/WorldClock) which has 3 OLED displays over SPI, 3 timezones using BasicZoneProcessor, a SystemClock synchronized to a DS3231 chip on I2C, and 2 buttons with debouncing and event dispatching provided by the AceButton (https://github.com/bxparks/AceButton) library. This application consumes about 24 kB, well inside the 28 kB flash limit of a SparkFun Pro Micro controller.

This library does not perform dynamic allocation of memory so that it can be used in small microcontroller environments. In other words, it does not call the new operator nor the malloc() function, and it does not use the Arduino String class. Everything it needs is allocated statically at initialization time.

Flash And Static Memory

MemoryBenchmark was used to determine the size of the library for various microcontrollers (Arduino Nano to ESP32). Here are 2 samples:

Arduino Nano:

+----------------------------------------------------------------------+
| Functionality                          |  flash/  ram |        delta |
|----------------------------------------+--------------+--------------|
| baseline                               |    474/   11 |      0/    0 |
|----------------------------------------+--------------+--------------|
| LocalDateTime                          |   1108/   21 |    634/   10 |
| ZonedDateTime                          |   1444/   30 |    970/   19 |
| Manual ZoneManager                     |   1406/   13 |    932/    2 |
|----------------------------------------+--------------+--------------|
| Basic TimeZone (1 zone)                |   7624/  208 |   7150/  197 |
| Basic TimeZone (2 zones)               |   8170/  357 |   7696/  346 |
| BasicZoneManager (1 zone)              |   7834/  219 |   7360/  208 |
| BasicZoneManager (all zones)           |  19686/  599 |  19212/  588 |
| BasicZoneManager (all zones+links)     |  25066/  599 |  24592/  588 |
|----------------------------------------+--------------+--------------|
| Basic ZoneSorterByName [1]             |   8608/  221 |    774/    2 |
| Basic ZoneSorterByOffsetAndName [1]    |   8740/  221 |    906/    2 |
|----------------------------------------+--------------+--------------|
| Extended TimeZone (1 zone)             |  11326/  623 |  10852/  612 |
| Extended TimeZone (2 zones)            |  11924/ 1187 |  11450/ 1176 |
| ExtendedZoneManager (1 zone)           |  11506/  629 |  11032/  618 |
| ExtendedZoneManager (all zones)        |  34508/ 1111 |  34034/ 1100 |
| ExtendedZoneManager (all zones+links)  |  40540/ 1111 |  40066/ 1100 |
|----------------------------------------+--------------+--------------|
| Extended ZoneSorterByName [2]          |  12276/  631 |    770/    2 |
| Extended ZoneSorterByOffsetAndName [2] |  12360/  631 |    854/    2 |
|----------------------------------------+--------------+--------------|
| Complete TimeZone (1 zone)             |     -1/   -1 |     -1/   -1 |
| Complete TimeZone (2 zones)            |     -1/   -1 |     -1/   -1 |
| CompleteZoneManager (1 zone)           |     -1/   -1 |     -1/   -1 |
| CompleteZoneManager (all zones)        |     -1/   -1 |     -1/   -1 |
| CompleteZoneManager (all zones+links)  |     -1/   -1 |     -1/   -1 |
|----------------------------------------+--------------+--------------|
| Complete ZoneSorterByName [3]          |     -1/   -1 |      0/    0 |
| Complete ZoneSorterByOffsetAndName [3] |     -1/   -1 |      0/    0 |
+---------------------------------------------------------------------+

ESP8266:

+----------------------------------------------------------------------+
| Functionality                          |  flash/  ram |        delta |
|----------------------------------------+--------------+--------------|
| baseline                               | 260089/27892 |      0/    0 |
|----------------------------------------+--------------+--------------|
| LocalDateTime                          | 260613/27912 |    524/   20 |
| ZonedDateTime                          | 261573/27928 |   1484/   36 |
| Manual ZoneManager                     | 261553/27900 |   1464/    8 |
|----------------------------------------+--------------+--------------|
| Basic TimeZone (1 zone)                | 267117/28528 |   7028/  636 |
| Basic TimeZone (2 zones)               | 267533/28736 |   7444/  844 |
| BasicZoneManager (1 zone)              | 267277/28552 |   7188/  660 |
| BasicZoneManager (all zones)           | 283613/28552 |  23524/  660 |
| BasicZoneManager (all zones+links)     | 292141/28552 |  32052/  660 |
|----------------------------------------+--------------+--------------|
| Basic ZoneSorterByName [1]             | 268029/28552 |    752/    0 |
| Basic ZoneSorterByOffsetAndName [1]    | 268157/28552 |    880/    0 |
|----------------------------------------+--------------+--------------|
| Extended TimeZone (1 zone)             | 269653/29152 |   9564/ 1260 |
| Extended TimeZone (2 zones)            | 270069/29880 |   9980/ 1988 |
| ExtendedZoneManager (1 zone)           | 269813/29160 |   9724/ 1268 |
| ExtendedZoneManager (all zones)        | 301077/29160 |  40988/ 1268 |
| ExtendedZoneManager (all zones+links)  | 310645/29160 |  50556/ 1268 |
|----------------------------------------+--------------+--------------|
| Extended ZoneSorterByName [2]          | 270549/29160 |    736/    0 |
| Extended ZoneSorterByOffsetAndName [2] | 270613/29160 |    800/    0 |
|----------------------------------------+--------------+--------------|
| Complete TimeZone (1 zone)             | 270145/29508 |  10056/ 1616 |
| Complete TimeZone (2 zones)            | 271425/30236 |  11336/ 2344 |
| CompleteZoneManager (1 zone)           | 270289/29516 |  10200/ 1624 |
| CompleteZoneManager (all zones)        | 350449/29516 |  90360/ 1624 |
| CompleteZoneManager (all zones+links)  | 360017/29516 |  99928/ 1624 |
|----------------------------------------+--------------+--------------|
| Complete ZoneSorterByName [3]          | 271041/29516 |    752/    0 |
| Complete ZoneSorterByOffsetAndName [3] | 271089/29516 |    800/    0 |
+---------------------------------------------------------------------+

CPU Usage

AutoBenchmark was used to determine the CPU time consume by various features of the classes in this library. Two samples are shown below:

Arduino Nano:

+--------------------------------------------------+----------+
| Method                                           |   micros |
|--------------------------------------------------+----------|
| EmptyLoop                                        |    5.000 |
|--------------------------------------------------+----------|
| LocalDate::forEpochDays()                        |  241.000 |
| LocalDate::toEpochDays()                         |   52.000 |
| LocalDate::dayOfWeek()                           |   49.000 |
|--------------------------------------------------+----------|
| OffsetDateTime::forEpochSeconds()                |  361.000 |
| OffsetDateTime::toEpochSeconds()                 |   78.000 |
|--------------------------------------------------+----------|
| ZonedDateTime::toEpochSeconds()                  |   75.000 |
| ZonedDateTime::toEpochDays()                     |   63.000 |
| ZonedDateTime::forEpochSeconds(UTC)              |  391.000 |
|--------------------------------------------------+----------|
| ZonedDateTime::forEpochSeconds(Basic_nocache)    | 1710.000 |
| ZonedDateTime::forEpochSeconds(Basic_cached)     |  707.000 |
| ZonedDateTime::forEpochSeconds(Extended_nocache) |   -1.000 |
| ZonedDateTime::forEpochSeconds(Extended_cached)  |   -1.000 |
| ZonedDateTime::forEpochSeconds(Complete_nocache) |   -1.000 |
| ZonedDateTime::forEpochSeconds(Complete_cached)  |   -1.000 |
|--------------------------------------------------+----------|
| ZonedDateTime::forComponents(Basic_nocache)      | 2252.000 |
| ZonedDateTime::forComponents(Basic_cached)       | 1254.000 |
| ZonedDateTime::forComponents(Extended_nocache)   |   -1.000 |
| ZonedDateTime::forComponents(Extended_cached)    |   -1.000 |
| ZonedDateTime::forComponents(Complete_nocache)   |   -1.000 |
| ZonedDateTime::forComponents(Complete_cached)    |   -1.000 |
|--------------------------------------------------+----------|
| ZonedExtra::forEpochSeconds(Basic_nocache)       | 1386.000 |
| ZonedExtra::forEpochSeconds(Basic_cached)        |  378.000 |
| ZonedExtra::forEpochSeconds(Extended_nocache)    |   -1.000 |
| ZonedExtra::forEpochSeconds(Extended_cached)     |   -1.000 |
| ZonedExtra::forEpochSeconds(Complete_nocache)    |   -1.000 |
| ZonedExtra::forEpochSeconds(Complete_cached)     |   -1.000 |
|--------------------------------------------------+----------|
| ZonedExtra::forComponents(Basic_nocache)         | 2276.000 |
| ZonedExtra::forComponents(Basic_cached)          | 1277.000 |
| ZonedExtra::forComponents(Extended_nocache)      |   -1.000 |
| ZonedExtra::forComponents(Extended_cached)       |   -1.000 |
| ZonedExtra::forComponents(Complete_nocache)      |   -1.000 |
| ZonedExtra::forComponents(Complete_cached)       |   -1.000 |
|--------------------------------------------------+----------|
| BasicZoneRegistrar::findIndexForName(binary)     |  118.000 |
| BasicZoneRegistrar::findIndexForIdBinary()       |   47.000 |
| BasicZoneRegistrar::findIndexForIdLinear()       |  299.000 |
|--------------------------------------------------+----------|
| ExtendedZoneRegistrar::findIndexForName(binary)  |   -1.000 |
| ExtendedZoneRegistrar::findIndexForIdBinary()    |   -1.000 |
| ExtendedZoneRegistrar::findIndexForIdLinear()    |   -1.000 |
|--------------------------------------------------+----------|
| CompleteZoneRegistrar::findIndexForName(binary)  |   -1.000 |
| CompleteZoneRegistrar::findIndexForIdBinary()    |   -1.000 |
| CompleteZoneRegistrar::findIndexForIdLinear()    |   -1.000 |
+--------------------------------------------------+----------+
Iterations_per_run: 1000

ESP8266:

+--------------------------------------------------+----------+
| Method                                           |   micros |
|--------------------------------------------------+----------|
| EmptyLoop                                        |    4.500 |
|--------------------------------------------------+----------|
| LocalDate::forEpochDays()                        |    7.500 |
| LocalDate::toEpochDays()                         |    4.000 |
| LocalDate::dayOfWeek()                           |    3.500 |
|--------------------------------------------------+----------|
| OffsetDateTime::forEpochSeconds()                |   12.000 |
| OffsetDateTime::toEpochSeconds()                 |    7.000 |
|--------------------------------------------------+----------|
| ZonedDateTime::toEpochSeconds()                  |    6.500 |
| ZonedDateTime::toEpochDays()                     |    5.500 |
| ZonedDateTime::forEpochSeconds(UTC)              |   13.500 |
|--------------------------------------------------+----------|
| ZonedDateTime::forEpochSeconds(Basic_nocache)    |  141.500 |
| ZonedDateTime::forEpochSeconds(Basic_cached)     |   21.500 |
| ZonedDateTime::forEpochSeconds(Extended_nocache) |  354.500 |
| ZonedDateTime::forEpochSeconds(Extended_cached)  |   28.000 |
| ZonedDateTime::forEpochSeconds(Complete_nocache) |  407.000 |
| ZonedDateTime::forEpochSeconds(Complete_cached)  |   28.000 |
|--------------------------------------------------+----------|
| ZonedDateTime::forComponents(Basic_nocache)      |  159.000 |
| ZonedDateTime::forComponents(Basic_cached)       |   46.000 |
| ZonedDateTime::forComponents(Extended_nocache)   |  241.500 |
| ZonedDateTime::forComponents(Extended_cached)    |    2.500 |
| ZonedDateTime::forComponents(Complete_nocache)   |  354.000 |
| ZonedDateTime::forComponents(Complete_cached)    |    2.500 |
|--------------------------------------------------+----------|
| ZonedExtra::forEpochSeconds(Basic_nocache)       |  134.500 |
| ZonedExtra::forEpochSeconds(Basic_cached)        |   11.000 |
| ZonedExtra::forEpochSeconds(Extended_nocache)    |  308.000 |
| ZonedExtra::forEpochSeconds(Extended_cached)     |   18.000 |
| ZonedExtra::forEpochSeconds(Complete_nocache)    |  396.000 |
| ZonedExtra::forEpochSeconds(Complete_cached)     |   17.500 |
|--------------------------------------------------+----------|
| ZonedExtra::forComponents(Basic_nocache)         |  184.500 |
| ZonedExtra::forComponents(Basic_cached)          |   48.500 |
| ZonedExtra::forComponents(Extended_nocache)      |  268.000 |
| ZonedExtra::forComponents(Extended_cached)       |   29.000 |
| ZonedExtra::forComponents(Complete_nocache)      |  332.500 |
| ZonedExtra::forComponents(Complete_cached)       |    5.000 |
|--------------------------------------------------+----------|
| BasicZoneRegistrar::findIndexForName(binary)     |   18.000 |
| BasicZoneRegistrar::findIndexForIdBinary()       |    6.500 |
| BasicZoneRegistrar::findIndexForIdLinear()       |   43.000 |
|--------------------------------------------------+----------|
| ExtendedZoneRegistrar::findIndexForName(binary)  |   24.500 |
| ExtendedZoneRegistrar::findIndexForIdBinary()    |    6.000 |
| ExtendedZoneRegistrar::findIndexForIdLinear()    |   50.500 |
|--------------------------------------------------+----------|
| CompleteZoneRegistrar::findIndexForName(binary)  |   18.500 |
| CompleteZoneRegistrar::findIndexForIdBinary()    |    6.500 |
| CompleteZoneRegistrar::findIndexForIdLinear()    |   43.000 |
+--------------------------------------------------+----------+
Iterations_per_run: 2000

System Requirements

Hardware

Tier 1: Fully supported

These boards are tested on each release:

  • Arduino Nano (16 MHz ATmega328P)
  • SparkFun Pro Micro (16 MHz ATmega32U4)
  • Seeed Studio XIAO M0 (SAMD21, 48 MHz ARM Cortex-M0+)
  • STM32 Blue Pill (STM32F103C8, 72 MHz ARM Cortex-M3)
  • Adafruit ItsyBitsy M4 (SAMD51, 120 MHz ARM Cortex-M4)
  • NodeMCU 1.0 (ESP-12E module, 80 MHz ESP8266)
  • WeMos D1 Mini (ESP-12E module, 80 MHz ESP8266)
  • ESP32 dev board (ESP-WROOM-32 module, 240 MHz dual core Tensilica LX6)

Tier 2: Should work

These boards should work but I don't test them as often:

  • ATtiny85 (8 MHz ATtiny85)
  • Arduino Pro Mini (16 MHz ATmega328P)
  • Mini Mega 2560 (Arduino Mega 2560 compatible, 16 MHz ATmega2560)
  • Teensy LC (48 MHz ARM Cortex-M0+)
  • Teensy 3.2 (96 MHz ARM Cortex-M4)

Tier 3: May work, but not supported

  • Other SAMD21 based boards, e.g Arduino Zero
    • SAMD21 based boards are now split into 2 groups:
      • Those using the new ArduinoCore-API, usually Arduino-branded boards. These are explicitly blacklisted. See below.
      • Other 3rd party SAMD21 boards using the previous Arduino API.
    • The ones using the previous Arduino API may work but I have not explicitly tested any of them except for the Seeed Studio XIAO M0 and Adafruit ItsyBitsy M4.

Tier Blacklisted

The following boards are not supported and are explicitly blacklisted to allow the compiler to print useful error messages instead of hundreds of lines of compiler errors:

  • Any platform using the ArduinoCore-API. For example:
    • Arduino Nano Every
    • Arduino Nano 33 IoT
    • Arduino MKRZero
    • Arduino UNO R4
    • Raspberry Pi Pico RP2040

Tool Chain

This library was developed and tested using:

This library is not compatible with:

It should work with PlatformIO but I have not tested it.

The library works on Linux or MacOS (using both g++ and clang++ compilers) using the EpoxyDuino (https://github.com/bxparks/EpoxyDuino) emulation layer.

Operating System

I use Ubuntu 22.04 for the vast majority of my development. I expect that the library will work fine under MacOS and Windows, but I have not tested them.

Motivation and Design Considerations

In the beginning, I created a digital clock using an Arduino Nano board, a small OLED display, and a DS3231 RTC chip. Everything worked, it was great. Then I wanted the clock to figure out the Daylight Saving Time (DST) automatically. And I wanted to create a clock that could display multiple timezones. Thus began my journey down the rabbit hole of timezones.

In full-featured operating systems (e.g. Linux, MacOS, Windows) and languages with timezone library support (e.g. Java, Python, JavaScript, C#, Go), the user has the ability to specify the Daylight Saving time (DST) transitions using 2 ways:

  • POSIX format which encodes the DST transitions into a string (e.g. EST+5EDT,M3.2.0/2,M11.1.0/2) that can be parsed programmatically, or
  • a reference to a TZ Database entry (e.g. America/Los_Angeles or Europe/London) which identifies a set of time transition rules for the given timezone.

The problem with the POSIX format is that it is somewhat difficult for a human to understand, and the programmer must manually update this string when a timezone changes its DST transition rules. Also, there is no historical information in the POSIX string, so date and time written in the past cannot be accurately expressed. As far as I know, POSIX timezone strings can support only 2 DST transitions per year. However, there are a handful of timezones which have (or used to have) 4 timezone transitions in a single year, which cannot be represented by a POSIX string. Most Arduino timezone libraries use the POSIX format (e.g. ropg/ezTime or JChristensen/Timezone) for simplicity and smaller memory footprint.

The libraries that incorporate the full IANA TZ Database are often far too large to fit inside the resource constrained Arduino environments. The AceTime library has been optimized to reduce the flash memory size of the library as much as possible. The application can choose to load only of the smallest subset of the TZ Database that is required to support the selected timezones (1 to 4 have 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 rest of the application, it may be possible to load the entire IANA TZ database. This will allow the end-user to select the timezone dynamically, just like desktop-class machines.

When new versions of the database are released (several times a year), I can regenerate the zone files, recompile the application, and it will instantly use the new transition rules, without the developer needing to create a new POSIX string.

The AceTime library is inspired by and borrows from:

The names and API of AceTime classes are heavily borrowed from the Java JDK 11 java.time package. Some important differences come from the fact that in Java, most objects are reference objects and created on the heap. To allow AceTime to work on an Arduino chip with only 2kB of RAM and 32kB of flash, the AceTime C++ classes perform no heap allocations (i.e. no calls to operator new() or malloc()). Many of the smaller classes in the library are expected to be used as "value objects", in other words, created on the stack and copied by value. Fortunately, the C++ compilers are extremely good at optimizing away unnecessary copies of these small objects. It is not possible to remove all complex memory allocations when dealing with the TZ Database. In the AceTime library, I managed to move most of the complex memory handling logic into the ZoneProcessor class hierarchy. These are relatively large objects which are meant to be opaque to the application developer, created statically at start-up time of the application, and never deleted during the lifetime of the application.

The Arduino Time Library uses a set of C functions similar to the traditional C/Unix library methods (e.g makeTime() and breaktime()). It also uses the Unix epoch of 1970-01-01T00:00:00Z and a int32_t type as its time_t to track the number of seconds since the epoch. That means that the largest date it can handle is 2038-01-19T03:14:07Z. AceTime uses an epoch that starts on 2000-01-01T00:00:00Z using the same int32_t as its ace_time::acetime_t, which means that maximum date increases to 2068-01-19T03:14:07Z. AceTime is also quite a bit faster than the Arduino Time Library (although in most cases, performance of the Time Library is not an issue): AceTime is 2-5X faster on an ATmega328P, 3-5X faster on the ESP8266, 7-8X faster on the ESP32, and 7-8X faster on the Teensy ARM processor.

AceTime aims to be the smallest library that can run on the basic Arduino platform (e.g. Nano with 32kB flash and 2kB of RAM) that fully supports all timezones in the TZ Database at compile-time. Memory constraints of the smallest Arduino boards may limit the number of timezones supported by a single program at runtime to 1-3 timezones. The library also aims to be as portable as possible, and supports AVR microcontrollers, as well as ESP8266, ESP32 and Teensy microcontrollers.

Comparisons to Other Time Libraries

Arduino Time Library

The AceTime library can be substantially faster than the equivalent methods in the Arduino Time Library. The ComparisonBenchmark.ino program compares the CPU run time of LocalDateTime::forEpochSeconds() and LocalDateTime::toEpochSeconds() with the equivalent breakTime() and makeTime() functions of the Arduino Time Library. Details are given in the ComparisonBenchmark/README.md file. Two examples for the Arduino Nano and ESP8266 are shown below:

Nano

+----------------------------------------+----------+
| Method                                 |   micros |
|----------------------------------------+----------|
| EmptyLoop                              |    5.000 |
|----------------------------------------+----------|
| LocalDateTime::forEpochSeconds()       |  270.000 |
| breakTime()                            |  594.500 |
|----------------------------------------+----------|
| LocalDateTime::toEpochSeconds()        |   66.500 |
| makeTime()                             |  344.500 |
+----------------------------------------+----------+

ESP8266

+----------------------------------------+----------+
| Method                                 |   micros |
|----------------------------------------+----------|
| EmptyLoop                              |    0.800 |
|----------------------------------------+----------|
| LocalDateTime::forEpochSeconds()       |   13.100 |
| breakTime()                            |   42.600 |
|----------------------------------------+----------|
| LocalDateTime::toEpochSeconds()        |    4.500 |
| makeTime()                             |   24.800 |
+----------------------------------------+----------+

C Time Library (time.h)

Some version of the standard Unix/C library <time.h> is available in some Arduino platforms, but not others:

  • The AVR libc time library
    • contains methods such as gmtime() to convert time_t integer into date time components struct tm,
    • and a non-standard mk_gmtime() to convert components into a time_t integer
    • the time_t integer is unsigned, and starts at 2000-01-01T00:00:00 UTC
    • no support for timezones
    • the time() value does not auto-increment. The system_tick() function must be manually called, probably in an ISR (interrupt service routine).
  • The SAMD21 and Teensy platforms do not seem to have a <time.h> library.
  • The ESP8266 and ESP32 have a <time.h> library.
    • The time() function automatically increments through the system_get_time() system call.
    • Provides an SNTP client that can synchronize with an NTP service and resynchronize the time() function.
    • Adds configTime() functions to configure the behavior of the SNTP service, including POSIX timezones.
    • ESP8266 TZ.h containing pre-calculated POSIX timezone strings.

These libraries are all based upon the traditional C/Unix library methods which can be difficult to understand.

ESP8266 and ESP32 TimeZones

The ESP8266 platform provides a cores/esp8266/TZ.h file which contains a list of pre-generated POSIX timezone strings. These can be passed into the configTime() function that initializes the SNTP service.

The ESP32 platform does not provide a TZ.h file as far as I can tell. I believe the same POSIX strings can be passed into its configTime() function. But POSIX timezone strings have limitations that I described in Motivation, and the C-style library functions are often confusing and hard to use.

Application developers can choose to use the built-in SNTP service and the time() function on the ESP8266 and ESP32 as the source of accurate clock, but take advantage of the versatility and power of the AceTime library for timezone conversions. AceTime v1.10 adds the forUnixSeconds64() and toUnixSeconds64() methods in various classes to make it far easier to interact with the 64-bit time_t integers returned by the time() function on these platforms.

See EspTime for an example of how to integrate AceTime with the built-in SNTP service and time() function on the ESP8266 and ESP32. See also the EspSntpClock class in the AceTimeClock project which provides a thin-wrapper around this service on the ESP platforms.

ezTime

The ezTime is a library that seems to be composed of 2 parts: A client library that runs on the microcontroller and a server part that provides a translation from the timezone name to the POSIX DST transition string. Unfortunately, this means that the controller must have network access for this library to work. I wanted to create a library that was self-contained and could run on an Arduino Nano with just an RTC chip without a network shield.

Micro Time Zone

The Micro Time Zone is a pure-C library that can compile on the Arduino platform. It contains a limited subset of the TZ Database encoded as C structs and determines the DST transitions using the encoded structs. It supports roughly of 45 zones with just a 3kB tzinfo database. The initial versions of AceTime, particularly the BasicZoneProcessor class was directly inspired by this library. It would be interesting to run this library to the same set of "validation" unit tests that checks the AceTime logic and see how accurate this library is. One problem with Micro Time Zone library is that it loads the entire tzinfo database for all 45 time zones, even if only one zone is used. Therefore, the AceTime library will consume less flash memory for the database part if only a handful of zones are used. But the AceTime library contains more algorithmic code so will consume more flash memory. It is not entirely clear which library is smaller for 1-3 time zones. (This may be an interesting investigation the future.)

Java Time, Joda-Time, Noda Time

The names and functionality of most the date and time classes (LocalTime, LocalDate, LocalDateTime, OffsetDateTime, and ZonedDateTime) were inspired by the architecture of the Java 11 java.time package. However, there were many parts of the java.time package that were not appropriate for a microcontroller environment with small memory. Those were implemented in other ways. There were other parts that seemed better implemented by Joda-Time or Noda Time). I picked the ones that I liked.

Those other libraries (java.time, Joda-Time, and Noda Time) all provide substantially more fine-grained class hierarchies to provider better type-safety. For example, those libraries just mentioned provided an Instant class, a Duration class, an Interval class. The java.time package also provides other fine-grained classes such as OffsetTime, OffsetDate, Year, Month, MonthDay classes. For the AceTime library, I decided to avoid providing too many classes. The API of the library is already too large, I did not want to make them larger than necessary.

Howard Hinnant Date Library

The date package by Howard Hinnant is based upon the <chrono> standard library and consists of several libraries of which date.h and tz.h are comparable to AceTime. Modified versions of these libraries were voted into the C++20 standard.

Unfortunately these libraries are not suitable for an Arduino microcontroller environment because:

  • The libraries depend extensively on 64-bit integers which are impractical on 8-bit microcontrollers with only 32kB of flash memory.
  • The tz.h library has the option of downloading the TZ Database files over the network using libcurl to the OS filesystem then parsing the files, or using the native Zoneinfo entries on the host OS. Neither options are practical on small microcontrollers. The raw TZ Database files consume about 1MB in gzip'ed format, which are not suitable for a 32kB Arduino microcontroller.
  • The libraries has dependencies on other libraries such as <iostream> and <chrono> which don't exist on most Arduino platforms.
  • The libraries are heavily templatized to provide maximum flexibility and type-safety. But this makes the libraries incredibly hard to understand and cumbersome to use for the simple use cases targeted by the AceTime library.

The Hinnant date libraries were invaluable for writing the HinnantBasicTest and HinnantExtendedTest validation tests which compare the AceTime algorithms to the Hinnant Date algorithms. For all times zones between the years 2000 until 2100, the AceTime date-time components (ZonedDateTime) and abbreviations (ZonedExtra) calculated from the given epochSeconds match the results from the Hinnant Date libraries.

Google cctz

The cctz library from Google is also based on the <chrono> library. I have not looked at this library closely because I assumed that it would not fit inside an Arduino controller. Hopefully I will get some time to take a closer look in the future.

License

MIT License

Feedback and Support

If you have any questions, comments, or feature requests for this library, please use the GitHub Discussions for this project. If you have bug reports, please file a ticket in GitHub Issues. Feature requests should go into Discussions first because they often have alternative solutions which are useful to remain visible, instead of disappearing from the default view of the Issue tracker after the ticket is closed.

Please refrain from emailing me directly unless the content is sensitive. The problem with email is that I cannot reference the email conversation when other people ask similar questions later.

Authors

acetime's People

Contributors

arkhipenko avatar bxparks avatar denis-stepanov avatar naguissa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

acetime's Issues

Constructor for NtpClock::setup() missing

In v. 0.8.1 there is no constructor for ace_time::clock::NtpClock::setup(void). As mentioned in the documentation, this should be the constructor to use when there is already an existing WLAN connection.
There is only a constructor for NtpClock::setup(const char* ssid, const char* password).
Otherwise, this library is a wonderful thing! Thanks!

The code to add to NtpClock.h would be:

   void setup(void) {
      mUdp.begin(mLocalPort);

    #if ACE_TIME_NTP_CLOCK_DEBUG == 1
      #if defined(ESP8266)
        SERIAL_PORT_MONITOR.print(F("Local port: "));
        SERIAL_PORT_MONITOR.println(mUdp.localPort());
      #endif
    #endif

      mIsSetUp = true;
    }

Is AceTime working with ESP32

Hi,

i used your great library with an ESP8266 which works perfect.
But when compiling for ESP32 i get a lot of error messages ;-(
Is there a way to get AceTime running with an ESP32?

This is the error code pasted from Arduino IDE (sorry for that much text ;-(
There are also some other error messages in between but the most are related to acetime.
Would be great if you could help me running that library again

Arduino: 1.8.16 (Linux), Board: "ESP32 Dev Module, Disabled, Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS), 240MHz (WiFi/BT), QIO, 80MHz, 4MB (32Mb), 921600, None"

Arduino: 1.8.16 (Linux), Board: "ESP32 Dev Module, Disabled, Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS), 240MHz (WiFi/BT), QIO, 80MHz, 4MB (32Mb), 921600, None"



In file included from /home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/WString.h:29:0,
                 from /home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/Arduino.h:146,
                 from /media/daten/Arduino/mytestsketch/Code/mytestsketch/mytestsketch.ino:7:
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/common/DateStrings.h: In static member function 'static const char* ace_time::DateStrings::getStringAt(const char* const*, uint8_t)':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/common/DateStrings.h:73:28: note: in expansion of macro 'pgm_read_ptr'
       return (const char*) pgm_read_ptr(&strings[i]);
                            ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/common/DateStrings.h:73:28: note: in expansion of macro 'pgm_read_ptr'
       return (const char*) pgm_read_ptr(&strings[i]);
                            ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/common/DateStrings.h:73:28: note: in expansion of macro 'pgm_read_ptr'
       return (const char*) pgm_read_ptr(&strings[i]);
                            ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h: In member function 'const ace_time::basic::ZoneRuleBroker ace_time::basic::ZonePolicyBroker::rule(uint8_t) const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:157:29: note: in expansion of macro 'pgm_read_ptr'
           (const ZoneRule*) pgm_read_ptr(&mZonePolicy->rules);
                             ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:157:29: note: in expansion of macro 'pgm_read_ptr'
           (const ZoneRule*) pgm_read_ptr(&mZonePolicy->rules);
                             ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:157:29: note: in expansion of macro 'pgm_read_ptr'
           (const ZoneRule*) pgm_read_ptr(&mZonePolicy->rules);
                             ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h: In member function 'const char* ace_time::basic::ZonePolicyBroker::letter(uint8_t) const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:167:11: note: in expansion of macro 'pgm_read_ptr'
           pgm_read_ptr(&mZonePolicy->letters);
           ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:167:11: note: in expansion of macro 'pgm_read_ptr'
           pgm_read_ptr(&mZonePolicy->letters);
           ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:167:11: note: in expansion of macro 'pgm_read_ptr'
           pgm_read_ptr(&mZonePolicy->letters);
           ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:168:28: note: in expansion of macro 'pgm_read_ptr'
       return (const char*) pgm_read_ptr(&letters[i]);
                            ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:168:28: note: in expansion of macro 'pgm_read_ptr'
       return (const char*) pgm_read_ptr(&letters[i]);
                            ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:168:28: note: in expansion of macro 'pgm_read_ptr'
       return (const char*) pgm_read_ptr(&letters[i]);
                            ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h: In member function 'const ace_time::basic::ZonePolicyBroker ace_time::basic::ZoneEraBroker::zonePolicy() const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:215:31: note: in expansion of macro 'pgm_read_ptr'
           (const ZonePolicy*) pgm_read_ptr(&mZoneEra->zonePolicy));
                               ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:215:31: note: in expansion of macro 'pgm_read_ptr'
           (const ZonePolicy*) pgm_read_ptr(&mZoneEra->zonePolicy));
                               ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:215:31: note: in expansion of macro 'pgm_read_ptr'
           (const ZonePolicy*) pgm_read_ptr(&mZoneEra->zonePolicy));
                               ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h: In member function 'const char* ace_time::basic::ZoneEraBroker::format() const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:227:28: note: in expansion of macro 'pgm_read_ptr'
       return (const char*) pgm_read_ptr(&mZoneEra->format);
                            ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:227:28: note: in expansion of macro 'pgm_read_ptr'
       return (const char*) pgm_read_ptr(&mZoneEra->format);
                            ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:227:28: note: in expansion of macro 'pgm_read_ptr'
       return (const char*) pgm_read_ptr(&mZoneEra->format);
                            ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h: In member function 'const ace_time::internal::ZoneContext* ace_time::basic::ZoneInfoBroker::zoneContext() const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:309:11: note: in expansion of macro 'pgm_read_ptr'
           pgm_read_ptr(&mZoneInfo->zoneContext);
           ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:309:11: note: in expansion of macro 'pgm_read_ptr'
           pgm_read_ptr(&mZoneInfo->zoneContext);
           ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:309:11: note: in expansion of macro 'pgm_read_ptr'
           pgm_read_ptr(&mZoneInfo->zoneContext);
           ^
In file included from /home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/Arduino.h:146:0,
                 from /media/daten/Arduino/mytestsketch/Code/mytestsketch/mytestsketch.ino:7:
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h: In member function 'const __FlashStringHelper* ace_time::basic::ZoneInfoBroker::name() const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/WString.h:39:76: note: in definition of macro 'FPSTR'
 #define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer))
                                                                            ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:313:20: note: in expansion of macro 'pgm_read_ptr'
       return FPSTR(pgm_read_ptr(&mZoneInfo->name));
                    ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/WString.h:39:76: note: in definition of macro 'FPSTR'
 #define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer))
                                                                            ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:313:20: note: in expansion of macro 'pgm_read_ptr'
       return FPSTR(pgm_read_ptr(&mZoneInfo->name));
                    ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/WString.h:39:76: note: in definition of macro 'FPSTR'
 #define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer))
                                                                            ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:313:20: note: in expansion of macro 'pgm_read_ptr'
       return FPSTR(pgm_read_ptr(&mZoneInfo->name));
                    ^
In file included from /home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/WString.h:29:0,
                 from /home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/Arduino.h:146,
                 from /media/daten/Arduino/mytestsketch/Code/mytestsketch/mytestsketch.ino:7:
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h: In member function 'uint32_t ace_time::basic::ZoneInfoBroker::zoneId() const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:44:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:317:14: note: in expansion of macro 'pgm_read_dword'
       return pgm_read_dword(&mZoneInfo->zoneId);
              ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:45:28: error: '_addr' was not declared in this scope
   *(const unsigned long *)(_addr); \
                            ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:317:14: note: in expansion of macro 'pgm_read_dword'
       return pgm_read_dword(&mZoneInfo->zoneId);
              ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:46:2: error: void value not ignored as it ought to be
 })
  ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:317:14: note: in expansion of macro 'pgm_read_dword'
       return pgm_read_dword(&mZoneInfo->zoneId);
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h: In member function 'const ace_time::basic::ZoneEraBroker ace_time::basic::ZoneInfoBroker::era(uint8_t) const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:325:46: note: in expansion of macro 'pgm_read_ptr'
       const ZoneEra* eras = (const ZoneEra*) pgm_read_ptr(&mZoneInfo->eras);
                                              ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:325:46: note: in expansion of macro 'pgm_read_ptr'
       const ZoneEra* eras = (const ZoneEra*) pgm_read_ptr(&mZoneInfo->eras);
                                              ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:325:46: note: in expansion of macro 'pgm_read_ptr'
       const ZoneEra* eras = (const ZoneEra*) pgm_read_ptr(&mZoneInfo->eras);
                                              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h: In member function 'const ace_time::basic::ZoneInfo* ace_time::basic::ZoneRegistryBroker::zoneInfo(uint16_t) const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:375:32: note: in expansion of macro 'pgm_read_ptr'
       return (const ZoneInfo*) pgm_read_ptr(&mZoneRegistry[i]);
                                ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:375:32: note: in expansion of macro 'pgm_read_ptr'
       return (const ZoneInfo*) pgm_read_ptr(&mZoneRegistry[i]);
                                ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:375:32: note: in expansion of macro 'pgm_read_ptr'
       return (const ZoneInfo*) pgm_read_ptr(&mZoneRegistry[i]);
                                ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h: In member function 'uint32_t ace_time::basic::LinkEntryBroker::zoneId() const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:44:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:405:38: note: in expansion of macro 'pgm_read_dword'
     uint32_t zoneId() const { return pgm_read_dword(&mLinkEntry->zoneId); }
                                      ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:45:28: error: '_addr' was not declared in this scope
   *(const unsigned long *)(_addr); \
                            ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:405:38: note: in expansion of macro 'pgm_read_dword'
     uint32_t zoneId() const { return pgm_read_dword(&mLinkEntry->zoneId); }
                                      ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:46:2: error: void value not ignored as it ought to be
 })
  ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:405:38: note: in expansion of macro 'pgm_read_dword'
     uint32_t zoneId() const { return pgm_read_dword(&mLinkEntry->zoneId); }
                                      ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h: In member function 'uint32_t ace_time::basic::LinkEntryBroker::linkId() const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:44:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:406:38: note: in expansion of macro 'pgm_read_dword'
     uint32_t linkId() const { return pgm_read_dword(&mLinkEntry->linkId); }
                                      ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:45:28: error: '_addr' was not declared in this scope
   *(const unsigned long *)(_addr); \
                            ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:406:38: note: in expansion of macro 'pgm_read_dword'
     uint32_t linkId() const { return pgm_read_dword(&mLinkEntry->linkId); }
                                      ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:46:2: error: void value not ignored as it ought to be
 })
  ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/BasicBrokers.h:406:38: note: in expansion of macro 'pgm_read_dword'
     uint32_t linkId() const { return pgm_read_dword(&mLinkEntry->linkId); }
                                      ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h: In member function 'const ace_time::extended::ZoneRuleBroker ace_time::extended::ZonePolicyBroker::rule(uint8_t) const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:181:29: note: in expansion of macro 'pgm_read_ptr'
           (const ZoneRule*) pgm_read_ptr(&mZonePolicy->rules);
                             ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:181:29: note: in expansion of macro 'pgm_read_ptr'
           (const ZoneRule*) pgm_read_ptr(&mZonePolicy->rules);
                             ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:181:29: note: in expansion of macro 'pgm_read_ptr'
           (const ZoneRule*) pgm_read_ptr(&mZonePolicy->rules);
                             ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h: In member function 'const char* ace_time::extended::ZonePolicyBroker::letter(uint8_t) const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:191:11: note: in expansion of macro 'pgm_read_ptr'
           pgm_read_ptr(&mZonePolicy->letters);
           ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:191:11: note: in expansion of macro 'pgm_read_ptr'
           pgm_read_ptr(&mZonePolicy->letters);
           ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:191:11: note: in expansion of macro 'pgm_read_ptr'
           pgm_read_ptr(&mZonePolicy->letters);
           ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:192:28: note: in expansion of macro 'pgm_read_ptr'
       return (const char*) pgm_read_ptr(&letters[i]);
                            ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:192:28: note: in expansion of macro 'pgm_read_ptr'
       return (const char*) pgm_read_ptr(&letters[i]);
                            ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:192:28: note: in expansion of macro 'pgm_read_ptr'
       return (const char*) pgm_read_ptr(&letters[i]);
                            ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h: In member function 'const ace_time::extended::ZonePolicyBroker ace_time::extended::ZoneEraBroker::zonePolicy() const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:241:31: note: in expansion of macro 'pgm_read_ptr'
           (const ZonePolicy*) pgm_read_ptr(&mZoneEra->zonePolicy));
                               ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:241:31: note: in expansion of macro 'pgm_read_ptr'
           (const ZonePolicy*) pgm_read_ptr(&mZoneEra->zonePolicy));
                               ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:241:31: note: in expansion of macro 'pgm_read_ptr'
           (const ZonePolicy*) pgm_read_ptr(&mZoneEra->zonePolicy));
                               ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h: In member function 'const char* ace_time::extended::ZoneEraBroker::format() const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:255:28: note: in expansion of macro 'pgm_read_ptr'
       return (const char*) pgm_read_ptr(&mZoneEra->format);
                            ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:255:28: note: in expansion of macro 'pgm_read_ptr'
       return (const char*) pgm_read_ptr(&mZoneEra->format);
                            ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:255:28: note: in expansion of macro 'pgm_read_ptr'
       return (const char*) pgm_read_ptr(&mZoneEra->format);
                            ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h: In member function 'const ace_time::internal::ZoneContext* ace_time::extended::ZoneInfoBroker::zoneContext() const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:341:11: note: in expansion of macro 'pgm_read_ptr'
           pgm_read_ptr(&mZoneInfo->zoneContext);
           ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:341:11: note: in expansion of macro 'pgm_read_ptr'
           pgm_read_ptr(&mZoneInfo->zoneContext);
           ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:341:11: note: in expansion of macro 'pgm_read_ptr'
           pgm_read_ptr(&mZoneInfo->zoneContext);
           ^
In file included from /home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/Arduino.h:146:0,
                 from /media/daten/Arduino/mytestsketch/Code/mytestsketch/mytestsketch.ino:7:
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h: In member function 'const __FlashStringHelper* ace_time::extended::ZoneInfoBroker::name() const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/WString.h:39:76: note: in definition of macro 'FPSTR'
 #define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer))
                                                                            ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:345:20: note: in expansion of macro 'pgm_read_ptr'
       return FPSTR(pgm_read_ptr(&mZoneInfo->name));
                    ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/WString.h:39:76: note: in definition of macro 'FPSTR'
 #define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer))
                                                                            ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:345:20: note: in expansion of macro 'pgm_read_ptr'
       return FPSTR(pgm_read_ptr(&mZoneInfo->name));
                    ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/WString.h:39:76: note: in definition of macro 'FPSTR'
 #define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer))
                                                                            ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:345:20: note: in expansion of macro 'pgm_read_ptr'
       return FPSTR(pgm_read_ptr(&mZoneInfo->name));
                    ^
In file included from /home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/WString.h:29:0,
                 from /home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/Arduino.h:146,
                 from /media/daten/Arduino/mytestsketch/Code/mytestsketch/mytestsketch.ino:7:
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h: In member function 'uint32_t ace_time::extended::ZoneInfoBroker::zoneId() const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:44:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:349:14: note: in expansion of macro 'pgm_read_dword'
       return pgm_read_dword(&mZoneInfo->zoneId);
              ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:45:28: error: '_addr' was not declared in this scope
   *(const unsigned long *)(_addr); \
                            ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:349:14: note: in expansion of macro 'pgm_read_dword'
       return pgm_read_dword(&mZoneInfo->zoneId);
              ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:46:2: error: void value not ignored as it ought to be
 })
  ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:349:14: note: in expansion of macro 'pgm_read_dword'
       return pgm_read_dword(&mZoneInfo->zoneId);
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h: In member function 'const ace_time::extended::ZoneEraBroker ace_time::extended::ZoneInfoBroker::era(uint8_t) const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:357:46: note: in expansion of macro 'pgm_read_ptr'
       const ZoneEra* eras = (const ZoneEra*) pgm_read_ptr(&mZoneInfo->eras);
                                              ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:357:46: note: in expansion of macro 'pgm_read_ptr'
       const ZoneEra* eras = (const ZoneEra*) pgm_read_ptr(&mZoneInfo->eras);
                                              ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:357:46: note: in expansion of macro 'pgm_read_ptr'
       const ZoneEra* eras = (const ZoneEra*) pgm_read_ptr(&mZoneInfo->eras);
                                              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h: In member function 'const ace_time::extended::ZoneInfo* ace_time::extended::ZoneRegistryBroker::zoneInfo(uint16_t) const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:407:32: note: in expansion of macro 'pgm_read_ptr'
       return (const ZoneInfo*) pgm_read_ptr(&mZoneRegistry[i]);
                                ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:407:32: note: in expansion of macro 'pgm_read_ptr'
       return (const ZoneInfo*) pgm_read_ptr(&mZoneRegistry[i]);
                                ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:407:32: note: in expansion of macro 'pgm_read_ptr'
       return (const ZoneInfo*) pgm_read_ptr(&mZoneRegistry[i]);
                                ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h: In member function 'uint32_t ace_time::extended::LinkEntryBroker::zoneId() const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:44:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:437:38: note: in expansion of macro 'pgm_read_dword'
     uint32_t zoneId() const { return pgm_read_dword(&mLinkEntry->zoneId); }
                                      ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:45:28: error: '_addr' was not declared in this scope
   *(const unsigned long *)(_addr); \
                            ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:437:38: note: in expansion of macro 'pgm_read_dword'
     uint32_t zoneId() const { return pgm_read_dword(&mLinkEntry->zoneId); }
                                      ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:46:2: error: void value not ignored as it ought to be
 })
  ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:437:38: note: in expansion of macro 'pgm_read_dword'
     uint32_t zoneId() const { return pgm_read_dword(&mLinkEntry->zoneId); }
                                      ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h: In member function 'uint32_t ace_time::extended::LinkEntryBroker::linkId() const':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:44:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:438:38: note: in expansion of macro 'pgm_read_dword'
     uint32_t linkId() const { return pgm_read_dword(&mLinkEntry->linkId); }
                                      ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:45:28: error: '_addr' was not declared in this scope
   *(const unsigned long *)(_addr); \
                            ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:438:38: note: in expansion of macro 'pgm_read_dword'
     uint32_t linkId() const { return pgm_read_dword(&mLinkEntry->linkId); }
                                      ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:46:2: error: void value not ignored as it ought to be
 })
  ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/internal/ExtendedBrokers.h:438:38: note: in expansion of macro 'pgm_read_dword'
     uint32_t linkId() const { return pgm_read_dword(&mLinkEntry->linkId); }
                                      ^
/media/daten/Arduino/mytestsketch/Code/mytestsketch/mytestsketch.ino: In function 'void setup()':
mytestsketch:372:34: error: invalid conversion from 'const char*' to 'long int' [-fpermissive]
   configTime(MY_TZ, MY_NTP_SERVER); // Wird für die Abfrage der Uhrzeit online benötigt (nur falls eine WLAN-Verbindung besteht und nur für das erste Mal einschalten...
                                  ^
mytestsketch:372:34: error: invalid conversion from 'const char*' to 'int' [-fpermissive]
mytestsketch:372:34: error: too few arguments to function 'void configTime(long int, int, const char*, const char*, const char*)'
In file included from /media/daten/Arduino/mytestsketch/Code/mytestsketch/mytestsketch.ino:7:0:
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/Arduino.h:173:17: note: declared here
 extern "C" void configTime(long gmtOffset_sec, int daylightOffset_sec,
                 ^
/media/daten/Arduino/mytestsketch/Code/mytestsketch/mytestsketch.ino: In lambda function:
mytestsketch:605:37: error: 'firmwareUpdate' was not declared in this scope
       server.send(200, "text/html", firmwareUpdate);
                                     ^
/media/daten/Arduino/mytestsketch/Code/mytestsketch/mytestsketch.ino: In function 'void setup()':
mytestsketch:645:61: error: no matching function for call to 'WiFiUDP::beginMulticast(IPAddress, IPAddress&, const uint16_t&)'
   if (!Udp.beginMulticast(WiFi.softAPIP(), multicastIP, PORT)) {
                                                             ^
In file included from /home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/libraries/WiFi/src/WiFi.h:39:0,
                 from /home/basementmedia/Arduino/libraries/AceTime/src/ace_time/clock/NtpClock.h:15,
                 from /home/basementmedia/Arduino/libraries/AceTime/src/AceTime.h:68,
                 from /media/daten/Arduino/mytestsketch/Code/mytestsketch/mytestsketch.ino:69:
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/libraries/WiFi/src/WiFiUdp.h:57:11: note: candidate: virtual uint8_t WiFiUDP::beginMulticast(IPAddress, uint16_t)
   uint8_t beginMulticast(IPAddress a, uint16_t p);
           ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/libraries/WiFi/src/WiFiUdp.h:57:11: note:   candidate expects 2 arguments, 3 provided
/media/daten/Arduino/mytestsketch/Code/mytestsketch/mytestsketch.ino: In function 'void AP_conn()':
mytestsketch:656:25: error: 'class EspClass' has no member named 'getChipId'
   uint32_t chipid = ESP.getChipId();
                         ^

       ^
exit status 1
invalid conversion from 'const char*' to 'long int' [-fpermissive]

Looking up by shortname? or TZ name? or CountryCode?

In my situation, I want to give a flexible way to just enter common TZ references as a text field.

So instead of looking up just by the long name: Europe/Amsterdam
Would it also be possible to lookup by, just the short name: Amsterdam
Or the common TZ name: CET / CEDT
Or the country code: NL

A user can be pointed to the long name, but in most cases, the short name, Country Code or short name is enough too.

How to handle error in lookup

So I want to use your library to lookup Timezone by name.

auto myTz =  manager.createForZoneName(CSTR(settingNTPtimezone));
auto myTime = ZonedDateTime::forUnixSeconds(NtpLastSync, myTz);

It works great, but when you give a random string, you want to catch the error in lookup and have a default replace that TZname. For example: "Amsterdam" --> Error
But it works for "Europe/Amsterdam".

This way I can have a string field, but when it fails to set it correctly, it falls back to the default.

Now I have looked at the documentation, but it's not clear how to catch an error in lookup.

Your help is greatly appreciated.

support arduino:samd Core >= 1.8.10

The arduino::samd core converted to using a new Arduino API for versions >= 1.8.10. (The SparkFun::samd core is fine). I don't have time to work on this right now, so I will explicitly blacklist these boards in AceTime.h so that the user gets a useful error message, instead of pages of compiler errors.

(This issue is identical to bxparks/AUnit#66).

support '/' in FORMAT where RULES is a fixed offset

Asia/Dushanbe in 1991 has an entry where the FORMAT column contains a '/' but the RULES column contains a 1:00.

# Zone  NAME            STDOFF  RULES   FORMAT  [UNTIL]                         
Zone    Asia/Dushanbe   4:35:12 -       LMT     1924 May  2                     
                        5:00    -       +05     1930 Jun 21                     
                        6:00 RussiaAsia +06/+07 1991 Mar 31  2:00s              
                        5:00    1:00    +05/+06 1991 Sep  9  2:00s              
                        5:00    -       +05  

This probably indicates that the abbreviation should be "+06". Currently, BasicZoneProcessor does not handle this case, and will be excluded by transformer.py, and the entry is moot because the zonedb files are generated only for year 2000 and later. It should be relatively easy to fix BasicZoneProcessor to handle this.

Prevent incorrect initialization

Hello,

I found that if I create ZoneManager like this:

ace_time::CompleteZoneManager zoneManager(
  ace_time::zonedbc::kZoneRegistrySize, // note incorrect size passed, should be kZoneAndLinkRegistrySize
  ace_time::zonedbc::kZoneAndLinkRegistry,
  zoneProcessorCache);

the code hangs up while trying to enumerate them later:

  // here we pass the correct size
  zoneSorter.fillIndexes(indexes, ace_time::zonedbc::kZoneAndLinkRegistrySize);
  zoneSorter.sortIndexes(indexes, ace_time::zonedbc::kZoneAndLinkRegistrySize);

  // later...
  auto zone = zoneManager.getZoneForIndex(indexes[0]); // hangs up here

I understand it's technically not a bug within the library, but maybe there's a way to prevent incorrect size passing? The size of array ace_time::zonedbc::kZoneAndLinkRegistry is known at compile-time, so maybe it's possible to avoid passing its size directly?

Need to support other WiFi platforms like the Nano 33 IOT, Maker Wifi ,etc

I am trying to use this library on a Nano 33 IOT device which has built-in Wifi support and I have successfully run the example programs. It would be cleanest to use your NtpClock but it appears I have to develop my own because the current implementation requires an ESP8266, and I don't want to mess with the standard libraries to fix it. In general I am building a sophisticated system that has many users of the wifi, and it's best to just make yours assume that wifi is somehow provided and not only by an 8266.

ESP32 support

Hi Brian,

just wanted to use your great library with an ESP32 Board and got a bunch of error messages after sketch upload.

If i just include the library by

#include <AceTime.h>

i get a huge fault message starting like this (just a few lines, complete message is very long):

In file included from /home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/WString.h:29:0,
                 from /home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/Arduino.h:146,
                 from sketch/waterbot_v44_esp32_v2.ino.cpp:1:
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/common/DateStrings.h: In static member function 'static const char* ace_time::DateStrings::getStringAt(const char* const*, uint8_t)':
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:52:14: error: 'typeof_' was not declared in this scope
   typeof(addr) _addr = (addr); \
              ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/common/DateStrings.h:73:28: note: in expansion of macro 'pgm_read_ptr'
       return (const char*) pgm_read_ptr(&strings[i]);
                            ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:21: error: '_addr' was not declared in this scope
   *(void * const *)(_addr); \
                     ^
/home/basementmedia/Arduino/libraries/AceTime/src/ace_time/common/DateStrings.h:73:28: note: in expansion of macro 'pgm_read_ptr'
       return (const char*) pgm_read_ptr(&strings[i]);
                            ^
/home/basementmedia/.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/pgmspace.h:53:27: error: void value not ignored as it ought to be
   *(void * const *)(_addr); \
                           ^

Is this library not compatible to the ESP32?

Best wishes

Daniel

support megaAVR boards (e.g. Nano Every)

AceTime does not work on megaAVR boards because:

  1. It uses the new Arduino API,
  2. Its F() macro returns the wrong type.

I don't have the time to work on this, and I don't have any megaAVR boards that I can test on. I am explicitly blacklisting the megaAVR in AceTime.h for now, so that the user gets a useful error message, instead of pages of compiler errors.

(This issue is identical to bxparks/AUnit#56).

Construct NtpClock assuming network is available

I have difficulty understanding the choice to constuct NtpClock with Wi-Fi parameters. In a project which already uses Wi-Fi for other reason (e.g., running a web server), is there a way to create an NTP clock without running a Wi-Fi setup?

Thanks.

In OLED clock manual mode, can't set the clock

I fixed this in controller.h by adding a manual config in setup. The code is below. I'm not an expert on git and don't have the time right now to do a pull request. Once some time is set, the manual clock change buttons, etc will work. But without this, it stays stuck at "Error". The new code is below setupClockInfo();

void setup() {
  // Restore from EEPROM to retrieve time zone.
  StoredInfo storedInfo;
  bool isValid = mPersistentStore.readStoredInfo(storedInfo);
#if FORCE_INITIALIZE
  setupClockInfo();
#else
  if (isValid) {
    restoreClockInfo(mClockInfo, storedInfo);
  } else {
    setupClockInfo();
    auto pacificTz = mZoneManager.createForZoneIndex(mZoneIndex);
    // Set the SystemClock using these components.
    auto pacificTime = ZonedDateTime::forComponents(
    2020, 2, 5, 4, 30, 0, pacificTz);
    mClock.setNow(pacificTime.toEpochSeconds());
  }
#endif

  // Retrieve current time from Clock and set the current clockInfo.
  updateDateTime();
}

Getting this error compiling for ESP32

Library Version: 2.2.3 in Platform.io for ESP32

In file included from .pio\libdeps\esp32doit-devkit-v1\AceCommon\src/AceCommon.h:54:0,
                 from .pio\libdeps\esp32doit-devkit-v1\AceTime\src/zoneinfo/ZoneRegistrar.h:10,
                 from .pio\libdeps\esp32doit-devkit-v1\AceTime\src/AceTime.h:31,
                 from include/hardware_drivers.h:13,
                 from src\hardware_drivers.cpp:1:
.pio\libdeps\esp32doit-devkit-v1\AceCommon\src/print_str/PrintStr.h:127:10: error: 'void ace_common::PrintStrBase::flush()' marked 'override', but does not override
     void flush() override {
          ^
Compiling .pio\build\esp32doit-devkit-v1\lib313\TinyGPSPlus\TinyGPS++.cpp.o
Compiling .pio\build\esp32doit-devkit-v1\lib97d\AceCommon\backslash_x_encoding\backslash_x_encoding.cpp.o
In file included from .pio\libdeps\esp32doit-devkit-v1\AceCommon\src/AceCommon.h:54:0,
                 from .pio\libdeps\esp32doit-devkit-v1\AceTime\src/zoneinfo/ZoneRegistrar.h:10,
                 from .pio\libdeps\esp32doit-devkit-v1\AceTime\src/AceTime.h:31,
                 from include/hardware_drivers.h:13,
                 from src\main.cpp:2:
.pio\libdeps\esp32doit-devkit-v1\AceCommon\src/print_str/PrintStr.h:127:10: error: 'void ace_common::PrintStrBase::flush()' marked 'override', but does not override
     void flush() override {
          ^
Compiling .pio\build\esp32doit-devkit-v1\lib97d\AceCommon\cstrings\copyReplace.cpp.o
*** [.pio\build\esp32doit-devkit-v1\src\hardware_drivers.cpp.o] Error 1
*** [.pio\build\esp32doit-devkit-v1\src\main.cpp.o] Error 1

Question: Does Acetime support standalone determination of timezone using GPS module?

The question assumes no internet access by the design, with everything needed to determine the Timezone based on the GPS provided coordinates. The design would need to incorporate a database for position comparison. Not sure how AceTime works and if it provides this database, how it does the position comparison to the database, etc.

Thanks,

Add support for other HW RTCs

Hello,

I've seen your project has DS3231 support.

I want to suggest to add DS3232 support. It uses same control registers so you can use same files or simply add a note about supporting this RTC.

Also you can add DS1307 support; works the same as DS3232 but you may need to change addresses a little.

I've developed a minimal RTC library where you can see how they work, and there I have the three RTCs datasheets: https://github.com/Naguissa/uRTCLib/tree/master/extras

Cheers!

correctly handle Fri<=1 expressions in TZ database

TZ Database version 2019b is the first version (in my short experience with the database) that contains the '<=' operator in 'dayOfWeek<=dayOfMonth' expression:

Rule    Zion    2005    2012    -       Apr     Fri<=1  2:00    1:00    D

I added support for this in BasicZoneProcessor::calcStartDayOfMonth() (and used by ExtendedZoneProcessor as well). But it looks like I still have some bugs in the various Python scripts such as transformer.py. The script needs to:

  • print a warning if the <= or >= shift causes a change into the previous or following month (for curiosity)
  • exclude Zones or Rules if the shift would cause a change into the previous or following year, since this is not (yet) supported in calcStartDayOfMonth()
  • fix a Python exception when creating the Anchor rule in _get_anchor_rule(), triggered when generating zonedbx/ files between 1940 to 2050, since it then causes Rule Zion to need an anchor rule, and the _get_anchor_rule() barfs on the Fri<=1

Q: AceTime with external database?

Hi,
Not an issue, but rather a question:
Is it possible to run AceTime with an external tz db?
For instance, on esp32 chips? There is a flash filesystem that could be updated OTA without recompiling the code.
For other MCUs - the DB could be on SD card.
Is it possible? Is it doable given current architecture even if it needs to be changed?

2.3.0 compile issues

Following the issue I raised last week in AceTimeClock (which is now resolved) I have updated AceTime to 2.2.3 AceTimeClock to 1.3.0 and AceCommon to 1.6.2. All is working. However if I move AceTime to 2.3.0 I get the compile errors below.

I am using the BasicZoneProcessor - which may be the issue and seems to be not recommended, but it does work in previous versions.

ld.exe: Sensor_MQTT_FrontDeck.cpp.o:(.literal._ZNK8ace_time5clock12EspSntpClock6getNowEv[_ZNK8ace_time5clock12EspSntpClock6getNowEv]+0x0): undefined reference to ace_time::Epoch::sDaysToCurrentEpochFromInternalEpoch

Error linking for board MH ET LIVE ESP32MiniKit (esp32_mhetesp32minikit)
Build failed for project 'Sensor_MQTT_FrontDeck'
ld.exe: Sensor_MQTT_FrontDeck.cpp.o:(.literal._ZNK8ace_time26BasicZoneProcessorTemplateINS_11zoneinfolow13ZoneInfoStoreINS1_11ZoneContextINS_5basic5BasicEEENS1_8ZoneInfoIS5_S6_EENS1_7ZoneEraIS5_EENS1_10ZonePolicyIS5_EENS1_8ZoneRuleIS5_EEEENS1_14ZoneInfoBrokerIS6_S8_SA_SC_SE_EENS1_13ZoneEraBrokerIS6_SA_SC_SE_EENS1_16ZonePolicyBrokerIS6_SC_SE_EENS1_14ZoneRuleBrokerIS6_SE_EEE16printShortNameToER5Print[_ZNK8ace_time26BasicZoneProcessorTemplateINS_11zoneinfolow13ZoneInfoStoreINS1_11ZoneContextINS_5basic5BasicEEENS1_8ZoneInfoIS5_S6_EENS1_7ZoneEraIS5_EENS1_10ZonePolicyIS5_EENS1_8ZoneRuleIS5_EEEENS1_14ZoneInfoBrokerIS6_S8_SA_SC_SE_EENS1_13ZoneEraBrokerIS6_SA_SC_SE_EENS1_16ZonePolicyBrokerIS6_SC_SE_EENS1_14ZoneRuleBrokerIS6_SE_EEE16printShortNameToER5Print]+0x0): undefined reference to ace_time::zoneinfo::findShortName(__FlashStringHelper const*)
ld.exe: Sensor_MQTT_FrontDeck.cpp.o:(.literal._ZNK8ace_time26BasicZoneProcessorTemplateINS_11zoneinfolow13ZoneInfoStoreINS1_11ZoneContextINS_5basic5BasicEEENS1_8ZoneInfoIS5_S6_EENS1_7ZoneEraIS5_EENS1_10ZonePolicyIS5_EENS1_8ZoneRuleIS5_EEEENS1_14ZoneInfoBrokerIS6_S8_SA_SC_SE_EENS1_13ZoneEraBrokerIS6_SA_SC_SE_EENS1_16ZonePolicyBrokerIS6_SC_SE_EENS1_14ZoneRuleBrokerIS6_SE_EEE16initForLocalDateERKNS_9LocalDateE[_ZNK8ace_time26BasicZoneProcessorTemplateINS_11zoneinfolow13ZoneInfoStoreINS1_11ZoneContextINS_5basic5BasicEEENS1_8ZoneInfoIS5_S6_EENS1_7ZoneEraIS5_EENS1_10ZonePolicyIS5_EENS1_8ZoneRuleIS5_EEEENS1_14ZoneInfoBrokerIS6_S8_SA_SC_SE_EENS1_13ZoneEraBrokerIS6_SA_SC_SE_EENS1_16ZonePolicyBrokerIS6_SC_SE_EENS1_14ZoneRuleBrokerIS6_SE_EEE16initForLocalDateERKNS_9LocalDateE]+0x8): undefined reference to ace_time::internal::createAbbreviation(char*, unsigned char, char const*, unsigned int, char const*)
 
ld.exe: Sensor_MQTT_FrontDeck.cpp.o: in function ace_time::zoneinfolow::ZoneInfoBroker<ace_time::zoneinfolow::ZoneContext<ace_time::basic::Basic>, ace_time::zoneinfolow::ZoneInfo<ace_time::basic::Basic, ace_time::zoneinfolow::ZoneContext<ace_time::basic::Basic> >, ace_time::zoneinfolow::ZoneEra<ace_time::basic::Basic>, ace_time::zoneinfolow::ZonePolicy<ace_time::basic::Basic>, ace_time::zoneinfolow::ZoneRule<ace_time::basic::Basic> >::printShortNameTo(Print&) const
BrokersLow.h:464: undefined reference to ace_time  zoneinfo  findShortName(__FlashStringHelper const*)
 
ld.exe: Sensor_MQTT_FrontDeck.cpp.o: in function ace_time::BasicZoneProcessorTemplate<ace_time::zoneinfolow::ZoneInfoStore<ace_time::zoneinfolow::ZoneContext<ace_time::basic::Basic>, ace_time::zoneinfolow::ZoneInfo<ace_time::basic::Basic, ace_time::zoneinfolow::ZoneContext<ace_time::basic::Basic> >, ace_time::zoneinfolow::ZoneEra<ace_time::basic::Basic>, ace_time::zoneinfolow::ZonePolicy<ace_time::basic::Basic>, ace_time::zoneinfolow::ZoneRule<ace_time::basic::Basic> >, ace_time::zoneinfolow::ZoneInfoBroker<ace_time::zoneinfolow::ZoneContext<ace_time::basic::Basic>, ace_time::zoneinfolow::ZoneInfo<ace_time::basic::Basic, ace_time::zoneinfolow::ZoneContext<ace_time::basic::Basic> >, ace_time::zoneinfolow::ZoneEra<ace_time::basic::Basic>, ace_time::zoneinfolow::ZonePolicy<ace_time::basic::Basic>, ace_time::zoneinfolow::ZoneRule<ace_time::basic::Basic> >, ace_time::zoneinfolow::ZoneEraBroker<ace_time::zoneinfolow::ZoneContext<ace_time::basic::Basic>, ace_time::zoneinfolow::ZoneEra<ace_time::basic::Basic>, ace_time::zoneinfolow::ZonePolicy<ace_time::basic::Basic>, ace_time::zoneinfolow::ZoneRule<ace_time::basic::Basic> >, ace_time::zoneinfolow::ZonePolicyBroker<ace_time::zoneinfolow::ZoneContext<ace_time::basic::Basic>, ace_time::zoneinfolow::ZonePolicy<ace_time::basic::Basic>, ace_time::zoneinfolow::ZoneRule<ace_time::basic::Basic> >, ace_time::zoneinfolow::ZoneRuleBroker<ace_time::zoneinfolow::ZoneContext<ace_time::basic::Basic>, ace_time::zoneinfolow::ZoneRule<ace_time::basic::Basic> > >::calcAbbreviations() const
BasicZoneProcessor.h:888: undefined reference to ace_time  internal  createAbbreviation(char*, unsigned char, char const*, unsigned int, char const*)
 
collect2.exe*: error: ld returned 1 exit status

Include order issue

Discussed in #76

Originally posted by rvdbreemen October 16, 2021
Well, interestingly enough I struggled with the order of the includes.

So I am using TimeLib.h next to AceTime.h. I do this to minimize code change... Historically I used ezTime and before that TimeLib. Anyway, there is lots of compile errors if I include AceTime later dan TimeLib.

So the order that worked for me is:
#include <AceTime.h>
#include <TimeLib.h>

There must be a namespace conflict or something, because if I do it the otherway around I won't even compile.

What could be the reason for that?

The reason why I included TimeLib.h again,is that AceTime does not support the normal now(), hour(), minute(), etc. API.

Would it be thinkable to support a "default Timezone" that you setup on the object, so that the "TimeLib" API would also work?

List timezone names

I'm trying to get a list of all timezone names, but struggling to understand the ZoneInfo name format:

for (uint16_t n = 0; n < ace_time::zonedb::kZoneRegistrySize; n++) {
    auto a = ace_time::zonedb::kZoneRegistry[n];
    Serial.println(a->name);
}

This prints part of the name, but without the prefix/fragment.

22:3:56.584 -> �Detroit
22:3:56.585 -> �Bogota
22:3:56.586 -> �Glace_Bay

How would I get to a list that contains full names like Europe/London ?

createForZoneName no longer working for "Europe/Amsterdam"

With the current AceTime release the .createForZoneName is no longer working for my default timezone, which is the Netherlands?

It had been a while since I updated your library to the latest and the greatest. And I use it to lookup user input to match with a TimeZone name. Now the default always works, which is "Europe/Amsterdam".

I have taken your Hello Timezone Manager example, and extended it with some entries:

  TimeZone londonTz = manager.createForZoneName("Europe/London");
  ZonedDateTime londonTime = losAngelesTime.convertToTimeZone(londonTz);
  londonTime.printTo(SERIAL_PORT_MONITOR);
  SERIAL_PORT_MONITOR.println();

  // Create Europe/Amsterdam timezone by ZoneName.
  TimeZone amsterdamTz = manager.createForZoneName("Europe/Amsterdam");
  ZonedDateTime amsterdamTime = losAngelesTime.convertToTimeZone(amsterdamTz);
  amsterdamTime.printTo(SERIAL_PORT_MONITOR);
  SERIAL_PORT_MONITOR.println();
  
  // Create Europe/Brussels timezone by ZoneName.
  TimeZone brusselsTZ = manager.createForZoneName("Europe/Brussels");
  ZonedDateTime brusselsTime= losAngelesTime.convertToTimeZone(brusselsTZ);
  brusselsTime.printTo(SERIAL_PORT_MONITOR);
  SERIAL_PORT_MONITOR.println();

Output:
2019-03-10T03:00:00-07:00[America/Los_Angeles]
2019-03-10T10:00:00+00:00[Europe/London]
<Invalid ZonedDateTime>
2019-03-10T11:00:00+01:00[Europe/Brussels]
2019-03-10T21:00:00+11:00[Australia/Sydney]


improve STDOFF and DST offsets to handle one minute resolution

Currently (v0.7.2), the AT and UNTIL times are handled with one-minute resolution. But the STDOFF and DST offsets (in RULES column with 'hh:mm' and SAVE column) are handled using a 15-minute resolution. The 15-minute resolution is sufficient for all timezones after the year 2000, but if we want to support historical DST shifts before year 2000, then we need to support one-minute resolution.

An example is Pacific/Kiritimati which used a UTC offset of -10:40 from 1901 to 1979:

# Zone  NAME            STDOFF  RULES   FORMAT  [UNTIL]
Zone Pacific/Kiritimati -10:29:20 -     LMT     1901
                        -10:40  -       -1040   1979 Oct                        
                        -10:00  -       -10 

If we go very far back, there are a number of timezones which have UTC offsets in one-second resolution. Because I want to keep the zoneinfo files as small as possible, I don't think these will be supported. For curiosity, here is the output from tzcompiler.py if we ask it to truncate the offsets to 1-minute resolution, for the years 1935 - 2050:

// Africa/El_Aaiun (STDOFF '-0:52:48' truncated to '-00:52')
// Africa/Johannesburg (RULES not fixed but FORMAT is missing '%' or '/')
// Africa/Monrovia (STDOFF '-0:44:30' truncated to '-00:44')
// America/Goose_Bay (STDOFF '-3:30:52' truncated to '-03:30')
// America/Managua (STDOFF '-5:45:12' truncated to '-05:45')
// America/Paramaribo (STDOFF '-3:40:36' truncated to '-03:40', STDOFF '-3:40:52' truncated to '-03:40')
// America/St_Johns (STDOFF '-3:30:52' truncated to '-03:30')
// Asia/Dhaka (STDOFF '5:53:20' truncated to '05:53')
// Asia/Riyadh (STDOFF '3:06:52' truncated to '03:06')
// Asia/Tehran (STDOFF '3:25:44' truncated to '03:25')
// Asia/Thimphu (STDOFF '5:58:36' truncated to '05:58')
// Atlantic/Azores (RULES not fixed but FORMAT is missing '%' or '/')
// Atlantic/Madeira (RULES not fixed but FORMAT is missing '%' or '/')          
// Europe/Amsterdam (STDOFF '0:19:32' truncated to '00:19')

Broken SAMD core testing because of AceTime

Compiling sketch: /home/runner/Arduino/libraries/AceTime/examples/HelloDateTime
  In file included from /home/runner/.arduino15/packages/arduino/hardware/samd/1.8.11/cores/arduino/api/ArduinoAPI.h:31:0,
                   from /home/runner/.arduino15/packages/arduino/hardware/samd/1.8.11/cores/arduino/Arduino.h:23,
                   from /home/runner/Arduino/libraries/AceTime/src/ace_time/LocalDateTime.h:12,
                   from /home/runner/Arduino/libraries/AceTime/src/ace_time/OffsetDateTime.h:11,
                   from /home/runner/Arduino/libraries/AceTime/src/ace_time/ZonedDateTime.h:11,
                   from /home/runner/Arduino/libraries/AceTime/src/ace_time/ZonedDateTime.cpp:7:
  /home/runner/.arduino15/packages/arduino/hardware/samd/1.8.11/cores/arduino/api/Print.h:96:16: error: 'Print' is already declared in this scope
   using arduino::Print;
                  ^~~~~
  
  Error during build: exit status 1
  
Error: Compilation failed

gcc 11.3 compiler warning

I recently upgraded the toolchain I am using to build from gcc 5.4.1 to 11.3.1.

The compiler now emits this warning that looks valid although probably innocuous seeing that the code explicitly null terminates the string immediately after the strncpy call
In static member function 'static void ace_time::ExtendedZoneProcessorTemplate<BF, ZIB, ZEB, ZPB, ZRB>::createAbbreviation(char*, uint8_t, const char*, uint16_t, const char*) [with BF = ace_time::extended::BrokerFactory; ZIB = ace_time::extended::ZoneInfoBroker; ZEB = ace_time::extended::ZoneEraBroker; ZPB = ace_time::extended::ZonePolicyBroker; ZRB = ace_time::extended::ZoneRuleBroker]', inlined from 'static void ace_time::ExtendedZoneProcessorTemplate<BF, ZIB, ZEB, ZPB, ZRB>::createAbbreviation(char*, uint8_t, const char*, uint16_t, const char*) [with BF = ace_time::extended::BrokerFactory; ZIB = ace_time::extended::ZoneInfoBroker; ZEB = ace_time::extended::ZoneEraBroker; ZPB = ace_time::extended::ZonePolicyBroker; ZRB = ace_time::extended::ZoneRuleBroker]' at .pio/libdeps/teensy41/AceTime/src/ace_time/ExtendedZoneProcessor.h:2115:17, inlined from 'static void ace_time::ExtendedZoneProcessorTemplate<BF, ZIB, ZEB, ZPB, ZRB>::calcAbbreviations(ace_time::ExtendedZoneProcessorTemplate<BF, ZIB, ZEB, ZPB, ZRB>::Transition**, ace_time::ExtendedZoneProcessorTemplate<BF, ZIB, ZEB, ZPB, ZRB>::Transition**) [with BF = ace_time::extended::BrokerFactory; ZIB = ace_time::extended::ZoneInfoBroker; ZEB = ace_time::extended::ZoneEraBroker; ZPB = ace_time::extended::ZonePolicyBroker; ZRB = ace_time::extended::ZoneRuleBroker]' at .pio/libdeps/teensy41/AceTime/src/ace_time/ExtendedZoneProcessor.h:2098:27: .pio/libdeps/teensy41/AceTime/src/ace_time/ExtendedZoneProcessor.h:2149:18: warning: 'char* strncpy(char*, const char*, size_t)' specified bound 7 equals destination size [-Wstringop-truncation] 2149 | strncpy(dest, format, destSize); | ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
Perhaps the final argument should be changed to destSize-1 like line #2126?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.