Giter Club home page Giter Club logo

ropg / eztime Goto Github PK

View Code? Open in Web Editor NEW
327.0 23.0 92.0 13.36 MB

ezTime — pronounced "Easy Time" — is a very easy to use Arduino time and date library that provides NTP network time lookups, extensive timezone support, formatted time and date strings, user events, millisecond precision and more.

License: MIT License

Makefile 0.34% C++ 91.43% PHP 6.81% Shell 1.41%
time timezones timezone-conversion timestamp events milliseconds ntp ntp-client formatted-output datetime

eztime's Introduction

Jump to:   Table of Contents  —  Function Reference  —  dateTime function

ezTime, an Arduino library for all of time *

                                            written by Rop Gonggrijp

ezTime — pronounced "Easy Time" — is a very easy to use Arduino time and date library that provides NTP network time lookups, extensive timezone support, formatted time and date strings, user events, millisecond precision and more.

                                                                                                                                        * limitations may apply, see "2036 and 2038" chapter

 

A brief history of ezTime

I was working on M5ez, an interface library to easily make cool-looking programs for the "M5Stack" ESP32 hardware. The status bar of M5ez needed to display the time. That was all, I swear. I figured I would use Time, Michael Margolis' and Paul Stoffregen's library to do time things on Arduino. Then I needed to sync that to an NTP server, so I figured I would use NTPclient, one of the existing NTP client libraries. And then I wanted it to show the local time, so I would need some way for the user to set an offset between UTC and local time.

So far, so good.

Then I remembered how annoyed I always am when daylight savings time comes or goes, as I have to manually set some of my clocks such as the microwave oven, the clock in the car dashboard, etc etc. It's 2018, my clock should know about timezone rules. So I could get Jack Christensen's Timezone library. But it needs the timezone's rules, like "DST goes into effect on the last Sunday in March at 02:00 local time" told to it. I figured I would simply get this data from the internet and parse it.

Then I wanted 12 or 24 hour time displayed, and thought about various formats for date and time. Wouldn't it be nice to have some function to print formatted time like many programming languages offer?

Overlooking the battlefield after implementing some part of this, it seemed like there had to be a better way. Some way in which all this work would benefit more people. This is how ezTime — the project that was only going to take a few days — came to be.

ezTime is ...

self-contained: It only depends on other libraries to get online, but then it doesn't need other libraries for NTP and timezone data lookups. (And even networking can be disabled completely if you have another source for time.)

precise: Unlike other libraries, ezTime does not throw away or mangle the fractional second information from the NTP server. An NTP request to pool.ntp.org only takes 40ms round-trip on home DSL these days, so adding sub-second precision to a time library makes sense. ezTime reads the fractional seconds and tries to account for network latency to give you precise time.

backwards compatible: Anything written for the existing Arduino time library will still work. You can set which timezone the sketch should be in, or have it be in UTC which is the default. But you can also set and express time referring to multiple timezones, all very easy and intuitive.

eventful: You can set events to have ezTime execute your own functions at a given time, and delete the events again if you change your mind.

robust: It doesn't fail if the timezone api goes away: it can use cached data, which ezTime can store in EEPROM (AVR Arduinos) or NVS (e.g. ESP32 through Preferences library).

informative: No need to guess while you're working on something, ezTime can print messages to the serial port at your desired level of detail, telling you about the timezone's daylight savings info it receives or when it gets an NTP update and by how much your internal clock was off, for instance.

time-saving: No more time spent on writing code to print date or time in some nicer way. Print things like "8:20 PM" or "Saturday the 23rd of August 2018" with ease. Prevent display-flicker with minuteChanged() and secondChanged() functions without storing any values to compare.

multilingual: Can display names of days and months in different languages. Easy to add your own language.

small enough: Works with all features and full debugging information on an old Arduino Uno with an Ethernet Shield, leaving 2/3 of RAM and even some of the flash for you to work with. Various #define options let you leave parts of the library out if you want to make it smaller: you can even leave out the networking altogether if you have a different time source.

easy to use: Don't believe it until you see it. Have a look at some of these examples to see how easy it is to use.

 

Timezones

(a complete sketch to show how simple it is)

#include <ezTime.h>
#include <WiFi.h>

void setup() {
	Serial.begin(115200);
	WiFi.begin("your-ssid", "your-password");

	waitForSync();

	Serial.println("UTC: " + UTC.dateTime());
	
	Timezone NewZealand;
	NewZealand.setLocation("Pacific/Auckland");
	Serial.println("New Zealand time: " + NewZealand.dateTime());
}

void loop() { }
UTC: Friday, 07-Sep-2018 11:25:10 UTC
New Zealand time: Friday, 07-Sep-2018 23:25:11 NZST

 

Formatted date and time

Serial.println("COOKIE:      " + UTC.dateTime(COOKIE));
Serial.println("ISO8601:      " + UTC.dateTime(ISO8601));
Serial.println("RFC822:      " + UTC.dateTime(RFC822));
Serial.println("RFC850:      " + UTC.dateTime(RFC850));
Serial.println("RFC3339:     " + UTC.dateTime(RFC3339));
Serial.println("RFC3339_EXT: " + UTC.dateTime(RFC3339_EXT));
Serial.println("RSS:         " + UTC.dateTime(RSS));
Serial.println();
Serial.println("or like " + UTC.dateTime("l ~t~h~e jS ~o~f F Y, g:i A") );
COOKIE:      Saturday, 25-Aug-2018 14:23:45 UTC
ISO8601:      2018-08-25T14:23:45+0000
RFC822:      Sat, 25 Aug 18 14:23:45 +0000
RFC850:      Saturday, 25-Aug-18 14:23:45 UTC
RFC3339:     2018-08-25T14:23:45+00:00
RFC3339_EXT: 2018-08-25T14:23:45.846+00:00
RSS:         Sat, 25 Aug 2018 14:23:45 +0000

or like Saturday the 25th of August 2018, 2:23 PM

 

milliseconds

for (int n = 0; n < 10; n++) {
	Serial.println(UTC.dateTime("l, d-M-y H:i:s.v T"));
}
Saturday, 25-Aug-18 14:32:53.282 UTC
Saturday, 25-Aug-18 14:32:53.283 UTC
Saturday, 25-Aug-18 14:32:53.284 UTC
Saturday, 25-Aug-18 14:32:53.285 UTC
Saturday, 25-Aug-18 14:32:53.287 UTC
Saturday, 25-Aug-18 14:32:53.290 UTC
Saturday, 25-Aug-18 14:32:53.293 UTC
Saturday, 25-Aug-18 14:32:53.297 UTC
Saturday, 25-Aug-18 14:32:53.300 UTC
Saturday, 25-Aug-18 14:32:53.303 UTC

This is on my ESP32. See how it fills up the serial buffer real fast at first, and then has to wait for the characters to be sent before it can return?

 

Rich information and ... oh my just look at these NTP updates

[...]
	setInterval(60);
	setDebug(INFO);
}

void loop() {
	events();
}
ezTime debug level set to INFO
Querying pool.ntp.org ... success (round trip 42 ms)
Received time: Saturday, 25-Aug-18 14:34:53.410 UTC (internal clock was 1 ms fast)
Querying pool.ntp.org ... success (round trip 43 ms)
Received time: Saturday, 25-Aug-18 14:35:53.480 UTC (internal clock was 1 ms slow)
Querying pool.ntp.org ... success (round trip 43 ms)
Received time: Saturday, 25-Aug-18 14:36:53.525 UTC (internal clock was 1 ms slow)
Querying pool.ntp.org ... success (round trip 36 ms)
Received time: Saturday, 25-Aug-18 14:37:53.573 UTC (internal clock was 4 ms slow)
Querying pool.ntp.org ... success (round trip 35 ms)
Received time: Saturday, 25-Aug-18 14:38:53.636 UTC (internal clock was spot on)
Querying pool.ntp.org ... success (round trip 32 ms)
Received time: Saturday, 25-Aug-18 14:39:53.674 UTC (internal clock was 1 ms slow)

 

Getting started

ezTime is an Arduino library. To start using it with the Arduino IDE:

  • Choose Sketch -> Include Library -> Manage Libraries...
  • Type ezTime into the search box.
  • Click the row to select the library.
  • Click the Install button to install the library.

in File -> Examples you will now see an ezTime heading down under "Examples from custom libraries". You can try running some of these examples to see if it all works. ezTime is made to be, as the name implies, quite easy to use. So you'll probably understand a lot of how things work from just looking at the examples. Now either just play with those and use the rest of this documentation only when you get stuck, or keep reading to see how things work in ezTime.

 

ezTime User Manual

 

About this manual

Semi-internal functions

Some functions are not necessarily useful for everyday users of this library, but might be useful to someone someday. For instance, this library checks with the NTP servers automatically, so there should be no need to ever "manually" get an NTP response. But the function to do that is still exposed to the user. Even some functions that have nothing to do with time, like zeropad are there for you to use, simply because they might be useful to someone, and the library needed them internally so they come at no extra cost in terms of size. In this manual, the names of these functions are printed in italics in their chapter headings, just to make it a easier for you to see which functions are core functionality and which are really not needed in everyday use.

Specifying time

I hate documentation that still makes me reach for for the source code, so this manual supplies the function prototype with each function so you can see what types or arguments each function takes and what type the return value is. I took one shortcut though. A lot of functions allow you to specify a time. In the function prototype this looks like:

time_t t = TIME_NOW, const ezLocalOrUTC_t local_or_utc = LOCAL

Throughout this manual, we replace these two optional arguments in the function definitions with:

TIME

That's because the prior is just a little too long to be repeating a thousand times, and it also makes things look more complicated than they need to be. In most places where you specify a time in ezTime, you are most likely to mean "right now". This can be done by supplying no arguments at all, or TIME_NOW. You might make a number of requests in a row, and want to make sure that the time didn't change between them. No need to stick the time value in a variable. After you have made a call specifying no time (meaning TIME_NOW), you can specify LAST_READ to use the time from the exact moment you made that first call.

Otherwise, you can specify a time_t value, a well-known 32-bit signed integer way of specifying time in seconds elapsed since 00:00 Jan 1st 1970. If you specify a value other than TIME_NOW or LAST_READ, you can then specify whether you mean in UTC or local time, by following it with a second argument that is either UTC_TIME or LOCAL_TIME.

For example, if you have set up a timezone called Berlin, Berlin.isDST(1536314299, UTC_TIME) tells you whether Daylight Savings Time is in effect on that time, as seconds from 00:00 Jan 1st 1970 UTC, as opposed to the same amount of seconds from that time in Berlin (which would be the default). There will be some examples later on, showing you how to create and process such timestamps. Mostly though, you don't need specify anything at all because you just want something time-related about "right now".

Time-geek sidenote: ezTime does not have historical information about the daylight savings rules of the past or future, it only applies the rules it has now as if they also applied in the past or future. Check here for historical records for timezones.

 

How it all works

What happens when you include the library

It all starts when you include the library with #include <ezTime.h>. From that point forward you can use the functions in this manual to control the behaviour of ezTime. There will then also be a timezone object called UTC, which will be set as the default timezone for all commands that take an optional timezone prefix.

No daemons here

It is important to understand what ezTime does NOT do. It does not somehow create a background process that keeps time, contacts servers, or whatever. The Arduino does the timekeeping for us with its millis() counter, which keeps the time in milliseconds since the Arduino started. All ezTime does when it synchronises time is to store a time (in seconds since 1970) and the position of the millis counter when that was. By seeing how much the millis counter has advanced and adding that starting point since 1970, ezTime tells time. But that internal clock isn't perfect, it may — very slowly — drift away from the actual time. That's why there is a periodic event set to synchronise the clock with the NTP server.

If you want events to happen — whether your own or the NTP updates that ezTime does periodically) — you should have events() in the main loop of your program.

But I only just woke up !

Your code might call Serial.println(UTC.dateTime()); to print a complete textual representation of date and time in the default format to the serial port. The library would find out that time had not been synchronised yet, and it would send off an NTP request to one of the NTP servers that pool.ntp.org resolves to. If your Arduino has just woken up, it probably hasn't gotten its DHCP information, or is not connected to the WiFi network just yet. And so the time lookup would fail and the call to .dateTime would return a String with the date and time just after midnight on the 1st of January 1970: the zero-point for the unix-style time counter used by ezTime. It would later correct to the real time, but that's not pretty.

Worse is when you set up a timezone for which you would like to retrieve the daylight savings rules from the server: it can't do that if the connection isn't up yet. So that's why there's a function called waitForSync that simply calls events() until it is synchronized (or until a set number of seconds passes, see below).

 

Setting and synchronising time

The NTP request from the scenario above failed because the network wasn't up yet, so the clock would still not be synchronised. A new request will be scheduled for 1801 seconds later, and sent when your code (or waitForSync) calls events.

 

timeStatus

timeStatus_t timeStatus();

Returns what state the clock is in. timeStatus() will return one of:

timeStatus meaning
timeNotSet No NTP update or manual setting of the clock (by calling the .setTime method of a timezone) has taken place
timeSet The clock should have the current time
timeNeedsSync A scheduled NTP request has been due for more than an hour. (The time an update needs to be due before timeNeedsSync is set is configured by the NTP_STALE_AFTER define in the ezTime.h file.)

 

waitForSync

bool waitForSync(uint16_t timeout = 0);

If your code uses timezones other than UTC, it might want to wait to initialise them until there is a valid time to see if the cached timezone definitions are still current. And if you are displaying a calendar or clock, it might look silly if it first says midnight on January 1st 1970 before showing the real time. waitForSync will wait for the network to connect, and then for the time to be synchronised before returning true. If you specify a timeout (in seconds), it will return after that many seconds even if the clock is not in sync yet, returning false. (ezTime error TIMEOUT, see the chapter on error and debug messages further down)

 

setServer and setInterval

void setServer(String ntp_server = NTP_SERVER);

void setInterval(uint16_t seconds = 0);

By default, ezTime is set to poll pool.ntp.org about every 30 minutes. These defaults should work for most people, but you can change them by specifying a new server with setServer or a new interval (in seconds) with setInterval. If you call setInterval with an interval of 0 seconds or call it as setInterval(), no more NTP queries will be made.

 

updateNTP

void updateNTP();

Updates the time from the NTP server immediately. Will keep retrying about every 30 minutes (defined by NTP_RETRY in ezTime.h), will schedule the next update to happen after the normal interval.

 

lastNtpUpdateTime

time_t lastNtpUpdateTime();

Will return the last time the time was successfully synchronized with the NTP server.

 

queryNTP

bool queryNTP(String server, time_t &t, unsigned long &measured_at);

This will send a single query to the NTP server your specify. It will put, in the t and measured_at variables passed by reference, the UTC unix-time and the millis() counter at the time the exact second happened. It does this by subtracting from millis() the fractional seconds received in the answer, as well as half the time it took to get an answer. This means it assumes the network delay was symmetrical, meaning it took just as long for the request to get to the server as for the answer to get back.

If the time server answers, queryNTP returns true. If false is returned, error() will return either NO_NETWORK (if the WiFi is not connected) or TIMEOUT if a response took more than 1500 milliseconds (defined by NTP_TIMEOUT in ezTime.h).

Note that this function is used internally by ezTime, but does not by itself set the time ezTime keeps. You will likely never need to call this from your code.

 

Timezones

If only it was as uncomplicated as this map suggests. Every band is actually made up of countries that all change to their Daylight Saving Time on different dates, and they even frequently change the rules for when that happens.

Timezones in ezTime are objects. They can be created with Timezone yourTZ, where yourTZ is the name you choose to refer to the timezone. In this manual, this name will be used from now on. But you can naturally choose any name you want.

Internally, ezTime stores everything it knows about a timezone as two strings. One is the official name of the timezone in "Olson" format (like Europe/Berlin). That name is used to then update when needed all the other information needed to represent time in that timezone. This is in another string, in so-called "posix" format. It's often a little longer and for Berlin it is CET-1CEST,M3.5.0,M10.5.0/3. The elements of this string have the following meanings:

Element meaning
CET Name of timezone in standard time (CET = Central European Time in this case.)
-1 Hours offset from UTC, meaning subtract one hour from this time to get to UTC. (Note offset is often written elsewhere the other way around (so +1 in this case), just to confuse things.) Could also specify minutes, like -05:30 for India.
CEST Name of timezone in Daylight Saving Time (DST), CEST stands for Central European Summer Time
,M3 DST starts in March
.5 On the last occurrence of
.0 a Sunday
/2 at 02:00 local time
,M10 DST ends in October
.5 on the last occurrence of
.0 a Sunday
/3 at 03:00 local time

 

setDefault

void setDefault()    — MUST be prefixed with name of a timezone, like yourTz.setDefault()

#include <ezTime.h> includes the library, creates ezTime object and UTC instance of Timezone class, as well as defaultTZ, which is a reference to UTC unless you set it to another timezone by calling yourTZ.setDefault(). ezTime is compatible with the classic Arduino time library, and thus you can call various functions in the root namespace like hour() and minute() — without a timezone in front. They are interpreted as if passed to the default timezone. So if you have existing code, just setting up a timezone and making it the default should cause that code to work as if the time was set in local time. New code that depends on ezTime should probably explicitly mention the timezone.

 

setPosix

bool setPosix(String posix)    — MUST be prefixed with name of a timezone, like India.setPosix("IST-5:30")

Allows you to directly enter the posix information for a timezone. For simple timezones, you could set things up manually. For example for India, a mere

Timezone India;
India.setPosix("IST-5:30");
Serial.println(India.dateTime());

is enough, because the time in India doesn't go back and forth with the coming and going of Daylight Savings Time (even though the half hour offset to UTC is pretty weird.)

 

getPosix

String getPosix()    — MUST be prefixed with name of a timezone, like India.getPosix()

getPosix does what you would expect and simply returns the posix string stored in ezTime for a given timezone.

 

isDST

bool isDST(TIME);    — Assumes default timezone if no timezone is prefixed

Tells you whether DST is in effect at a given time in this timezone. If you do not provide arguments, it's interpreted as 'right now'. You can also specify a time (in seconds since 1970, we'll get back to that) in the first argument. If you want to know a certain time in UTC in within the DST windown in a given timezone you can set the second argument to false, otherwise it is assumed you are asking about a time expressed as local time.

 

getTimezoneName

String getTimezoneName(TIME);    — Assumes default timezone if no timezone is prefixed

Provides the current short code for the timezone, like IST for India, or CET (during standard time) or CEST (during Daylight Saving Time) for most of Europe.

 

getOffset

int16_t getOffset(TIME)    — Assumes default timezone if no timezone is prefixed

Provide the offset from UTC in minutes at the indicated time (or now if you do not specify anything). The offset here is in the same direction as the posix information, so -120 means 2 hours east of UTC.

 

setLocation

boolsetLocation(String location = "")    — MUST be prefixed with name of a timezone

With setLocation you can provide a string to do an internet lookup for a timezone. The string can either be an Olson timezone name, like Europe/Berlin (or some unique part of such a name). (Here is a complete list of these names.) Or it can be a two-letter country code for any country that does not span multiple timezones, like NL or DE (but not US). After the information is retrieved, it is loaded in the current timezone, and cached if a cache is set (see below). setLocation will return false (Setting either NO_NETWORK, DATA_NOT_FOUND or SERVER_ERROR) if it cannot get timezone information.

If you provide no location ( YourTZ.setLocation() ), ezTime will attempt to do a GeoIP lookup to find the country associated with your IP-address. If that is a country that has a single timezone, that timezone will be loaded, otherwise a SERVER_ERROR ("Country Spans Multiple Timezones") will result.

In the case of SERVER_ERROR, errorString() returns the error from the server, which might be "Country Spans Multiple Timezones", "Country Not Found", "GeoIP Lookup Failed" or "Timezone Not Found".

If you execute multiple calls to setLocation, make sure they are more than 3 seconds apart, because the server will not answer if calls from the same IP come within 3 seconds of one another (see below).

 

timezoned.rop.nl

timezoned.rop.nl is ezTime's own timezone service that it connects to. It is a simple UDP service that gets a packet on UDP port 2342 with the request, and responds with a packet that holds the POSIX information for that timezone (after OK ) or the error (after ERR ). It will only respond to the same IP-number once every three seconds to prevent being used in DDoS attacks.

The service has the potential of seeing which IP-numbers use ezTime and what timezone data they request. Any GeoIP lookups are done against a local database, no third parties are involved. The service does not keep logfiles unless something is wrong and needs debugging. In such a case any logfiles will be deleted after work is done, but within 48 hours at the latest.

Data has never been used for any other purposes than debugging, nor is any other use envisioned in the future.

The code for the timezoned server is included in the server directory of the library repository, in case someone wnats to know how that works or insists on running a timezone information server themselves. Be aware that it is a bit of an ugly hack at the time of writing this...

 

Timezone caching, EEPROM or NVS

If you use setLocation, the timezone information comes from timezoned.rop.nl. I'll try to keep that running as stable as possible, but if that service has a problem, your Arduino would not know what time it is anymore.

That is why you can create a place for ezTime to store the data about the timezone. That way, it doens't need to get the information anew every time the Arduino boots. You can store the cache for a timezone in EEPROM (the default) or NVS.

If your code says tz.setCache(0) it will try to read and interpret the data from EEPROM location 0 immediately, and it will store any future updated data it receives for that timezone there. Some programs might want to just start up in whatever timezone the user has set before, so they just call yourTZ.setCache(0) when they start and yourTZ.setLocation when the user goes to settings to select a different timezone. Simple programs might do:

if (!someTZ.setCache(0)) someTZ.setLocation("Europe/Berlin");

To only get the timezone data from the internet when the cache is empty or outdated and use the cached information all the other times. (Note that if you change the city in the above example it will still get the Berlin information from the cache and not execute the setLocation until you run someTZ.clearCache().

 

setCache

bool setCache(int16_t address)    — MUST be prefixed with name of a timezone

If your ezTime is compiled with #define EZTIME_CACHE_EEPROM (which is the default), you can supply an EEPROM location. A single timezone needs 50 bytes to cache. The data is written in compressed form so that the Olson and Posix strings fit in 3/4 of the space they would normally take up, and along with it is stored a checksum, a length field and a single byte for the month in which the cache was retrieved, in months after January 2018.

bool setCache(String name, String key)    — MUST be prefixed with name of a timezone

On ESP32 and possibly other platforms, there is an emulation for the EEPROM in flash, but there is also a nicer mechanism that stores keys and values in flash. You can use this by enabling #define EZTIME_CACHE_NVS in ezTime.h You can then supply a section name and a key to serve as the cache storage location for a given timezone.

 

clearCache

void clearCache(bool delete_section = false)    — MUST be prefixed with name of a timezone

Clears the cache for a timezone. If you use EEPROM, the bytes are overwritten with zeroes, if you use NVS, the key is deleted. If you provide the argument true using NVS the entire section is deleted. Do this only if that section does not contain anything else that you want to keep.

 

Crazy timezones

Chatham Islands and Nepal

The Chatham Islands are in Pacific about 800 kilometres east of New Zealand. Some 600 people live there, but they have their own timezone (UTC+12:45). It is one of only three time zones with a 45-minute offset from UTC, the others being Nepal Time (UTC+05:45) and the unofficial Australian Central Western Time (UTC+08:45). These timezones work fine in ezTime.

Morocco

Morocco goes on and off Daylight Saving Time twice per year. This currently breaks ezTime as our parser can only handle one DST period per year. Fortunately they will stop doing this in 2020: the Moroccans probably got tired of all the clocks that did not adjust properly.

 

Getting date and time

dateTime

String dateTime(TIME, String format = DEFAULT_TIMEFORMAT);
    — Assumes default timezone if no timezone is prefixed

We'll start with one of the most powerful functions of ezTime. With dateTime you can represent a date and/or a time in any way you want. You do this in the same way you do in many programming languages: by providing a special formatting string. Many characters in this string have special meanings and will be replaced. What this means is that UTC.dateTime("l, d-M-y H:i:s.v T") might return Saturday, 25-Aug-18 14:32:53.282 UTC. Below is the list of characters and what they are replaced by. Any characters not on this list are simply not replaced and stay as is. See the last two entries for a way to use characters on this list in your string.

char replaced by
d Day of the month, 2 digits with leading zeros
D First three letters of day in English, like Tue
j Day of the month without leading zeros
l (lowercase L) Day of the week in English, like Tuesday
N // ISO-8601 numeric representation of the day of the week. (1 = Monday, 7 = Sunday)
S English ordinal suffix for the day of the month, 2 characters (st, nd, rd, th)
w Numeric representation of the day of the week (0 = Sunday)
F A month's name, such as January
m Numeric representation of a month, with leading zeros
M Three first letters of a month in English, like Apr
n Numeric representation of a month, without leading zeros
t Number of days in the given month
Y A full numeric representation of the year, 4 digits
y Last two digits of the year
a am or pm
A AM or PM
g 12-hour format of an hour without leading zeros
G 24-hour format of an hour without leading zeros
h 12-hour format of an hour with leading zeros
H 24-hour format of an hour with leading zeros
i Minutes with leading zeros
s Seconds with leading zero
T abbreviation for timezone, like CEST
v milliseconds as three digits
e Timezone identifier (Olson name), like Europe/Berlin
O Difference to Greenwich time (GMT) in hours and minutes written together, like +0200. Here a positive offset means east of UTC.
P Same as O but with a colon between hours and minutes, like +02:00
Z Timezone offset in seconds. West of UTC is negative, east of UTC is positive.
z The day of the year (starting from 0)
W ISO-8601 week number. See right below for explanation link.
X ISO-8601 year for year-week notation as four digit year. Warning: Not guaranteed to be same as current year, may be off by one at start or end of year. See here
B One-letter military code for the timezone, or ? if the offset is not a whole number of hours.
\ Not printed, but escapes the following character, meaning it will not be replaced. But inserting a backslash in the string means you have to supply two backslashes \\ to be interpreted as one.
~ (tilde) Same as backslash above, except easier to insert in the string. Example: ~t~h~e will print the word the in the string. Letters should be escaped even if they are not on the list because they may be replaced in future versions.

So as an example: UTC.dateTime("l ~t~h~e jS ~o~f F Y, g:i A") yields date and time in this format: Saturday the 25th of August 2018, 2:23 PM.

 

Built-in date and time formats

There are built-in values to specify some standard date and time formats. For example: UTC.dateTIme(RSS) (without quotes around RSS) returns something like Sat, 25 Aug 2018 14:23:45 +0000. Here's a list of all these built in format abbreviations.

name formatted date and time
ATOM 2018-08-25T14:23:45+00:00
COOKIE Saturday, 25-Aug-2018 14:23:45 UTC
ISO8601 2018-08-25T14:23:45+0000
RFC822 Sat, 25 Aug 18 14:23:45 +0000
RFC850 Saturday, 25-Aug-18 14:23:45 UTC
RFC1036 Sat, 25 Aug 18 14:23:45 +0000
RFC1123 Sat, 25 Aug 2018 14:23:45 +0000
RFC2822 Sat, 25 Aug 2018 14:23:45 +0000
RFC3339 2018-08-25T14:23:45+00:00
RFC3339_EXT 2018-08-25T14:23:45.846+00:00
RSS Sat, 25 Aug 2018 14:23:45 +0000
W3C 2018-08-25T14:23:45+00:00
ISO8601_YWD 2018-W34-5

 

Time and date as numbers

time_t now()    — Assumes default timezone if no timezone is prefixed

Returns the current time in seconds since midnight Jan 1st 1970 in the timezone specified.

uint8_t hour(TIME)
uint8_t hourFormat12(TIME)
uint8_t minute(TIME)
uint8_t second(TIME)
uint16_t ms(TIME)
uint8_t day(TIME)
uint8_t weekday(TIME)
uint8_t month(TIME)
uint16_t year(TIME);

These functions return the various elements of date or time for right now (no arguments) or for a given time in seconds sinds 1970. weekday returns a number starting with 1 for Sunday. hourFormat12 does hours from 1 to 12.

If you want to compare you can use compiler defines in all capital letters for names of days and months, like:

if (weekday() == TUESDAY) Serial.print("Tuesday!!");
if (month() == FEBRUARY && day() == 14) Serial.print("Valentine's day!");

 

bool isAM(TIME)    — Both assume default timezone if no timezone is prefixed
bool isPM(TIME)

These will tell if it is before or after noon for a given TIME, return true or false.

 

uint16_t dayOfYear(TIME)    — Assumes default timezone if no timezone is prefixed

Returns how many days have passed in the year. January 1st returns 0,

 

weekISO and yearISO

uint8_t weekISO(TIME)
uint16_t yearISO(TIME)    — Both assume default timezone if no timezone is prefixed

These functions return the ISO-8601 Year-week notation year and week number. Note that the year returned here can differ one from the current year at the first or last days or the year. ISO-8601 defines the first year of the week as the first week that has a Thursday in it. Meaning the start of the ISO-year can be a few days earlier (in December) or a few days later (in January).

 

militaryTZ

String militaryTZ(TIME)    — Assumes default timezone if no timezone is prefixed

Returns the one-letter military code for the timezone. See here for details. If the offset for the current timezone is not a whole number of hours, "?" is returned.

 

secondChanged and minuteChanged

bool secondChanged()

bool minuteChanged()

You might have code that put the time on a display in some really nice-looking format, using dateTime. The main loop wants to keep the time updated, but not every time the main loop runs, because it would cause the display to flicker. The classic solution for this is to store the time, recreate the string every time and compare to see if it changed. With secondChanged and minuteChanged you can just write something like:

if (minuteChanged()) WriteToSomeDisplay(UTC.dateTime("H:i"));

 

Note that this uses a single variable internally to store when the time was last accessed, so your code can only poll this in one place.

names of days and months

String dayStr(const uint8_t day)

String dayShortStr(const uint8_t day)

String MonthStr(const uint8_t month)

String MonthShortStr(const uint8_t month)

These functions will take a numeric argument and convert it to the name of the day or the name of the months. These functions do not tell you the current day or month, they just convert the number 1 to Sunday, Sun, January or Jan respectively. They are here to be compatible with the classic Time library. The dateTime function can provide all sorts of strings and is much more flexible.

 

different languages

If you edit the ezTime.h file in the library directory and set the EZTIME_LANGUAGE define to NL or DE, you will get the names of the months and days in Dutch or German respectively. The functions that return these names are separated out in files in the src/lang directory, the files there will show you what languages are currently supported. If you add a file in this directory you will add a language, it is that easy. Please submit the files you make via a pull request so others can use ezTime in their own language too.

 

Events

events

void events()

This is what your loop functions should call if they want events executed. This includes user-set events (see below) and the NTP updates that ezTime does periodically. events() also calls the Arduino function yield(), so you do not need to call that anymore (but once more doesn't hurt).

 

setEvent

uint8_t setEvent(void (*function)(), TIME)    — Both assume default timezone if no timezone is prefixed

uint8_t setEvent(void (*function)(), uint8_t hr, uint8_t min, uint8_t sec,
          uint8_t day, uint8_t mnth, uint16_t yr)

With ezTime, you can set your own events to run at a specified time. Simply run setEvent specifying the name of the function you would like to call (without the brackets) and a time you would like to call it. The first time events runs and notices that it is at or after the time you specified it will run and then delete the event. If you want an event to recur, simply set a new event in the function that gets called. You can have a maximum of 8 events by default (easily changed by changing MAX_EVENTS in ezTime.h). ezTime uses one event internally to trigger the next NTP update.

setevent returns an 8-bit event handle between 1 and MAX_EVENTS which you can store in a variable and use to delete the event with deleteEvent should your program need to. Zero is returned and the error TOO_MANY_EVENTS set if there are no more free slots for your new event.

 

deleteEvent

void deleteEvent(uint8_t event_handle)

Deletes the event with the handle as returned by setEvent.

void deleteEvent(void (*function)())

Buy you can also call deleteEvent with the name of the function (again without the brackets) to delete all events that would have executed that function.

 

Setting date and time manually

setTime

void setTime(time_t t, uint16_t ms = 0)    — Both assume default timezone if no timezone is prefixed

void setTime(uint8_t hr, uint8_t min, uint8_t sec,
          uint8_t day, uint8_t mnth, uint16_t yr)

setTime pretty much does what it says on the package: it sets the time to the time specified, either as separate elements or as a time_t value in seconds since Jan 1st 1970. If you have another source of time — say, a GPS receiver — you can use setTime to set the time in the UTC timezone. Or you can set the local time in any other timezone you have set up and ezTime will set its internal offset to the corresponding time in UTC so all timezones stay at the correct time.

It's important to realise however that NTP updates will still become due and when they do time will be set to the time returned by the NTP server. If you do not want that, you can turn off NTP updates with setInterval(). If you do not use NTP updates at all and do not use the network lookups for timezone information either, you can compile ezTime with no network support by commenting out #define EZTIME_NETWORK_ENABLE in the ezTime.h file, creating a smaller library.

Alternate sources of time

If your time source is not NTP, the way to update time is to create a user function that gets the time from somewhere and then sets the clock with setTime and then schedules the next time it synchronises the clock with setEvent. This way you have full flexibility: you can schedule the next update sooner if this update fails, for instance. Remember to turn off NTP updates if you want your new time to stick.

Working with time values

breakTime

void breakTime(time_t time, tmElements_t &tm)

If you create a tmElements_t structure and pass it to breakTime, it will be filled with the various numeric elements of the time value specified. tmElements_t looks as follows:

typedef struct  {
	uint8_t Second;
	uint8_t Minute;
	uint8_t Hour;
	uint8_t Wday;   // day of week, sunday is day 1
	uint8_t Day;
	uint8_t Month;
	uint8_t Year;   // offset from 1970;
} tmElements_t;

Meaning this code would print the hour:

tmElements_t tm;
breakTime(UTC.now(), tm);
Serial.print(tm.Hour);

But Serial.println(UTC.hour()) also works and is much simpler. breakTime is used internally and is a part of the original Time library, so it is available for you to use. Mind that the year is a single byte value, years since 1970.

 

makeTime

time_t makeTime(tmElements_t &tm);

This does the opposite of breakTime: it takes a tmElements_t structure and turns it into a time_t value in seconds since Jan 1st 1970.

time_t makeTime(uint8_t hour, uint8_t minute, uint8_t second,
          uint8_t day, uint8_t month, int16_t year);

This version takes the various numeric elements as arguments. Note that you can pass the year both as years since 1970 and as full four digit years.

 

makeOrdinalTime

time_t makeOrdinalTime(uint8_t hour, uint8_t minute, uint8_t second,
          uint8_t ordinal, uint8_t wday, uint8_t month, int16_t year);

With makeOrdinalTime you can get the time_t value for a date written as "the second Tuesday in March". The ordinal value is 1 for first, 2 for second, 3 for third, 4 for fourth and either 5 or 0 for the last of that weekday in the month. wday is weekdays starting with Sunday as 1. You can use the names of ordinals, months and weekdays in all caps as they are compiler defines. So the following would find the time_t value for midnight at the start of the first Thursday of the year in variable year.

makeOrdinalTime(0, 0, 0, FIRST, THURSDAY, JANUARY, year)

This is actually a fragment of ezTime's own code, as it can print ISO week numbers and the first ISO week in a year is defined as the week that has the first Thursday in it.

 

compileTime

time_t compileTime(String compile_date = __DATE__, String compile_time = __TIME__);

You can ignore the arguments above and just say compileTime(). Returns the time value for when you compiled your sketch. You can check out the "NoNetwork" example with this library to see it in use: it makes your Arduino pretend to know what time it is.

 

tzTime

time_t tzTime(TIME)    — Both forms MUST be prefixed with name of a timezone

This is the internal workhorse function that converts time_t in UTC to time_t in a timezone or vice versa. It is used by almost all the functions that apply to a timezone, and it takes TIME — meaning nothing for "right now", or a time_t value and an optional argument to specify whether that is LOCAL_TIME or UTC_TIME, and then it will convert to the opposite. TIME_NOW and LAST_READ are always output as time_t in that timezone.

time_t tzTime(time_t t, ezLocalOrUTC_t local_or_utc, String &tzname, bool &is_dst, int16_t &offset)

In this second form you have to supply all arguments, and it will fill your tzname, is_dst and offset variables with the appropriate values, the offset is in minutes west of UTC. Note that there are easier functions for you to get this information: getTimezoneName, isDST and getOffset respectively. If your code calls all three in a tight loop you might consider using tzTime instead as the other functions each do the whole parsing using tzTime, so you would be calling it three times and it does quite a bit.

 

Various functions

These functions are available for you to use because ezTime needed them internally, so they come at no extra cost, so to speak.

zeropad

String zeropad(uint32_t number, uint8_t length);

Pads number with zeroes to the left until the resulting string is length places long.

 

Errors and debug information

setDebug

void setDebug(ezDebugLevel_t level)
void setDebug(ezDebugLevel_t level, Print &device)

level sets the level of detail at which ezTime outputs messages on the serial port. Can be set to one of:

level effect
NONE ezTime does not output anything on the serial port
ERROR ezTime will show when errors occur. Note that these may be transient errors that ezTime recovers from, such as NTP timeouts.
INFO Essentially shows you what ezTime is doing in the background. Includes messages about NTP updates, initialising timezones, etc etc.
DEBUG Detailed debugging information unlikely to be of much use unless you are trying to get to the bottom of certain internal behaviour of ezTime.

Note: you can specify which level of debug information would be compiled into the library. This is especially significant for AVR Arduino users that need to limit the flash and RAM footprint of ezTtime. See the "Smaller footprint, AVR Arduinos" chapter further down. device is optional and can specify a device to receive the debug messages. This defaults to the Hardwareserial object named Serial but can be any device that has inherited from the Print class. Don't worry if you don't understand that: it means you can specify not only serial ports, but also a handle to a file you have opened on the SD card as well as a lot of LCD screen devices. For instance, on my M5Stack device I can — after #include <M5Stack.h> and m5.begin() — do: setDebug(INFO, m5.lcd)

You cannot send debug information to multiple devices at the same time.

 

error

ezError_t error(bool reset = false);

A number of functions in ezTime are booleans, meaning they return true or false as their return value, where false means some error occurred. error will return an ezError_t enumeration, something like NO_NETWORK (obvious) or LOCKED_TO_UTC (when you try to load some new timezone info to the UTC object). You can test for these specific errors and this document will mention which errors might happen in what functions.

When you call error(true), it will also reset the error to OK, so you can make sure no new errors happened after a certain point.

 

errorString

String errorString(ezError_t err = LAST_ERROR);

This will give you a string representation of the error specified. The pseudo-error LAST_ERROR, which is the default, will give you the textual representation of the last error. This will not reset the last error stored.

 

Compatibility with Arduino Time library

The classic Arduino time library has a lot of functions and defines that end up in the root namespace, meaning you can just run hour() instead of someTZ.hour(). These functions are supported by ezTime and will act as if they are prefixed with the defaultTZ. This is UTC by default, but you can make any timezone the default by writing someTZ.setDefault();

If you do not wish to have these functions in your namespace, you can comment out #define ARDUINO_TIMELIB_COMPATIBILITY in ezTime.h. New code depending on ezTime should probably explicitly state the timezone, especially in code with multiple timezones.

 

Smaller footprint, AVR Arduinos

This library compiles on an Arduino Uno with an Ethernet shield. However, it will use up almost all of the flash on that, which is fine if you were making a date and time display anyway. But if your code is bigger than that, you will want to make it smaller. By uncommenting #define EZTIME_MAX_DEBUGLEVEL_NONE in ezTime.h you get no debugging information and no textual errors, which saves a couple of kilobytes. If you do not use networking, you should also comment out #define EZTIME_NETWORK_ENABLE, that will save a ton of space: not just in ezTime but also because the networking library does not get loaded.

 

2036 and 2038

The NTP timestamps used here run until the 7th of February 2036. NTP itself has 128 bits of time precision, I haven't looked into it much. Didn't have to, because just a little later, on the 19th of January 2038, the time_t 32 bit signed integer overflows. This is 20 years from today, in 2018. The Arduino world, if it still exists around then, will have come together around some solution that probably involves 64-bit time like in many operating systems of 2018. If you use this library in your nuclear generating station (NOOOOO!), make sure you're not around when these timers wrap around.

Should you be the one doing maintenance on this in some far-ish future: For ezTime I created another overflowing counter: the cache age for the timezone information is written as a single unsigned byte in months after January 2018, so that could theoretically cause problems in 2039, but I think everything will just roll over and use 2039 as the new anchor date.

 

Inspiration

Please do tell me if you made something cool and I'll include it here.

Arduino clock

Github user BugerDread made an Arduino clock using ESP8266, ezTIME and MAX7219 LED display modules. It's pretty:

 

ezTime on various Arduino platforms

If your Arduino has anything like normal Arduino networking, we can make it work. In some cases it might take an exception in the code if it needs a special header file or so, but no big deal. And if it has EEPROM.h or Preferences.h to store things in flash, we can make the cache work too. Please open an issue on github to tell me if something doesn't work. Here's a list of boards that ezTime has been tested on.

DSD Tech ESP8266

ezTime 0.7.2 ran fine. Board: Generic ESP8266, Reset Method: nodemcu. Don't forget to replace #include <WiFi.h> with #include <ESP8266WiFi.h> in your sketch.

 

Teensy 3.2

ezTime 0.7.2 ran fine. Did not test networking, so compiled with #define EZTIME_NETWORK_ENABLE commented out, used NoNetwork example.

 

Arduino Uno R3 (clone) with Ethernet Shield W5100

ezTime 0.7.4 ran, the EthernetShield example leaves some 5k of flash:

Sketch uses 26536 bytes (82%) of program storage space. Maximum is 32256 bytes.
Global variables use 733 bytes (35%) of dynamic memory, leaving 1315 bytes for local variables. Maximum is 2048 bytes.

By setting #define EZTIME_MAX_DEBUGLEVEL_NONE in eztime.h we can free up some more flash:

Sketch uses 23870 bytes (74%) of program storage space. Maximum is 32256 bytes.
Global variables use 729 bytes (35%) of dynamic memory, leaving 1319 bytes for local variables. Maximum is 2048 bytes.

ezTime and NoNetwork example without #define EZTIME_NETWORK_ENABLE (if you have another time source and are willing to put in the Posix information for timezones yourself.):

Sketch uses 11558 bytes (35%) of program storage space. Maximum is 32256 bytes.
Global variables use 354 bytes (17%) of dynamic memory, leaving 1694 bytes for local variables. Maximum is 2048 bytes.

 

M5Stack (ESP32)

ezTime 0.7.2 ran fine.

 

Arduino Micro

USB took a while to be recognized on my Mac, and then I took a while to discover that this is one that needs the

while (!Serial) { ; }		// wait for serial port to connect. Needed for native USB port only

line that you see in many sketches. But then ezTime 0.7.2 ran fine using NoNetwork example.

 

Arduino Due

ezTime 0.7.2 runs fine (No networking on board, so tested with NoNetwork example). If you use the native USB port it also needs the while (!Serial) { ; } and you need to change all the Serial. to SerialUSB. in your sketch. Note that if you want debugging info you can pass the SerialUSB port as the second argument to setDebug.

 

Arduino MKR1000

ezTime 0.7.2 worked, eventually. But I didn't like this one. Getting online is difficult. Install Wifi101 library from the library manager and make sure to start your sketch with:

#include <SPI.h>
#include <WiFi101.h>
  • Test sketch complained about WiFi firmware / driver mismatch. Couldn't get the firmware update tool to work, but WiFi worked anyway.
  • The WiFi object does not have the isConnected method so I wrote some detection for ezTime to skip the NO_NETWORK checks. This means that if you have debug level at ERROR or higher, waitForSync will throw some NTP TIMEOUT errors (and then continue just fine after wifi is online).
  • It doesn't have EEPROM.h or Preferences.h but some proprietary FlashStorage.h. So no cache for the moment. (Turn off both cache defines at the beginning of ezTime.h. I'll write it if the third person wants it.

 

Arduino Nano

ezTime 0.7.2 runs fine (No networking on board, so tested with NoNetwork example)

 

Table of Contents

 

Function reference

function returns arguments TZ prefix network cache
breakTime void time_t time, tmElements_t &tm no no no
clearCache void bool delete_section = false yes yes NVS
clearCache void yes yes EEPROM
compileTime time_t String compile_date = __DATE__, String compile_time = __TIME__ no no no
dateTime String TIME, String format = DEFAULT_TIMEFORMAT optional no no
day uint8_t TIME optional no no
dayOfYear uint16_t TIME optional no no
dayShortStr String uint8_t day no no no
dayStr String uint8_t day no no no
deleteEvent void uint8_t event_handle no no no
deleteEvent void void (*function)(``) no no no
error ezError_t bool reset = false no no no
errorString String ezError_t err = LAST_ERROR no no no
events void no no no
getOffset int16_t TIME optional no no
function returns arguments TZ prefix network cache
getOlson String optional yes yes
getPosix String yes no no
getTimezoneName String TIME optional no no
hour uint8_t TIME optional no no
hourFormat12 uint8_t TIME optional no no
isAM bool TIME optional no no
isDST bool TIME optional no no
isPM bool TIME optional no no
**lastNtpUpdateTime time_t no yes no
makeOrdinalTime time_t uint8_t hour, uint8_t minute, uint8_t second, uint8_t ordinal, uint8_t wday, uint8_t month, uint16_t year no no no
makeTime time_t tmElements_t &tm no no no
makeTime time_t uint8_t hour, uint8_t minute, uint8_t second, uint8_t day, uint8_t month, uint16_t year no no no
militaryTZ String TIME optional no no
minute uint8_t TIME optional no no
minuteChanged bool no no no
month uint8_t TIME optional no no
function returns arguments TZ prefix network cache
monthShortStr String uint8_t month no no no
monthStr String uint8_t month no no no
ms uint16_t TIME_NOW or LAST_READ optional no no
now time_t optional no no
queryNTP bool String server, time_t &t, unsigned long &measured_at no yes no
second uint8_t TIME optional no no
secondChanged bool no no no
setCache bool String name, String key yes yes NVS
setCache bool int16_t address yes yes EEPROM
setDebug void ezDebugLevel_t level no no no
setDebug void ezDebugLevel_t level, Print &device no no no
setDefault void yes no no
setEvent uint8_t void (*function)(), TIME optional no no
setEvent uint8_t void (*function)(), uint8_t hr, uint8_t min, uint8_t sec, uint8_t day, uint8_t mnth, uint16_t yr optional no no
setInterval void uint16_t seconds = 0 yes no
function returns arguments TZ prefix network cache
setLocation bool String location = "" yes yes no
setPosix bool String posix yes yes no
setServer void String ntp_server = NTP_SERVER no yes no
setTime void time_t t, uint16_t ms = 0 optional no no
setTime void uint8_t hr, uint8_t min, uint8_t sec, uint8_t day, uint8_t mnth, uint16_t yr optional no no
timeStatus timeStatus_t no no no
tzTime time_t TIME yes no no
tzTime time_t TIME, String &tzname, bool &is_dst, int16_t &offset yes no no
updateNTP void no yes no
waitForSync bool uint16_t timeout = 0 no yes no
weekISO uint8_t TIME optional no no
weekday uint8_t TIME optional no no
year uint16_t TIME optional no no
yearISO uint16_t TIME optional no no
zeropad String uint32_t number, uint8_t length no no no

eztime's People

Contributors

alberto-im avatar bugerdread avatar chinswain avatar clydde avatar durobot avatar koter84 avatar mike-s123 avatar per1234 avatar ropg avatar t1m0thyj avatar wayfarerbasta 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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

eztime's Issues

error connecting to pool.ntp.org

hi, trying to get this to work but everthing i have tried leaves me with this.

ezTime debug level set to INFO
Waiting for WiFi ... Querying pool.ntp.org ... ERROR: No network
connected
Waiting for time sync
Querying pool.ntp.org ... ERROR: Timeout
Querying pool.ntp.org ... ERROR: Timeout

SetLocation for "ie", "uk" and "pt" does not work

Using the timezones examples as base, none of the above return the correct time. They display as UTC, when they should be now UTC + 1

When you enable info serial prints, you see that none of them return a response for the timezone lookup. Setting the country code to "de" works as expected (UTC +2) and returns a response to the timezone lookup.

Setting the timezone in the olson format works as expected ("Europe/Dublin" returns UTC +1)

eztime does not use BST correctly

Today 26th March the time displayed using the ezTime library is one hour ahead for timezone United Kingdom, unfortunately BST does not start in the UK until the last Sunday in March. Last year it was 25th March, this year it is 29th March and next year it will be different again. Is eztTime designed to compensate for this change in the starting (and also ending) dates for BST?

User set events not triggering

First, love the library! After reading the docs thoroughly, I have a pretty good handle on how to use everything.

However, the events set by me are not triggering. I've tried a lot

  • setting events to UTS vs myTZ
  • Passing a time_t object vs hr min sec arguments
  • Praying
  • anything else I could think of before posting here

I am using a heltec automation wifi kit 8 esp8266 w/ integrated 128 x 32 px oled display.

In the script, I know that loop keeps looping, because there is a clock that shows the current time on the board's display. Also with the debug set to INFO, I can see the NTP syncs regularly. So events() is being called.

When I set Debug level DEBUG, it does not show my events being created.

The event is supposed to trigger a function that flips a pin and changes the screen. It also sends some data along the serial line to show that the event triggered.

When I run the code below, I get the following, and then nothing when the event should trigger (I should see something on the serial monitor).

Any thoughts?

Serial Output

Serial Connected

WiFi Connected

Waiting for WiFi ... Querying pool.ntp.org ... ERROR: No network
connected
Waiting for time sync
Querying pool.ntp.org ... success (round trip 106 ms)
Received time: Friday, 10-May-19 19:14:21.456 UTC
Time is in sync
Time Synced

Timezone lookup for: America/New_York ... (round-trip 123 ms) success.
Olson: America/New_York
Posix: EST5EDT,M3.2.0,M11.1.0
Friday, 10-May-2019 15:14:21 EDT Timezone Set

Friday, 10-May-2019 15:14:21 EDT Setting the 05:00:00 event
Friday, 10-May-2019 15:14:21 EDT Event set for 11-5-2019 05:00:00

Friday, 10-May-2019 15:14:21 EDT Setting the 10:00:00 event
Friday, 10-May-2019 15:14:21 EDT Event set for 11-5-2019 10:00:00

Friday, 10-May-2019 15:14:21 EDT Setting the 15:16:00 event
Friday, 10-May-2019 15:14:21 EDT Event set for 10-5-2019 15:16:00

Code:

/*
 * A script to automate the actuation of a pin (Normally HIGH, Actuated LOW) for a set duration
 * 
 * The board used is the Heltec WiFi kit 8 (I got mine on amazon)
 * Note - the pinout diagram is all wrong on that particular board.
 * Like, really, really wrong.
 * My pin 12 is "D6"
 * 
 * This script heavily utilizes the ezTime library for time keeping and event setting, 
 * So a big thanks to ropg for such a great library to use!
 * 
 * This script is simplified to show some issues I am having with events
 * 
 * By Andrew Shaw
 */

#include <ezTime.h>
#include <ESP8266WiFi.h>
#include "SSD1306Wire.h"
//#include "config.h"
#include "images.h"
#include "work_config.h"

//Event times, in global scope
uint8_t event1_hour = 5; // 5am
uint8_t event1_min = 0;
uint8_t event2_hour = 10;
uint8_t event2_min = 0;
uint8_t event3_hour = 15; // 3pm
uint8_t event3_min = 16;
uint8_t event_duration = 18000; // Event duration, seconds

//Define which pin the event pin is attached to
uint8_t event_pin = EVENT_PIN;

//Setup wifi credentials from config file.
char ssid[] = WIFI_SSID;
const char password[] = WIFI_PW;

//clearing the display, not going to use it for this sample.
SSD1306Wire display(0x3c, 4, 5, GEOMETRY_128_32);

//Create Timezone from config file, in global scope
Timezone myTZ;
char timezone_name[] = TIMEZONE_NAME;

void setup() {
  setDebug(INFO);
  
  pinMode(event_pin, OUTPUT);
  digitalWrite(event_pin, HIGH);

  Serial.begin(115200);
  while (!Serial) { ; }
  Serial.println("Serial Connected\n");
  
  //Just clearing the display
  pinMode(16, OUTPUT);
  digitalWrite(16, LOW);
  delay(50);
  digitalWrite(16, HIGH);
  display.init();
  display.clear();

  //Connect to WiFi
  WiFi.begin (ssid, password);
  Serial.println("WiFi Connected\n");

  //Sync with NTP Server
  waitForSync();
  Serial.println("Time Synced\n");

  //Set Timezone
  myTZ.setLocation(timezone_name);
  myTZ.setDefault();
  Serial.print(myTZ.dateTime() + "     ");
  Serial.println("Timezone Set\n\n\n");

  //Setting watering events to trigger for first time
  make_next_event(event1_hour, event1_min, 0);
  make_next_event(event2_hour, event2_min, 0);
  make_next_event(event3_hour, event3_min, 0);
}

void idleDisplay() {

  //This is where I have code for the oled display.  not important.

}

void event_cycle(uint8_t hr, uint8_t mn, uint8_t sec){
  Serial.print(myTZ.dateTime() + "     ");
  Serial.println("Executing the " + String(hr) + ":" + String(mn) + ":" + String(sec) + " event");
  
  uint8_t time_left = event_duration; // This will be used to end the event.

  digitalWrite(event_pin, LOW); //Turn on the relay
  
  while (time_left > 0) {
    //delay(1000);
    //Or
    //secondChanged is a boolean value, and is true when the second changes, 
    //but then goes back to false the next time you evaluate it.
    while (!secondChanged()) {
      delay(1);
    }
    time_left--; //decrement time left by one second
  }
  
  digitalWrite(event_pin, HIGH); //Turn off the relay
  
  Serial.print(myTZ.dateTime() + "     ");
  Serial.println("Concluding the " + String(hr) + ":" + String(mn) + ":" + String(sec) + " event");
  
  make_next_event(hr, mn, sec);
  
}

void make_next_event(uint8_t hr, uint8_t mn, uint8_t sec) {
  //makeTime(hour, minute, second, day, month year)
  time_t set_time = makeTime(hr, mn, sec, day(), month(), year());

  if (myTZ.now() >= set_time) { // See if event set time has already elapsed
    set_time += 86400; // 86400 seconds in 1 day
  }

  Serial.print(myTZ.dateTime() + "     ");
  Serial.println("  Setting the " + zeropad(hr, 2) + ":" + zeropad(mn, 2) + ":" + zeropad(sec, 2) + " event");

  //setEvent(function, time_t object)
  uint8_t setEvent(void event_cycle(uint8_t hr, uint8_t mn, uint8_t sec), time_t set_time);
 
  Serial.print(myTZ.dateTime() + "     ");
  Serial.println("  Event set for " + String(day(set_time)) + "-" + String(month(set_time)) + "-" + String(year(set_time)) + " " + zeropad(hr, 2) + ":" + zeropad(mn, 2) + ":" + zeropad(sec, 2) + "\n");
}

void loop() {
  //This is the events for the eztime library
  //Needed to continually sync with NTP and trigger events, such as the watering events and the secondChanged() function
  events();

  //This function happens every time the internal clock's second changes.
  //Unless an event is occuring...
  if (secondChanged()) {
    idleDisplay();

  }
  
  delay(5);

}

setting time manually when there is no internet

This library is really helpful and great.

I have a master controller in my project which connects to the internet so ezTime works fine with it
however, in my project there are other controllers that doesn't have an internet access, yet depends on the clock for some operations.
What I want to do is, let the controllers connect to the Hub and get some data to be used to set ezTime manually and offline to calculate the time. I can't seem to find a clear answer in the documentation.\

It would be also useful if there is a function in ezTime to return that last pinged Unix Time Stamp may be to pass it to other controllers to calulate time manually without having to sync with ntp server

Two global timezones?

Is it possible to have multiple global scoped timezones independent of each other?

I have the following code:
'

#include 
#include 
#define CONF_TIMEZONE "Europe/Stockholm"
const char *ssid     = "ssid";
const char *password = "pass";
Timezone tz;
Timezone tempTime;
void setup() {
    Serial.begin(115200);
    Serial.println("Serial run");
    WiFi.begin(ssid, password);
    while( WiFi.status() != WL_CONNECTED ){
        delay( 500 );
        Serial.print ( "." );
    }
    waitForSync();
    tempTime.setLocation(CONF_TIMEZONE );
    tz.setLocation(CONF_TIMEZONE );
    tz.setDefault();
    
    Serial.println("Time: "+tz.dateTime());
	tempTime.setTime(
        12, // H 
        0,  // M
        0,  // S
        1,1,2018
    );
    Serial.println("tz after setting tempTime");
    Serial.println(tz.dateTime());
}

void loop(){ delay(1000); }

After setting time on tempTime, it also changes the time of tz.

The reason is I want to be able to get the unix timestamp a day ahead of current time, while maintaining the current time to output onto a display every second.

I tried creating a new Timezone tempTime, when doing the comparison, but doing that added a delay of more than 1 second.

Please issue new release.

I submitted a couple of (accepted) PRs a while back, the main one fixed some summertime issues. Please create a new release. That will fix issues for others, and I won't have to keep a private copy.

Thanks.

Timezone::dateTime(time_t, ...) shows wrong milliseconds value

  • When using date and time formatting of an argument-passed timestamp, Timezone::dateTime(time_t, ...) would display last read milliseconds instead of zero for the v placeholder.
  • And an option to pass milliseconds along with the timestamp would be very handy. Probably with another overloaded variant of Timezone::dateTime(...).

Although ms-precision datetime formatting is still possible with some string gluing code and maintaining two time formats for both current and variable-based time formatting, it's a pity not having it in such a great library. :)

timeStatus timeNeedsSync never seted

Thanks for you work!
I think timeNeedsSync status never can be set. I did not find in the code timeNeedsSync and if I disable connection I always see status '2' (timeSet).
Maybe I'm wrong. Sorry for my bad english

get epoch in millis

What's the correct way to get an epoch time from millis? (as javascript/java System.currentTimeMillis())

i am not 100% sure that it's now()*1000+ms() so i'll like to get confirmation :)

tnx

Changing to DST at wrong time.

Just trying to test out code before a real summertime change.

So, I'm doing testing by setting the TZ string to change to summertime a few minutes in the future, expecting to watch the change. But, when set slightly in the future, it changes immediately. It's not changing at the correct local time.

Right now, it's Monday, 04-Feb-2019, 23:something. (date is M2.1.1, in "Olson speak")

e.g. With the string set to "EST5EDT,M2.1.2/4:13,M11.1.0" (summertime begins at 04:13 tomorrow morning), it actually changes to DST at 23:08 local standard time, which is 5 minutes before when it should change if it were simply using UTC instead of local time! 100% repeatable, I can switch back and forth. If I set the TZ string to 5 hours and 4 minutes ahead of local time, it will change to DST. If I set it to 5 hours and 6 minutes ahead of local time, it will change to standard time.

Weird. I'm not a coder, I only play one on the Internet enough to be dangerous. But, that behavior would make sense if in the relevant routine, instead of subtracting 5 hours (the offset from UTC) from UTC time, you're subtracting 5 minutes (or something like that, my brain is starting to hurt).

Possible to use standard NTP servers in your library

Dear Sir,
first of all congratulation for your fine work, by making this library.
My question is: Do you support standard NTP servers in your library? For example, I live in Greece, can I use NTP server like: gr.pool.ntp.org ?
Please explain it in details because I am not programmer.

Thanks and Best Regards,
Mike Kranidis

wrong day for DST change

Hi!

today I detect, that time from ezTime library is invalid. After some investigation I found, that problem is that ezTime thing that I need CET time, but today is last day with CEST
I am set Olsen format "Europe/Prague"
It is converted to POSIX correctly : "CET-1CEST,M3.5.0,M10.5.0/3"
This is correct. Problem is that today (27-Oct-2018) is last weekend on October but not .0 ( =Sunday)
ezTime show Time: Saturday, 27-Oct-2018 12:08:32 CET

Any idea?

Timezone not applying to makeTime

Is this expected behavior? I'm sure I'm doing something silly but If I set up a time_t element it prints without timezone adjustment.

The default timezone works, deconstructing t shows the hour as 21 and the epoch time is correct.

#include <ezTime.h>
#include <WiFi.h>
Timezone myTZ;

void setup() {
  Serial.begin(115200);
  WiFi.begin("", "");
  waitForSync();

  myTZ.setLocation(F("gb"));
  myTZ.setDefault();
  Serial.print("TimeZone: "); Serial.println(dateTime());
  Serial.print("epoch myTZ : "); Serial.println(myTZ.now());
  
  time_t t = 0;
  t = makeTime(21, 45, 00, myTZ.day() , myTZ.month(), myTZ.year());
  Serial.print("Test: "); Serial.println(myTZ.dateTime(t));

  Serial.print("epoch Test : "); Serial.println(t);

  tmElements_t tmTest;
  breakTime(t, tmTest);
  Serial.print("Hour: "); Serial.println(tmTest.Hour);
}

void loop() {

}
TimeZone: Friday, 26-Oct-2018 21:45:27 BST
epoch myTZ : 1540590327

Test: Friday, 26-Oct-2018 20:45:00 BST
epoch Test : 1540590300

Hour: 21

Problem with using minuteChanged and secondChanged together

Hi

I am writing a program to display he time on an LED matrix. I used secondChanged to blink a colon between the hours and minutes and also manually tracked when the minute changed in order to update the time on the display. That worked fine.

I figured I could simplify things by using minuteChanged to trigger a screen refresh rather than tracking when the minute changed. However, when I use both minuteChanged and secondChanged together I find that secondChanged is being triggered approx 100,000 times per second rather than just once per second.

My questions are:

  1. should the combination of these two functions work as I expect, and there is a bug occurring?
  2. these two functions not designed to work together in the same program?

Thanks
aussieW

Timezone definition incorrect

Hi,

Awesome library, however, this week, a bug was revealed in timezone config.
In the README.md, and also in your lookup server, it is stated that timezone for Berlin/western eu is:

CET-1CEST,M3.4.0/2,M10.4.0/3

However, the actual definition is 'last sunday of the month'. In march 2019, the month had 5 sundays, so the clock on my night table is off for an hour this week.

According to the spec, '5' means 'last of the month', so I've also took the liberty to update the definition in my code to

CET-1CEST,M3.5.0/2,M10.5.0/3

Can you update README.md and probably your server accordingly?

lastNtpUpdateTime() incorrect.

Shortly after things get started and NTP is updated,

myTz.dateTime(RFC850) produces "Wednesday, 10-Apr-2019 10:30:37 EDT"

but

dateTime(lastNtpUpdateTime(),RFC850) produces "Wednesday, 10-Apr-2019 18:29:37 EDT"

Seems to be a sign issue. EDT is UTC-4, and the reported time is off by 8. Or maybe it's got to do with dateTime(), not lastNtpUpdateTime().

UTC.dateTime(lastNtpUpdateTime(),RFC850) produces the expected result.

Timezones example - timeouts

Hallo Ropg,
thank you for ezTime library!

Right now Im testing it on ESP8266 but I found an issue with Timezones example.

If I change this example to be abe to run on ESP (WiFi.h -> ESP8266WiFi.h, set SSID and PASS), I get following output (debug enabled):

ezTime debug level set to INFO
Waiting for WiFi ... Querying pool.ntp.org ... ERROR: No network
connected
Waiting for time sync
Querying pool.ntp.org ... success (round trip 22 ms)
Received time: Thursday, 20-Dec-18 11:41:07.160 UTC
Time is in sync

UTC:             Thursday, 20-Dec-2018 11:41:07 UTC
Timezone lookup for: Pacific/Auckland ... (round-trip 43 ms)  success.
  Olsen: Pacific/Auckland
  Posix: NZST-12NZDT,M9.5.0,M4.1.0/3
New Zealand:     Friday, 21-Dec-2018 00:41:07 NZDT
Timezone lookup for: de ... ERROR: Timeout
Germany:         Friday, 21-Dec-2018 00:41:09 NZDT
Local (GeoIP):   Timezone lookup for: GeoIP ... ERROR: Timeout
Timeout

I always get New Zealand time correctly, Germany (de) timezone results in timeout in about 50% of tries, I never get GeoIP time - always timeout.

I think this is because of DDOS protection on the server you mentioned in readme: "will only respond to the same IP-number once every three seconds to prevent being used in dDoS attacks", but there is no delay in the example and we are calling setLocation 3 times in a row (from the same IP ofc).

Also if the myTZ.setLocation(F("de")) results in timeout, it shows New Zealand time for germany (as in output above), but this is because myTZ.setLocation(F("de")) is not checked if completed successfully as in "GeoIP part". The myTZ.setLocation(F("Pacific/Auckland")) is also not checked if completed successfully, but from my point of view this is not a problem, it demonstrate that you can but you are not required to check setLocation result in your sketch.

It works as expected when I add two delays this way (which confirms its 99% because of the DDoS protection):

#include <ezTime.h>
#include <ESP8266WiFi.h>

void setup() {

	Serial.begin(115200);
	while (!Serial) { ; }		// wait for Serial port to connect. Needed for native USB port only
        Serial.print(F("\nGood morning :-)"));
	WiFi.begin("your-ssid", "your-password");

	// Uncomment the line below to see what it does behind the scenes
	//setDebug(INFO);
	
	waitForSync();

	Serial.println();
	Serial.println("UTC:             " + UTC.dateTime());

	Timezone myTZ;

	// Provide official timezone names
	// https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
	myTZ.setLocation(F("Pacific/Auckland"));
	Serial.print(F("New Zealand:     "));
	Serial.println(myTZ.dateTime());
        
        // wait a little bit to not trigger DDoS protection on server - see readme
        delay(5000);

	// Or country codes for countries that do not span multiple timezones
	myTZ.setLocation(F("de"));
	Serial.print(F("Germany:         "));
	Serial.println(myTZ.dateTime());	

        // wait a little bit to not trigger DDoS protection on server - see readme
        delay(5000);

	// See if local time can be obtained (does not work in countries that span multiple timezones)
	Serial.print(F("Local (GeoIP):   "));
	if (myTZ.setLocation()) {
		Serial.println(myTZ.dateTime());
	} else {
		Serial.println(errorString());
	}
}

void loop() {
	events();
}

I think the same apply to "EthernetShield" example, as it does the same (calling myTZ.setLocation() 3 times without delay), but I have no HW to test it.

Daily Alarm?

Would it be possible to set a daily repeating alarm without specifying the day, month and year?

I'm using Paul's time and timeAlarm libraries plus some hacky time zone adjustments. (https://github.com/PaulStoffregen/TimeAlarms)

 Alarm.alarmRepeat(8,30,0, MorningAlarm);  // 8:30am every day
 Alarm.alarmRepeat(17,45,0,EveningAlarm);  // 5:45pm every day 

// functions to be called when an alarm triggers:
void MorningAlarm(){
  Serial.println("Alarm: - turn lights off");    
}

void EveningAlarm(){
  Serial.println("Alarm: - turn lights on");           
}

I'm currently trying with this - which triggers continuously when the time arrives. How should I be setting up a daily repeating alarm?

#include <ezTime.h>
#include <WiFi.h>
Timezone myTZ;
void setup() {

  Serial.begin(115200);

  WiFi.begin("", "");

  waitForSync();
  Serial.println();
  Serial.println("UTC:             " + UTC.dateTime());


  myTZ.setLocation(F("gb"));
  Serial.print(F("United Kingdom:         "));
  Serial.println(myTZ.dateTime());
  myTZ.setDefault();

  // Set the event to trigger for the first time
  setEvent( mistOneStart, pumpOn() );
  setEvent( mistOneStop, pumpOff() );
}

void loop() {

  events();

}

void mistOneStart() {
  Serial.print(F("Start! "));
  Serial.println(myTZ.dateTime());
  setEvent( mistOneStart, pumpOn() );
}

time_t pumpOn() {
  int8_t d = myTZ.day() ;
  int8_t m = myTZ.month();
  int16_t y = myTZ.year();

  time_t t = 0;
  t = makeTime(1, 04, 0, d, m, y);
  return t;

}

void mistOneStop() {
  Serial.print(F("Stop! "));
  Serial.println(myTZ.dateTime());
  setEvent( mistOneStop, pumpOff() );
}

time_t pumpOff() {
  int8_t d = myTZ.day() ;
  int8_t m = myTZ.month();
  int16_t y = myTZ.year();

  time_t t = 0;
  t = makeTime(1, 04, 30, d, m, y);
  return t;

}


setLocation issue and offset wrong way? (previously: Seem good, but do not work !?)

Hello,

I have this code :

  Timezone myTZ;
  myTZ.setLocation(F("CET"));
  Serial.print(F("CET:\t\t\t"));
  Serial.println(myTZ.dateTime());
  myTZ.setLocation(F("CEST"));
  Serial.print(F("CEST:\t\t\t"));
  Serial.println(myTZ.dateTime());
  myTZ.setLocation(F("UTC"));
  Serial.print(F("UTC:\t\t\t"));
  Serial.println(myTZ.dateTime());
  myTZ.setLocation(F("Europe/London"));
  Serial.print(F("London:\t\t\t"));
  Serial.println(myTZ.dateTime());
  myTZ.setLocation(F("Europe/Paris"));
  Serial.print(F("France:\t\t\t"));
  Serial.println(myTZ.dateTime());
  myTZ.setPosix("CET+2:00");
  Serial.print(F("France apres ofset:\t"));
  Serial.println(myTZ.dateTime());
  Serial.println("Posix zone : " + myTZ.getPosix());
  Serial.println("Nom de la zone : " + myTZ.getTimezoneName());

It's very strange, the result is :

CET:				Friday, 10-May-2019 23:29:09 UTC
CEST:			Friday, 10-May-2019 23:29:11 UTC
UTC:			Friday, 10-May-2019 23:29:13 UTC
London:			Friday, 10-May-2019 23:29:15 UTC
France:			Friday, 10-May-2019 23:29:17 UTC
France apres ofset:	Friday, 10-May-2019 21:29:17 CET
Posix zone : CET+2:00
Nom de la zone : CET

I do not understand why it's the same hour whatever the location i take !?!?

More fun : actually, there is 2 hours offset as we are in summer (only 1 hour in winter) : so why does it send me 21:29 whereas it's 01:29 am ???
Why is it the same hour in Paris and London whereas it's not the same time zone ???

Does someone have an idea ? or what do i make wrong ?
Thank's again,
Thierry

waitForSync is not returning true

Sometimes, after doing a firmware update. waitForSync won't return true. Here is my code.

Timezone US;
...

void setup()
{
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  
  Serial.println("Connecting to Wifi");

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
  Serial.println("Connected to " + String(ssid) + " on address: " + WiFi.localIP().toString());

  while (!waitForSync(3))
  {
   Serial.println("Retrying timeSync");
  }
  Serial.println("Got timeSync");
}

void loop() {}

Incorrect time on WiFi Loss

I've had a few false triggers on setEvent that appear to be due to datetime being incorrect immediately after a WiFi loss and reconnect. On the next update it's corrected (if WiFi is ok) but all of the days event's are triggered.

I'll write a simplified example (with DEBUG level) and post\test tomorrow and leaving it running. I have a timer doing the following every 10 minutes:

 Serial.print("Time: "); Serial.println(myTZ.dateTime());

Output Example 1:

Querying pool.ntp.org ... success (round trip 64 ms)
Received time: Wednesday, 02-Jan-19 18:30:25.098 UTC (internal clock was 33 ms fast)

[0] Heartbeat timeout <-- WiFi Loss and Reconnect
[148] Ready (ping: 31ms).

**Time: Thursday, 21-Feb-2019 10:22:54 GMT**

Querying pool.ntp.org ... success (round trip 55 ms)
Received time: Wednesday, 02-Jan-19 18:31:42.317 UTC (internal clock was 4294973 ms fast)

Time: Wednesday, 02-Jan-2019 18:37:39 GMT

Querying pool.ntp.org ... success (round trip 906 ms)
Received time: Wednesday, 02-Jan-19 18:41:42.331 UTC (internal clock was 425 ms fast)

Output Example 2:

Time: Wednesday, 02-Jan-2019 23:25:20 UTC

[0] Heartbeat timeout <-- WiFi Loss and Reconnect
[148] Ready (ping: 35ms).

**Time: Thursday, 21-Feb-2019 15:16:33 UTC**

Querying pool.ntp.org ... success (round trip 44 ms)
Received time: Wednesday, 02-Jan-19 23:25:21.408 UTC (internal clock was 4294953 ms fast)

Time: Wednesday, 02-Jan-2019 23:25:21 UTC

Clock is set to 2036-02-07 about 7:30AM sometimes by sync

Hallo,

I made simple NTP clock using your ezTime library (https://github.com/BugerDread/esp8266-ezTIME-wifi-clock), but I noticed that it sometimes shows wrong time / date randomly. The wrong time / date is always 2036-02-07 about 7:30 (timezone Europe/Prague). So I made a simple sketch sending actual time and ezTime debug data to serial port which I captured to file.

Here is the testing sketch:

#include <ESP8266WiFi.h>
#include <ezTime.h>

// configuration
static const char ourtimezone[] PROGMEM = "Europe/Prague";  //official timezone names https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
static const char dot[] PROGMEM = ".";
#define wifi_ssid             "MikroTik-043865"                //ssid of your WiFi
#define wifi_pwd              "badik2323"                    //password for your WiFi

Timezone myTZ;

int i = 10;
String buf;

void setup() {
  Serial.begin(115200);
  Serial.println(F("\r\n* * * ESP BOOT * * *"));
  setDebug(INFO);
  
  Serial.print(F("# Connecting to WiFi"));
  WiFi.persistent(false);   //dont want to save wifi credentials into flash - it cause just fash wear every power-on, see https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/generic-class.html#persistent
  WiFi.mode(WIFI_STA);      //we want just Wifi client (station), no AP
  WiFi.begin(wifi_ssid, wifi_pwd);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(FPSTR(dot));
  }
  
  Serial.println(F("\r\n# WiFi connected, waiting for sync"));
  waitForSync();
  Serial.println(F("# Setting timezone"));
  if (myTZ.setLocation(FPSTR(ourtimezone))) {
    Serial.println(F("# Timezone lookup OK"));
  } else {
    Serial.println(F("# Timezone lookup error!"));
  }
  
  Serial.println(F("# Setup finished"));
}

void loop() {
  events();
  
  if (secondChanged()) {
    buf = myTZ.dateTime("# Y-m-d H-i-s");
    if (++i >= 10) {
      Serial.print("\r\n" + buf);
      i = 0;
    } else {
      Serial.print(FPSTR(dot));
    }
  }
  
}

Here is the (truncated) log:

# 2019-01-27 16-32-59.........
# 2019-01-27 16-33-09.........
# 2019-01-27 16-33-19.........
# 2019-01-27 16-33-29.........
# 2019-01-27 16-33-39...Querying pool.ntp.org ... success (round trip 55 ms)
Received time: Sunday, 27-Jan-19 15:33:43.071 UTC (internal clock was 15 ms fast)
......
# 2019-01-27 16-33-49.........
# 2019-01-27 16-33-59.........
# 2019-01-27 16-34-09.........
# 2019-01-27 16-34-19.........
# 2019-01-27 16-34-29.........
# 2019-01-27 16-34-39.........
# 2019-01-27 16-34-49.........
# 2019-01-27 16-34-59.........
# 2019-01-27 16-35-09.........
# 2019-01-27 16-35-19.........
# 2019-01-27 16-35-29.........
# 2019-01-27 16-35-39.........
# 2019-01-27 16-35-49.........
# 2019-01-27 16-35-59.........
# 2019-01-27 16-36-09.........
# 2019-01-27 16-36-19.........
# 2019-01-27 16-36-29.........
# 2019-01-27 16-36-39.........
# 2019-01-27 16-36-49.........
# 2019-01-27 16-36-59.........
# 2019-01-27 16-37-09.........
# 2019-01-27 16-37-19.........
# 2019-01-27 16-37-29.........
# 2019-01-27 16-37-39.........
# 2019-01-27 16-37-49.........
# 2019-01-27 16-37-59.........
# 2019-01-27 16-38-09.........
# 2019-01-27 16-38-19.........
# 2019-01-27 16-38-29.........
# 2019-01-27 16-38-39.........
# 2019-01-27 16-38-49.........
# 2019-01-27 16-38-59.........
# 2019-01-27 16-39-09.........
# 2019-01-27 16-39-19.........
# 2019-01-27 16-39-29.........
# 2019-01-27 16-39-39.........
# 2019-01-27 16-39-49.........
# 2019-01-27 16-39-59.........
# 2019-01-27 16-40-09.........
# 2019-01-27 16-40-19.........
# 2019-01-27 16-40-29.........
# 2019-01-27 16-40-39.........
# 2019-01-27 16-40-49.........
# 2019-01-27 16-40-59.........
# 2019-01-27 16-41-09.........
# 2019-01-27 16-41-19.........
# 2019-01-27 16-41-29.........
# 2019-01-27 16-41-39.........
# 2019-01-27 16-41-49.........
# 2019-01-27 16-41-59.........
# 2019-01-27 16-42-09.........
# 2019-01-27 16-42-19.........
# 2019-01-27 16-42-29.........
# 2019-01-27 16-42-39.........
# 2019-01-27 16-42-49.........
# 2019-01-27 16-42-59.........
# 2019-01-27 16-43-09.........
# 2019-01-27 16-43-19.........
# 2019-01-27 16-43-29.........
# 2019-01-27 16-43-39....Querying pool.ntp.org ... success (round trip 43 ms)
Received time: Thursday, 07-Feb-36 06:28:16.021 UTC (internal clock was 503760977 ms fast)
.....
# 2036-02-07 07-28-21.........
# 2036-02-07 07-28-31.........
# 2036-02-07 07-28-41.........
# 2036-02-07 07-28-51.........
# 2036-02-07 07-29-01.........
# 2036-02-07 07-29-11.........
# 2036-02-07 07-29-21.........
# 2036-02-07 07-29-31.........
# 2036-02-07 07-29-41.........
# 2036-02-07 07-29-51.........
# 2036-02-07 07-30-01.........
# 2036-02-07 07-30-11.........
# 2036-02-07 07-30-21.........
# 2036-02-07 07-30-31.........
# 2036-02-07 07-30-41.........
# 2036-02-07 07-30-51.........
# 2036-02-07 07-31-01.........
# 2036-02-07 07-31-11.........
# 2036-02-07 07-31-21.........
# 2036-02-07 07-31-31.........
# 2036-02-07 07-31-41.........
# 2036-02-07 07-31-51.........
# 2036-02-07 07-32-01.........
# 2036-02-07 07-32-11.........
# 2036-02-07 07-32-21.........
# 2036-02-07 07-32-31.........
# 2036-02-07 07-32-41.........
# 2036-02-07 07-32-51.........
# 2036-02-07 07-33-01.........
# 2036-02-07 07-33-11.........
# 2036-02-07 07-33-21.........
# 2036-02-07 07-33-31.........
# 2036-02-07 07-33-41.........
# 2036-02-07 07-33-51.........
# 2036-02-07 07-34-01.........
# 2036-02-07 07-34-11.........
# 2036-02-07 07-34-21.........
# 2036-02-07 07-34-31.........
# 2036-02-07 07-34-41.........
# 2036-02-07 07-34-51.........
# 2036-02-07 07-35-01.........
# 2036-02-07 07-35-11.........
# 2036-02-07 07-35-21.........
# 2036-02-07 07-35-31.........
# 2036-02-07 07-35-41.........
# 2036-02-07 07-35-51.........
# 2036-02-07 07-36-01.........
# 2036-02-07 07-36-11.........
# 2036-02-07 07-36-21.........
# 2036-02-07 07-36-31.........
# 2036-02-07 07-36-41.........
# 2036-02-07 07-36-51.........
# 2036-02-07 07-37-01.........
# 2036-02-07 07-37-11.........
# 2036-02-07 07-37-21.........
# 2036-02-07 07-37-31.........
# 2036-02-07 07-37-41.........
# 2036-02-07 07-37-51.........
# 2036-02-07 07-38-01.........
# 2036-02-07 07-38-11.....Querying pool.ntp.org ... success (round trip 19 ms)
Received time: Sunday, 27-Jan-19 15:53:43.109 UTC (internal clock was 503760912 ms slow)
....
# 2019-01-27 16-53-47.........
# 2019-01-27 16-53-57.........
# 2019-01-27 16-54-07.........
# 2019-01-27 16-54-17.........
# 2019-01-27 16-54-27.........

It occurs sometimes once / twice a day, randomly, it gets fixed after 10minutes as another sync is performed (as visible in the log above).

What can be source of the problem and how to avoid this?

Ggling around I found https://forum.arduino.cc/index.php?topic=92632.0 - maybe same or simmilar problem?

Ofcourse I can provide you with more info, just let me know...

DST ended early in PT

I noticed that DST ended early in my time zone on version 0.7.7.

Possibly related to #11?

Using setLocation("America/Los_Angeles"):

Date Time ezTime
NOV 3 11:00PM 10:00PM
NOV 4 12:00AM 11:00PM
NOV 4 1:00AM 12:00AM
NOV 4 1:00AM 1:00AM
NOV 4 2:00AM 2:00AM

Question: ezTime::setTime() and Arduino::configTime() not the same

While I love ezTime, I am confused how differently it works on an ESP8266 vs the configTime().

While writing in Arduino on a NodeMCU, I falsely assumed that calling ezTime::setTime() would set the system time that the Azure IoT Client SDK would honor. I still had to call the configTime() which grabbed from an NTP service.

From a core perspective, what is the difference between Arduino.h::configTime() and setTime()?

Feature request: expose _last_sync_time

It's great that it's logged in debug output, but it would be useful to be able to know programmatically when the last good network update occurred. Perhaps time_t lastNtpUpdateTime()

strip part of lib with define(s)

Hi,

i see that it's possible to remove some part of code with undef caching things.

i was wondering, if it's possible in the future to do the same with timezone part.
code size it's quite an issue for me, i am trying to make a reef aquarium controller, and pwm+i2c+5 adc+ 2x multiplexer + lcd+ 3*pump with timing + sunset/sunrise/cloud (for lights) and other things eat up a lot of memory. include the fact that i store everything via MQTT, have a websocket for debug, you can imagine that every bYte matter :)

taking out some pieces will greatly help.

tnx!

bool waitForSync should return a value

In successfull cases, synced time, waitForSync() should return a value (true). This return statement is missing in the function, so always false is returned.

Can not get network connection for NTP to work, not on WiFi

2:05:06.350 -> 192.168.0.99
12:05:06.385 -> Working ...
12:05:17.380 -> Working 2 ...
12:05:17.380 ->
12:05:17.380 -> Thursday, 01-Jan-70 00:00:11.574 UTC
12:05:17.380 -> Thursday, 01-Jan-70 00:00:11.577 UTC
12:05:17.380 -> Thursday, 01-Jan-70 00:00:11.580 UTC
12:05:17.380 -> Thursday, 01-Jan-70 00:00:11.583 UTC
12:05:17.415 -> Thursday, 01-Jan-70 00:00:11.586 UTC
12:05:17.415 -> Thursday, 01-Jan-70 00:00:11.589 UTC
12:05:17.415 -> Thursday, 01-Jan-70 00:00:11.592 UTC
12:05:17.415 -> Thursday, 01-Jan-70 00:00:11.596 UTC
12:05:17.415 -> Thursday, 01-Jan-70 00:00:11.599 UTC
12:05:17.415 -> Thursday, 01-Jan-70 00:00:11.602 UTC
12:05:17.415 ->
12:05:17.415 -> Those milliseconds between the first and the last line ...
12:05:17.415 ->
12:05:17.415 -> ... most of that is spent sending to the serial port.
12:05:17.415 ->
12:05:17.415 ->
12:05:17.415 ->
12:05:17.415 -> And ezTime is not making those milliseconds up either.
12:05:17.415 ->
12:05:17.415 -> ... Stick around as we do an NTP request every minute.
12:05:17.449 ->
12:05:17.449 -> ezTime debug level set to INFO
12:05:20.804 -> Querying pool.ntp.org ... ERROR: No network
12:05:25.808 -> Querying pool.ntp.org ... ERROR: No network

I have an NTP server at 192.168.0.5, and my IP is 192.168.0.99. Tried the pool.ntp.org site and still no joy.

UNO/Ethernet card.
Suggestions?
Thx,P

events conflicts with AsyncWebServer library

Hi Ron

Thanks for you previous help which looks good, however when I added your library into my main application and added the call to events(); I ran into a conflict with other libraries in my project which is using an ESP32 based project with the Arduino IDE. Looks like the conflict is with additional libraries required by the AsyncWebServer library.

task1.cpp:499:9: error: reference to 'events' is ambiguous

         events.onConnect([](AsyncEventSourceClient *client){

         ^

arduino_build_809613\sketch\task1.cpp:227:19: note: candidates are: AsyncEventSource events

 AsyncEventSource  events("/events");

                   ^

In file included from 
arduino_build_809613\sketch\main_framework.h:147:0,

                 from arduino_build_809613\sketch\task1.cpp:73:

Arduino Sketchbook\libraries\ezTime\src/ezTime.h:177:7: note:                 void ezt::events()

  void events();

       ^

task1.cpp:504:28: error: reference to 'events' is ambiguous

         server.addHandler(&events);

                            ^_

I solved the problem by renaming events to ezEvents in your libraries as they were the easiest to change and last to be added to my application. Is there a better way to do this without changing libraries.

Timezone date / time functions not working properly with time_t values

The TimeLib library allows using
hour(now()) to get the current hour so it would seem reasonable that local.hour(local.now()) should work as well as hour(now()) (when the local timezone is set to be the default) , but it doesn't.

Based on the above assumption that something like local.hour(local.now()), should work as it is passing in the time_t value from the local timezone object and simply attempting to get the hour in the local timezone,
there appears to be an issue related to using the date / time functions like hour() minute() etc....
when a time_t value is passed in.
Example:
local is not the default timezone.
now() - works as expected and returns the standard unix time_t
local.now() - returns a munged time_t value that is offset by the current local timezone offset.
local.hour() - works as expected and returns the hour in the local timezone

local.hour(local.now()) - returns the hour in UTC timezone not the hour in the local timezone.
local.hour(local.now(), LOCAL_TIME) - same as above
These seem incorrect, as there appears to be no way to get from a time_t value returned by the local timezone object to a local time value.

local.hour(UTC.now(), UTC_TIME) - works as expected and returns the hour in the local timezone

If you set the default timezone to local by using local.setDefault() then:
now() - returns a munged time_t value that is offset by the current local timezone offset.
local.hour(now()) - returns the hour in UTC timezone not the hour in the local timezone
hour(now()) - returns the hour in UTC timezone not the hour in the local timezone

While these examples are very simplistic actual code may do something more like:

t = now();
// other code
hourvalue = hour(t);
minvalue = minute(t);
// or
sprintf(buf, "%02d:%02d:%02d", hour(t), minute(t), second(t));

And that doesn't work with eztime when using something other than the UTC timezone.

It seems that there should be a way to get from a time_t value returned by the timezone object to a local time value using the timezone methods.


I think much of these kinds of issues relate to the issues brought in in issue #10 where the time_t values returned by the timezone objects are not the actual time_t value but rather a munged value for the local timezone.

In this specific case it appears that tzTime() is always called by the various timeszone methods like hour() and when the local_or_utc value indicates the value is LOCAL_TIME, tzTime() flips it to UTC , the UTC time_t value is used and then the UTC time value is returned instead of the local timezone value.
IMO, that is not the expected behavior.

While all this could be fixed to work, even when using munged time_t values, as the code is currently doing,
local.hour(t) or local.hour(local.now()) could work when time_t value was talways he proper unix time_t value.

I think things would get much simpler and become consistent with the way time_t epoch values are supposed to work if all the now() functions always returned the unix time_t value which is the UTC time_t.
Yes there would be some need for internally doing conversions when doing the local value conversions, but that wouldn't need to be exposed to the users.
Everything should still work and be compatible with the TimeLib API.

It would also make now() lightweight and very fast, as it should be.
Currently tzTime() is called 3 or more times just to get a time_t when some thing like local.now() is called which definitely adds in quite a bit of overhead that would go away.
makeTime() and breakTime() should be the expensive functions that deal with all the timezone issues and should be moved to be in the Timezone class which can handle the local timezone conversions.
Then, all the timezone methods like hour() would first call breakTime() which would do the needed timezone offset conversion, then pick out the needed value and return it.
users could call also local.breakTime() to get all the local time values at once if they desired.
makeTime() and breakTime() could be left in the ezt class and call the default timezone version just like some of the other functions.

Please document privacy policy

You are offering a service on timezoned.rob.nl so users of your library can find out DST and TZ information.

Please document your privacy policy for information collected on this service as per EU GDPR.

Querying pool.ntp.org ... ERROR: No network

I am using the default arduino example eztime-ethernetshield. I was using it for longer, however as of today i can not get it to work any more. Arduino SW-version 1.8.10 and eztime 0.7.10.
Serial output:
Ethernet connection ... got DHCP IP: 192.168.2.103

UTC: Thursday, 01-Jan-1970 00:00:08 UTC
New Zealand: Thursday, 01-Jan-1970 00:00:08 UTC
Germany: Thursday, 01-Jan-1970 00:00:13 UTC
Local (GeoIP): No network

Now ezTime will show an NTP sync every 60 seconds

ezTime debug level set to INFO
Querying pool.ntp.org ... ERROR: No network

I tried to set to de.pool.ntp.org and tested it on a mega and an uno with different ethernet shields, with the same result.
I tried with a different code on the same board to access google, which works.
Any idea?

MKR1000 and MKR WiFi1010 - EEPROM

Hello,
As indicate in the Readme file, to use the MKR familly, I commented the two lines :
//#define EZTIME_CACHE_EEPROM
// #define EZTIME_CACHE_NVS

What is the impact of not using the epprom ?

Picking up on an event

I am using EZTime together with a DS3231 RTC so that the clock will operate correctly even if there is no network connection. For instances where a network connection is available is there any way to pick up on the event that occurs when an NTP update completes so I can use the new time setting to correct the RTC if necessary.

I currently have the RTC periodically updating the local clock but would like to correct the RTC if a new time is received from the NTP. Using the DEBUG setting I can see the messages
Querying pool.ntp.org ... success (round trip 46 ms)
Received time: Friday, 02-Nov-18 20:32:29.319 UTC (internal clock was 1237 ms fast)
from the DEBUG but I am not sure how to pick up on the events completion.

Hardware is an ESP WROOM 32 module on a custom PCB with DS3231 chip, using the rtc_by_manuka library for the DS3231.

makeOrdinalTime return wrong result

The function makeOrdinalTime returns 24th of March 2019 as the last (ordinal 5) Sunday of March. In my calendar the 31st March is th last Sunday. It seams that this is the reason for #31

Spelling of February

In ezTime.h line 86: #define FEBRUARI 2
Should be: #define FEBRUARY 2

Also in keywords.txt

compileTime() wrong TZ

Compiled a sketch at 6:23 PM EST.

In the sketch, with myTZ.setPosix("EST5EDT,M3.2.0,M11.1.0"),

dateTime(compileTime(),RFC850) produces "Friday, 01-Feb-2019 23:17:55 EST"

So, it seems to be showing the time in UTC, but labeling it as EST.

Results from timezoned.rop.nl:2342

Hello, maybe this is not a bug, but I want to understand this.

For "Africa/Casablanca" your answer is: "OK Africa/Casablanca WET0WEST,M3.5.0,M10.5.0/3"

zdump -v Africa/Casablanca (for 2018) results to:

Africa/Casablanca Sun Mar 25 01:59:59 2018 UT = Sun Mar 25 01:59:59 2018 +00 isdst=0 gmtoff=0
Africa/Casablanca Sun Mar 25 02:00:00 2018 UT = Sun Mar 25 03:00:00 2018 +01 isdst=1 gmtoff=3600
Africa/Casablanca Sun May 13 01:59:59 2018 UT = Sun May 13 02:59:59 2018 +01 isdst=1 gmtoff=3600
Africa/Casablanca Sun May 13 02:00:00 2018 UT = Sun May 13 02:00:00 2018 +00 isdst=0 gmtoff=0
Africa/Casablanca Sun Jun 17 01:59:59 2018 UT = Sun Jun 17 01:59:59 2018 +00 isdst=0 gmtoff=0
Africa/Casablanca Sun Jun 17 02:00:00 2018 UT = Sun Jun 17 03:00:00 2018 +01 isdst=1 gmtoff=3600
Africa/Casablanca Fri Oct 26 22:59:59 2018 UT = Fri Oct 26 23:59:59 2018 +01 isdst=1 gmtoff=3600
Africa/Casablanca Fri Oct 26 23:00:00 2018 UT = Sat Oct 27 00:00:00 2018 +01 isdst=0 gmtoff=3600
0

I think POSIX TZ should be: GMT0GMT-1,M3.5.0/02:00:00,M5.3.0/03:00:00,M6.4.0/02:00:00,M10.4.6/00:00:00

Please enlighten me. / Greetings Kai.

Using country code "za" does not set timezone.setLocation as expected

I'm attempting to build an "always right" NTP based clock with a dot matrix display and have come across the awesome ezTime library which looks perfect for my needs (and way beyond!)

I have run into an issue whereby using a country code does not seem to set my location and hence the relevant timezone info.

I have a test sketch which uses "de" as per the ethernet example sketch which functions fine but when I change only the "de" to "za" I don't get a result returned. Exactly the same happens if I try to use the GeoIP lookup.

I'm in South Africa which has a single time zone of UTC+2.

The below illustrates first the working scenario with a "de" sketch and associated debug output and the second a non-working scenario and associated debug output.

I'm no developer and tend to hack my way through examples of various libraries to put sketches together so it's completely probable that I'm missing something along the way but thought I'd report this anyway,

Working Scenario - "de"

#include <ezTime.h>
#include <ESP8266WiFi.h>          // Replace with WiFi.h for ESP32
#include <ESP8266WebServer.h>     // Replace with WebServer.h for ESP32
#include <AutoConnect.h>

ESP8266WebServer Server;          // Replace with WebServer for ESP32
AutoConnect Portal(Server);

void rootPage() {
  char content[] = "Hello, world ... browse to http://<ip addres>/_ac to configure AP, SSID, password etc. settings";
  Server.send(200, "text/plain", content);
}

void setup() {

  // Set ezTime debug level as required [https://github.com/ropg/ezTime#setdebug]
  setDebug(DEBUG);
  
  // Open serial communications and wait for port to open:
  Serial.begin(115200);

  // wait for serial port to connect. Needed for native USB port only
  while (!Serial) {
    ;
  }

  //Beging Debug Output
  Serial.println();
  Serial.println();
  Serial.println();
  Serial.println();
  Serial.println("----Debug Begins--------------------------------------------");
  Serial.println();

  // Enable Autoconnect portal and if successful, output Ip to debug
  Server.on("/", rootPage);
  if (Portal.begin()) {
    Serial.println("WiFi connected: " + WiFi.localIP().toString());
  }

  // We're now online
  
  // Wait for ezTime to get its time synchronized and wait 5 seconds
  waitForSync();
  delay(5000);  
  
  // Create a timezonr called myTZ
  Timezone myTZ;

  // Output UTC
  Serial.println();
  Serial.println("<ezTime> UTC: " + UTC.dateTime());
  Serial.println();

  //Set myTZ's location and outpit the result
  myTZ.setLocation(F("de"));
  Serial.print(F("<ezTime> myTZ: "));
  Serial.println(myTZ.dateTime());
  myTZ.getTimezoneName();
  myTZ.getOlson();
  
  //Set NTP update frequency in seconds
  setInterval(60); //[https://github.com/ropg/ezTime#setserver-and-setinterval]
}

void loop() {
  //Handle the Autoconnect client
  Portal.handleClient();
  
  //Handle the ezTmine events //[https://github.com/ropg/ezTime#events]
  events();
}



----Debug Begins--------------------------------------------

[AC] WiFi.config(IP=0.0.0.0, Gateway=0.0.0.0, Subnetmask=0.0.0.0, DNS1=0.0.0.0, DNS2=0.0.0.0)
[AC] DHCP client(STARTED)
[AC] WiFi.begin()
[AC] Connecting.established IP:192.168.0.123
[AC] http server started
WiFi connected: 192.168.0.123
Waiting for time sync
Querying pool.ntp.org ... Received data:
0: 24, 2, 9, EC, 
4: 0, 0, 28, 9B, 
8: 0, 0, 0, 2F, 
12: 55, C7, D6, 62, 
16: E0, 53, 45, A9, 
20: 75, 9F, 5D, 1A, 
24: 0, 0, 0, 0, 
28: 0, 0, 0, 0, 
32: E0, 53, 48, 67, 
36: 8E, E8, 28, 34, 
40: E0, 53, 48, 67, 
44: 8E, EA, DD, 90, 
success (round trip 54 ms)
Received time: Saturday, 06-Apr-19 15:46:47.587 UTC
Set event (#1) to trigger on: Saturday, 06-Apr-2019 16:16:48 UTC
Time is in sync

<ezTime> UTC: Saturday, 06-Apr-2019 15:46:52 UTC

Timezone lookup for: de ... (round-trip 173 ms)  success.
  Olson: Europe/Berlin
  Posix: CET-1CEST,M3.5.0,M10.5.0/3
<ezTime> myTZ: Saturday, 06-Apr-2019 17:46:52 CEST
Deleted event (#1), set for Saturday, 06-Apr-2019 16:16:48 UTC
Set event (#1) to trigger on: Saturday, 06-Apr-2019 15:47:52 UTC

Failing scenario - "za"

#include <ezTime.h>
#include <ESP8266WiFi.h>          // Replace with WiFi.h for ESP32
#include <ESP8266WebServer.h>     // Replace with WebServer.h for ESP32
#include <AutoConnect.h>

ESP8266WebServer Server;          // Replace with WebServer for ESP32
AutoConnect Portal(Server);

void rootPage() {
  char content[] = "Hello, world ... browse to http://<ip addres>/_ac to configure AP, SSID, password etc. settings";
  Server.send(200, "text/plain", content);
}

void setup() {

  // Set ezTime debug level as required [https://github.com/ropg/ezTime#setdebug]
  setDebug(DEBUG);
  
  // Open serial communications and wait for port to open:
  Serial.begin(115200);

  // wait for serial port to connect. Needed for native USB port only
  while (!Serial) {
    ;
  }

  //Beging Debug Output
  Serial.println();
  Serial.println();
  Serial.println();
  Serial.println();
  Serial.println("----Debug Begins--------------------------------------------");
  Serial.println();

  // Enable Autoconnect portal and if successful, output Ip to debug
  Server.on("/", rootPage);
  if (Portal.begin()) {
    Serial.println("WiFi connected: " + WiFi.localIP().toString());
  }

  // We're now online
  
  // Wait for ezTime to get its time synchronized and wait 5 seconds
  waitForSync();
  delay(5000);  
  
  // Create a timezonr called myTZ
  Timezone myTZ;

  // Output UTC
  Serial.println();
  Serial.println("<ezTime> UTC: " + UTC.dateTime());
  Serial.println();

  //Set myTZ's location and outpit the result
  myTZ.setLocation(F("za"));
  Serial.print(F("<ezTime> myTZ: "));
  Serial.println(myTZ.dateTime());
  myTZ.getTimezoneName();
  myTZ.getOlson();
  
  //Set NTP update frequency in seconds
  setInterval(60); //[https://github.com/ropg/ezTime#setserver-and-setinterval]
}

void loop() {
  //Handle the Autoconnect client
  Portal.handleClient();
  
  //Handle the ezTmine events //[https://github.com/ropg/ezTime#events]
  events();
}


----Debug Begins--------------------------------------------

[AC] WiFi.config(IP=0.0.0.0, Gateway=0.0.0.0, Subnetmask=0.0.0.0, DNS1=0.0.0.0, DNS2=0.0.0.0)
[AC] DHCP client(STARTED)
[AC] WiFi.begin()
[AC] Connecting.established IP:192.168.0.123
[AC] http server started
WiFi connected: 192.168.0.123
Waiting for time sync
Querying pool.ntp.org ... Received data:
0: 24, 2, 9, E9, 
4: 0, 0, 0, 82, 
8: 0, 0, 9, 5D, 
12: C4, 15, BB, 2, 
16: E0, 53, 6A, 85, 
20: B5, 48, 0, BB, 
24: 0, 0, 0, 0, 
28: 0, 0, 0, 0, 
32: E0, 53, 6F, 6E, 
36: C3, 81, FF, 2B, 
40: E0, 53, 6F, 6E, 
44: C3, 82, CC, 2, 
success (round trip 53 ms)
Received time: Saturday, 06-Apr-19 18:33:18.792 UTC
Set event (#1) to trigger on: Saturday, 06-Apr-2019 19:03:19 UTC
Time is in sync

<ezTime> UTC: Saturday, 06-Apr-2019 18:33:23 UTC

Timezone lookup for: za ... (round-trip 504 ms)  <ezTime> myTZ: Saturday, 06-Apr-2019 18:33:24 UTC
Deleted event (#1), set for Saturday, 06-Apr-2019 19:03:19 UTC
Set event (#1) to trigger on: Saturday, 06-Apr-2019 18:34:24 UTC

Possible need to clarify where to use setInterval() function to disable updateNTP()

I am using eztime as part of a multitask environment and could not understand why it was not working as expected when trying to disable the default updateNTP event. The problem is that in this case you must use the events function first before you try to disable the updateNTP event as part of the events function is to start updateNTP on the first run through even if you had already called setInterval(0). The problem is exacerbated in a multi task environment where the two tasks are running independantly.

Would help I think to make this clear in the documentation.

Timezones not working

A few days ago this was still working for me, but it stopped working for some reason, even with your simple example. when enabling debugging (INFO), I got the following error:

Timezone lookup for: Pacific/Auckland
ERROR: Data not found

Checking the source, it appears that this library uses https://timezoneapi.io to get the data, which states on their website:

Announcement: As of October 4th, 2018 TimezoneAPI will no longer support free plans. Read more…

That's still 2 weeks from now, so to get more debugging I set debug to DEBUG, and it looks like they have a 301 redirect from the http address to https:

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="https://timezoneapi.io/api/timezone/?Pacific%2FAuckland">here</a>.</p>
</body></html>

so it looks like going forward another method for getting timezones should be used...

Wrong begin date of DST

Hello,
I use the library without a network connection. Therfore I defined the POSIX TZ rule like this:

#define CET_POSIX	"CET-1CEST,M3.5.0/02:00:00,M10.5.0/03:00:00"		// Time in Berlin
LOC.setPosix(CET_POSIX);

The last Sunday in March this year will be the 31st. Unfortunatly the DST begin date seems to be already on 24th of March. This could be a similar problem with the POSIX day number like #28

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.