-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
time is messed-up (RTC and utime) #5969
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
In rshell, I query the time to figure out the epoch, and then just
add/subtract that to convert times between the two time bases.
```
epoch_tuple = time.gmtime(0)
```
Then (at least on the host side) I set `time_offset
= calendar.timegm(epoch_tuple)` and all the places that I retrieve a time
from the pyboard, it adds time_offset to it toconvert it between pyboard
time and host time.
There is a constant number of seconds between Jan 1, 1970 and Jan 1, 2000,
so you can also just add/subtract that.
…On Sat, Apr 25, 2020 at 12:04 AM Thorsten von Eicken < ***@***.***> wrote:
Background: I'm trying to enable lwip's sntp client on the esp32 and it's
not going so well... The reason is the EPOCH. The world thinks it's 1970,
MP thinks it's 2000. Oops.
I looked at the machine.RTC mess, utime, #5733
<#5733> and #5553
<#5553>. On an unconnected
MP board, such as a pyboard perhaps with a GPS module the existing RTC and
utime make a lot of sense. It's very little code, the RTC can be set via
pyboard over USB or by app code using the GPS. Thereafter the app can get
the time.
On a connected board, such as esp or pybd, the existing RTC and utime make
much less sense. The lwip sntp client does what you'd expect it to do and
steps or slews the RTC (your choice). There's a good set of std C functions
to manipulate time (gettimeofday, mktime, localtime, etc). The machine.RTC
module can of course be useful if Wifi is off, etc, but it's kind'a
duplicated code. The utime localtime and mktime are a hazard given the they
use a different epoch than lwip. On the pybd all this is not a huge issue
'cause there's no SNTP...
I'm not sure how to fix this without spending a lot of work with an
uncertain outcome... It seems easier to just write a dynamically loadable
native module for the esp32 that uses the lwip sntp and std C time
functions and forget about RTC and utime. Thoughts?
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#5969>, or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAA7EDHBX6PDGCYI6FXRKC3ROKDOFANCNFSM4MQT7T2A>
.
--
Dave Hylands
Peachland, BC, Canada
http://www.davehylands.com
|
I understand that there is a constant difference. However, with SNTP enabled the RTC gets set based on 1970 and then calls to, for example, I also have a dynamically loaded native module that skips RTC and utime and just uses the esp-idf functions to handle sntp and time and completely disregards RTC and utime, but that doesn't make these less messed-up... |
I don't understand. The RTC gets sets using individual fields (year, month, day, hour, minute, second) and not the number of seconds from some epoch. So once it's set you can use utime.time.time() to get the current time and utime.localtime to convert that back into broken out fields. There might be a timzone difference, but this is also just a constant time difference that you can add/subtract from utime.time(). If you're using SNTP then the RTC time will wind up being on GMT (at least this is what happens on the leboris port) and you'll need to add/subtract your timezone to convert into local time since not of the micropython ports have a notion of timezone. |
The LwIP SNTP client sets the RTC on the esp32 directly, not by calling MicroPython's RTC.datetime. |
Right - this is what the leboris port does as well. This typically means that the RTC is in GMT instead of localtime, so you need to adjust the time returned by utime.time() by the number of seconds that your timezone is. If you wanted to make a patch, then having adding a function which sets/gets a timezone adjustment would be worthwhile (at least in my opinion) and would mean that you wouldn't need to do it in your own code. |
Nope. LwIP SNTP sets the RTC to UTC with an epoch of 1970. |
I would consider changing the MicroPython-epoch to the standard 1970 one.... this is a pretty significant difference from CPython (and the unix world) and has pretty far reaching consequences. And since time in general is hard to get right, this makes it unnecessarily harder. My opinion now (as opposed to 6 years ago when On systems with only 32-bit float it cannot return a float because floats can't represent the number with 1 second accuracy. So such systems would return a big-int. Code would then work "as expected", except you don't get sub-second accuracy. (Although there's an argument that if it can return sub-second accuracy then it's not working as expected from CPython sa shouldn't exist at all, but I think it's an ok compromise to return a big-int if 64-bit floats are not available.) On systems without big-ints enabled, they cannot include a sensible implementation of Note: currently the way to make For getting sub-second, absolute time values, @tve suggests in #5973 to add But then remains the question about getting absolute time values without memory allocation. One way to do that would be an in-place To make up for the loss of In summary:
(Also, I think all non-CPython functions like All the above is a big breaking change so would need to be decided upon and executed carefully. |
If that includes |
[sorry for the wall of text, sadly time is complicated...] I don't know whether you took a look at #5973 since I reverted back to the 2000 Epoch. It is much less painful than I expected, just a couple of delta constants sprinkled in. The NTP code is similarly a non-issue. The delta between 1970 and 2000 doesn't even appear because a delta between the NTP Epoch (which is not 1970) and the system Epoch is needed so that takes care of everything. I see two reasons to switch to a 1970 epoch. There's the compatibility with CPython and there's the issue that any short-int solution will overflow in less than 20 years. I haven't encountered the compatibility issue and thus don't have a good sense for the use-cases that hit it. Also, it seems to me that Python does not mandate a specific Epoch, e.g. the CPython docs for
I find the overflow issue still a bit more theoretical than practical, but it leaves a definitely bad taste behind. Can you perhaps elaborate on what makes you reconsider the change you describe? Overall it seems to me that it's really important that In the context of the above, I'm not sure about "I think all non-CPython functions like ticks_s() and time_us() should be in a separate module, eg ticks." I would rephrase this as "all functions that measure ticks (the vibrations of a crystal oscillator) should be in a separate module from those measuring time, as in unix time which is closely related to but different from NTP time, GPS time, and UTC time." I'm not sure I see the real benefit of such a module split, though. BTW, if there is a hard requirement for non-allocating You mention using RTC.datetime to perhaps address the allocation issue. I must say that I really dislike the idea because it mixes responsibilities. An application should either (a) use the RTC as a peripheral, manage it, and refrain from using system time, or (b) use system time and let that manage the RTC peripheral as it sees fit. I.e. you cannot use system time and also place requirements on how it is to manage the time-keeping peripheral. In terms of going forward, I'm using my PR #5973 as-is in my own fork 'cause I need the functionality to make SNTP work in a sane manner. I'm happy to prepare a different PR that implements, for example, the big-int version you outline. In my mind there are two big issues here:
|
I opt for a pragmatic solution:
An incomplete list of pros & cons:
Con:
|
The RTC hardware on stm32 does not allow NSSE, it consists of BCD counters for YMD-HMS.sss
NTP and adjtime really need sub-second resolution to get sub-second sync
The hardware may not support that, e.g. esp32, esp8266.
The ESP-IDF already contains the code, you're already paying for it.
Can you elaborate? |
I think @tve is right about system time vs RTC. RTC represents a peripheral. A piece of hardware which in some cases is more accurate than system clock, in others (ESP8266) is lousy. Some users install accurate RTC devices - another reason to see them as peripherals. It would be good if there were an interface spec for an AbstractRTC. I can also see merit in a means of monotonically adjusting the system clock from an AbstractRTC and vice versa. |
I think the biggest issue here is that there are two fundamentally different types of hardware devices. There are clock tick counters and there are calendar counters. The STM32 RTC and that DS13xx (forget the exact number) fundamentally count years, months, days, hours, seconds, fractions. Getting a seconds-since-epoch requires going through the equivalent of mktime. The esp and nrf RTC fundamentally count clock ticks, i.e. seconds-since-epoch and getting YMD-HMS requires going through the equivalent of gmtime. So at some level, you would really need a machine.Date peripheral or a machine.Clock peripheral depending on port... |
Let's distinguish between RTC as peripheral and RTC as a virtual device. In my point of view the current RTC module as used in MP already implements a virtual device. I agree that naming is quite confusing and I don't care how the virtual RTC is called as long as it provides a monotonic 'real-time' with sufficient precision, resolution and value range. A 64bit counter can do a pretty good job. |
I feel that For |
We have had Note this issue about avoiding double-precision floating-point when computing a float time, which can sneak in by accident and bloat the firmware: adafruit#343. Other CircuitPython discussions that may be of interest: |
Thanks for the pointers, I need to get into the habit of checking CP when fixing stuff! Question: other than the type of the return value, is this really ticks without roll-over? I.e., which time-base does it use? The python docs don't mention the difference between processor clock ticks and real-time... |
Right, no rollover. We were using |
If you're using the RTC, how do you keep |
On atmel and nrf, the RTC is a counter that is not reset. We just keep an offset. On STM, there may be a bug, since the RTC is a real calendar clock. We should keep an offset if we don't. |
This is a good discussion but there are lots of points to follow... I'm still of the opinion that It might also be useful to add |
crc32() code moved into binascii
Background: I'm trying to enable lwip's sntp client on the esp32 and it's not going so well... The reason is the EPOCH. The world thinks it's 1970, MP thinks it's 2000. Oops.
I looked at the machine.RTC mess, utime, #5733 and #5553. On an unconnected MP board, such as a pyboard perhaps with a GPS module the existing RTC and utime make a lot of sense. It's very little code, the RTC can be set via pyboard over USB or by app code using the GPS. Thereafter the app can get the time.
On a connected board, such as esp or pybd, the existing RTC and utime make much less sense. The lwip sntp client does what you'd expect it to do and steps or slews the RTC (your choice). There's a good set of std C functions to manipulate time (gettimeofday, mktime, localtime, etc). The machine.RTC module can of course be useful if Wifi is off, etc, but it's kind'a duplicated code. The utime localtime and mktime are a hazard given the they use a different epoch than lwip. On the pybd all this is not a huge issue 'cause there's no SNTP...
I'm not sure how to fix this without spending a lot of work with an uncertain outcome... It seems easier to just write a dynamically loadable native module for the esp32 that uses the lwip sntp and std C time functions and forget about RTC and utime. Thoughts?
The text was updated successfully, but these errors were encountered: