Skip to content

Instantly share code, notes, and snippets.

@jmparatte
Created January 13, 2022 14:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jmparatte/9b11bef78c722c09323898d85ab307fe to your computer and use it in GitHub Desktop.
Save jmparatte/9b11bef78c722c09323898d85ab307fe to your computer and use it in GitHub Desktop.
Leap second and time smearing with ESP32 MicroPython
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