Created
January 13, 2022 14:17
-
-
Save jmparatte/9b11bef78c722c09323898d85ab307fe to your computer and use it in GitHub Desktop.
Leap second and time smearing with ESP32 MicroPython
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import time | |
def time1_mktime(tm): | |
t = time.mktime(tm) | |
if tm[0]<MPY_MJD: t -= 2**32 # date < MicroPython epoch => previous u32 era !!! | |
return t | |
# https://developers.google.com/time/smear | |
# https://github.com/google/unsmear | |
# http://michel.lalos.free.fr/cadrans_solaires/doc_cadrans/seconde_intercalaire/seconde_intercalaire.html | |
# https://www.admin.ch/gov/fr/accueil/documentation/communiques.msg-id-45083.html | |
# https://www.bulletin.ch/fr/news-detail/alexia-labolition-de-la-seconde-intercalaire.html | |
# https://hpiers.obspm.fr/eop-pc/index.php?index=TAI-UTC_tab&lang=en | |
MPY_YEAR = 2000 # 2000-01-01 | |
MPY_MJD = 51544.0 # 2000-01-01 | |
MPY_UTC = 0 # 2000-01-01 | |
UTC_SEC = 1 # 1 second | |
UTC_MIN = 60 # 1 minute | |
UTC_HOUR = 3600 # 1 hour | |
UTC_DAY = 86400 # 1 day | |
UTC_NOON = 43200 # noon (12:00:00) = 12 hours = 1/2 day | |
UTC_MNS = 1000000000 # modulo 1e9 nanoseconds (1s) | |
LS32_UTC = -31536000 # 1999-01-01: leap second 32 (+1) | |
LS37_UTC = 536544000 # 2017-01-01: leap second 37 (+1); last leap as knowed at 2022-01 | |
# UTC and TAI constants are identical. | |
# UTC time is smeared from +/-12 hours around leap second. | |
# UTC time is expanded/contracted +/-11574ppb (about 11.5ppm) | |
# UTC is the human time (days are always 86400 seconds). | |
# TAI is never smeared. | |
# TAI is the true linear time. | |
# the conversion between UTC and TAI is safe. | |
# https://hpiers.obspm.fr/iers/bul/bulc/Leap_Second.dat | |
# ----------------------------------------------------- | |
# 1999-01-01 with 32 leap seconds (MicroPython epoch is 2000-01-01) | |
# till 2017-01-01 37 leap seconds (as knowed at 2022-01-11) | |
_leap_second_table = ( | |
#(-3155673600, 0), # 1900-01-01 | |
#(-883612800, 10), | |
#(-867888000, 11), | |
#(-851990400, 12), | |
#(-820454400, 13), | |
#(-788918400, 14), | |
#(-757382400, 15), | |
#(-725760000, 16), | |
#(-694224000, 17), | |
#(-662688000, 18), | |
#(-631152000, 19), | |
#(-583891200, 20), | |
#(-552355200, 21), | |
#(-520819200, 22), | |
#(-457660800, 23), | |
#(-378691200, 24), | |
#(-315532800, 25), | |
#(-283996800, 26), | |
#(-236736000, 27), | |
#(-205200000, 28), | |
#(-173664000, 29), | |
#(-126230400, 30), | |
#(-78969600, 31), | |
(-31536000, 32), # 1999-01-01 | |
(189388800, 33), # 2006-01-01 | |
(284083200, 34), # 2009-01-01 | |
(394416000, 35), # 2012-07-01 | |
(489024000, 36), # 2015-07-01 | |
(536544000, 37)) # 2017-01-01 | |
def leap_second_extract(): | |
global _leap_second_table | |
_leap_second_table = () | |
#_leap_second_table = ((-3155673600, 0),) # 1900-01-01 | |
#_leap_second_table = ((-31536000, 32),) # 1999-01-01 | |
f = open(b'Leap_Second.dat') | |
for l in f: | |
l = l.strip() | |
if len(l) and l[0]!='#': | |
#print(l) | |
l = l.replace(' ',' ') | |
l = l.replace(' ',' ') | |
l = l.replace(' ',' ') | |
#print(l) | |
(ls_mjd, ls_mday, ls_month, ls_year, ls_ofs) = eval('(' + l.replace(' ',',') + ')') | |
# (MJD, mday, month, year, leap_second), example: | |
# (57754.0, 1, 1, 2017, 37); last leap as knowed at 2022-01 | |
#print((ls_mjd, ls_mday, ls_month, ls_year, ls_ofs)) | |
# add data to table only if year >= 1999: | |
# - MicroPython not designed to handle dates below 2000. | |
# - 1999 is required to compute any timezone of 2000-01-01Z. | |
if ls_year>=1999: | |
#ls_utc = time1_mktime((ls_year,ls_month,ls_mday, 0,0,0, 0,0)) | |
ls_utc = int((ls_mjd - MPY_MJD)*UTC_DAY) # MJD to MicroPython epoch | |
_leap_second_table += ((ls_utc, ls_ofs),) | |
f.close() | |
return _leap_second_table | |
def taitime(utcsmear): | |
global _leap_second_table | |
(utc_sec, utc_mns) = utcsmear | |
#print((utc_sec, utc_mns)) | |
for i in range(len(_leap_second_table)): | |
j = len(_leap_second_table) - i - 1 | |
(ls_utc, ls_ofs) = _leap_second_table[j] | |
#print(ls_utc, ls_ofs) | |
if j==0 or utc_sec>=(ls_utc + UTC_NOON): | |
tai_sec = utc_sec + ls_ofs | |
tai_mns = utc_mns | |
break | |
ls_inc = ls_ofs - _leap_second_table[j-1][1] | |
#print(ls_inc) | |
if utc_sec>=(ls_utc - UTC_NOON): | |
tai_sec = utc_sec + ls_ofs - ls_inc | |
tai_mns = (utc_mns*(UTC_DAY + ls_inc) + (utc_sec - (ls_utc - UTC_NOON))%UTC_DAY*UTC_MNS + UTC_NOON) // UTC_DAY | |
tai_sec += tai_mns//UTC_MNS | |
tai_mns = tai_mns%UTC_MNS | |
break | |
#print(utc_sec, utc_mns, tai_sec, tai_mns, tai_sec - utc_sec, tai_mns - utc_mns) | |
return (tai_sec, tai_mns) # taitime | |
def utcsmear(taitime): | |
global _leap_second_table | |
(tai_sec, tai_mns) = taitime | |
#print((tai_sec, tai_mns)) | |
for i in range(len(_leap_second_table)): | |
j = len(_leap_second_table) - i - 1 | |
(ls_utc, ls_ofs) = _leap_second_table[j] | |
#print(ls_utc, ls_ofs) | |
if j==0 or tai_sec>=(ls_utc + ls_ofs + UTC_NOON): | |
utc_sec = tai_sec - ls_ofs | |
utc_mns = tai_mns | |
break | |
ls_inc = ls_ofs - _leap_second_table[j-1][1] | |
#print(ls_inc) | |
if tai_sec>=(ls_utc + ls_ofs - ls_inc - UTC_NOON): | |
utc_sec = tai_sec - ls_ofs + ls_inc | |
utc_mns = (tai_mns*UTC_DAY - (tai_sec - (ls_utc + ls_ofs - ls_inc - UTC_NOON))%(UTC_DAY + ls_inc)*UTC_MNS + UTC_NOON) // (UTC_DAY + ls_inc) | |
utc_sec += utc_mns//UTC_MNS | |
utc_mns = utc_mns%UTC_MNS | |
break | |
#print(utc_sec, utc_mns, tai_sec, tai_mns, tai_sec - utc_sec, tai_mns - utc_mns) | |
return (utc_sec, utc_mns) # utcsmear | |
leap_second_extract() | |
#taitime((0, 0)) | |
#taitime((LS37_UTC + UTC_NOON + 1, 0)) | |
#for s in range(LS37_UTC - UTC_DAY, LS37_UTC + UTC_DAY + 60*60*2, 60*60*2): | |
# tai = taitime((s,0)) | |
# print(tai[0]-s + tai[1]/UTC_MNS) | |
#utcsmear(taitime((LS37_UTC+UTC_DAY, UTC_MNS//2))) | |
print() | |
utc=(LS37_UTC+UTC_NOON+0, UTC_MNS//2);utc;tai=taitime(utc);tai;utcsmear(tai) | |
print() | |
utc=(LS37_UTC+UTC_NOON+0, 0);utc;tai=taitime(utc);tai;utcsmear(tai) | |
print() | |
utc=(LS37_UTC+UTC_NOON-1, UTC_MNS//2);utc;tai=taitime(utc);tai;utcsmear(tai) | |
print() | |
utc=(LS37_UTC+UTC_NOON-1, 0);utc;tai=taitime(utc);tai;utcsmear(tai) | |
print() | |
utc=(LS37_UTC-UTC_NOON*0, 0);utc;tai=taitime(utc);tai;utcsmear(tai) | |
print() | |
utc=(LS37_UTC-UTC_NOON+1, 0);utc;tai=taitime(utc);tai;utcsmear(tai) | |
print() | |
utc=(LS37_UTC-UTC_NOON+0, UTC_MNS//2);utc;tai=taitime(utc);tai;utcsmear(tai) | |
print() | |
utc=(LS37_UTC-UTC_NOON+0, 0);utc;tai=taitime(utc);tai;utcsmear(tai) | |
print() | |
utc=(LS37_UTC-UTC_NOON-1, UTC_MNS//2);utc;tai=taitime(utc);tai;utcsmear(tai) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment