Files
micropython/tests/extmod/time_mktime.py
Yoctopuce dev df05caea6c
Some checks failed
JavaScript code lint and formatting with Biome / eslint (push) Has been cancelled
Check code formatting / code-formatting (push) Has been cancelled
Check spelling with codespell / codespell (push) Has been cancelled
Build docs / build (push) Has been cancelled
Check examples / embedding (push) Has been cancelled
Package mpremote / build (push) Has been cancelled
.mpy file format and tools / test (push) Has been cancelled
Build ports metadata / build (push) Has been cancelled
alif port / build_alif (alif_ae3_build) (push) Has been cancelled
cc3200 port / build (push) Has been cancelled
esp32 port / build_idf (esp32_build_cmod_spiram_s2) (push) Has been cancelled
esp32 port / build_idf (esp32_build_s3_c3) (push) Has been cancelled
esp8266 port / build (push) Has been cancelled
mimxrt port / build (push) Has been cancelled
nrf port / build (push) Has been cancelled
powerpc port / build (push) Has been cancelled
qemu port / build_and_test_arm (bigendian) (push) Has been cancelled
qemu port / build_and_test_arm (sabrelite) (push) Has been cancelled
qemu port / build_and_test_arm (thumb) (push) Has been cancelled
qemu port / build_and_test_rv32 (push) Has been cancelled
renesas-ra port / build_renesas_ra_board (push) Has been cancelled
rp2 port / build (push) Has been cancelled
samd port / build (push) Has been cancelled
stm32 port / build_stm32 (stm32_misc_build) (push) Has been cancelled
stm32 port / build_stm32 (stm32_nucleo_build) (push) Has been cancelled
stm32 port / build_stm32 (stm32_pyb_build) (push) Has been cancelled
unix port / minimal (push) Has been cancelled
unix port / reproducible (push) Has been cancelled
unix port / standard (push) Has been cancelled
unix port / standard_v2 (push) Has been cancelled
unix port / coverage (push) Has been cancelled
unix port / coverage_32bit (push) Has been cancelled
unix port / nanbox (push) Has been cancelled
unix port / float (push) Has been cancelled
unix port / stackless_clang (push) Has been cancelled
unix port / float_clang (push) Has been cancelled
unix port / settrace_stackless (push) Has been cancelled
unix port / macos (push) Has been cancelled
unix port / qemu_mips (push) Has been cancelled
unix port / qemu_arm (push) Has been cancelled
unix port / qemu_riscv64 (push) Has been cancelled
unix port / sanitize_address (push) Has been cancelled
unix port / sanitize_undefined (push) Has been cancelled
webassembly port / build (push) Has been cancelled
windows port / build-vs (Debug, x64, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Debug, x64, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Debug, x86, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Debug, x86, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x64, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x64, dev, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x64, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x64, standard, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x64, standard, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x64, standard, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x86, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x86, dev, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x86, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x86, standard, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x86, standard, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x86, standard, 2022, [17, 18)) (push) Has been cancelled
windows port / build-mingw (i686, mingw32, dev) (push) Has been cancelled
windows port / build-mingw (i686, mingw32, standard) (push) Has been cancelled
windows port / build-mingw (x86_64, mingw64, dev) (push) Has been cancelled
windows port / build-mingw (x86_64, mingw64, standard) (push) Has been cancelled
windows port / cross-build-on-linux (push) Has been cancelled
zephyr port / build (push) Has been cancelled
Python code lint and formatting with ruff / ruff (push) Has been cancelled
shared/timeutils: Standardize supported date range on all platforms.
This is code makes sure that time functions work properly on a
reasonable date range, on all platforms, regardless of the epoch.
The suggested minimum range is 1970 to 2099.

In order to reduce code footprint, code to support far away dates
is only enabled specified by the port.

New types are defined to identify timestamps.

The implementation with the smallest code footprint is when
support timerange is limited to 1970-2099 and Epoch is 1970.
This makes it possible to use 32 bit unsigned integers for
all timestamps.

On ARM4F, adding support for dates up to year 3000 adds
460 bytes of code. Supporting dates back to 1600 adds
another 44 bytes of code.

Signed-off-by: Yoctopuce dev <dev@yoctopuce.com>
2025-07-09 11:54:21 +10:00

121 lines
4.0 KiB
Python

# test conversion from date tuple to timestamp and back
try:
import time
time.localtime
except (ImportError, AttributeError):
print("SKIP")
raise SystemExit
# Range of date expected to work on all MicroPython platforms
MIN_YEAR = 1970
MAX_YEAR = 2099
# CPython properly supported date range:
# - on Windows: year 1970 to 3000+
# - on Unix: year 1583 to 3000+
# Start test from Jan 1, 2001 13:00 (Feb 2000 might already be broken)
SAFE_DATE = (2001, 1, 1, 13, 0, 0, 0, 0, -1)
# mktime function that checks that the result is reversible
def safe_mktime(date_tuple):
try:
res = time.mktime(date_tuple)
chk = time.localtime(res)
except OverflowError:
print("safe_mktime:", date_tuple, "overflow error")
return None
if chk[0:5] != date_tuple[0:5]:
print("safe_mktime:", date_tuple[0:5], " -> ", res, " -> ", chk[0:5])
return None
return res
# localtime function that checks that the result is reversible
def safe_localtime(timestamp):
try:
res = time.localtime(timestamp)
chk = time.mktime(res)
except OverflowError:
print("safe_localtime:", timestamp, "overflow error")
return None
if chk != timestamp:
print("safe_localtime:", timestamp, " -> ", res, " -> ", chk)
return None
return res
# look for smallest valid timestamps by iterating backwards on tuple
def test_bwd(date_tuple):
curr_stamp = safe_mktime(date_tuple)
year = date_tuple[0]
month = date_tuple[1] - 1
if month < 1:
year -= 1
month = 12
while year >= MIN_YEAR:
while month >= 1:
next_tuple = (year, month) + date_tuple[2:]
next_stamp = safe_mktime(next_tuple)
# at this stage, only test consistency and monotonicity
if next_stamp is None or next_stamp >= curr_stamp:
return date_tuple
date_tuple = next_tuple
curr_stamp = next_stamp
month -= 1
year -= 1
month = 12
return date_tuple
# test day-by-day to ensure that every date is properly converted
def test_fwd(start_date):
DAYS_PER_MONTH = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
curr_stamp = safe_mktime(start_date)
curr_date = safe_localtime(curr_stamp)
while curr_date[0] <= MAX_YEAR:
if curr_date[2] < 15:
skip_days = 13
else:
skip_days = 1
next_stamp = curr_stamp + skip_days * 86400
next_date = safe_localtime(next_stamp)
if next_date is None:
return curr_date
if next_date[2] != curr_date[2] + skip_days:
# next month
if next_date[2] != 1:
print("wrong day of month:", next_date)
return curr_date
# check the number of days in previous month
month_days = DAYS_PER_MONTH[curr_date[1]]
if month_days == 28 and curr_date[0] % 4 == 0:
if curr_date[0] % 100 != 0 or curr_date[0] % 400 == 0:
month_days += 1
if curr_date[2] != month_days:
print("wrong day count in prev month:", curr_date[2], "vs", month_days)
return curr_date
if next_date[1] != curr_date[1] + 1:
# next year
if curr_date[1] != 12:
print("wrong month count in prev year:", curr_date[1])
return curr_date
if next_date[1] != 1:
print("wrong month:", next_date)
return curr_date
if next_date[0] != curr_date[0] + 1:
print("wrong year:", next_date)
return curr_date
curr_stamp = next_stamp
curr_date = next_date
return curr_date
small_date = test_bwd(SAFE_DATE)
large_date = test_fwd(small_date)
print("tested from", small_date[0:3], "to", large_date[0:3])
print(small_date[0:3], "wday is", small_date[6])
print(large_date[0:3], "wday is", large_date[6])