8000 unix/modtime: Add mktime function. · micropython/micropython@8c3956a · GitHub
[go: up one dir, main page]

Skip to content

Commit 8c3956a

Browse files
committed
unix/modtime: Add mktime function.
Also applies to windows port.
1 parent 1e2f751 commit 8c3956a

File tree

3 files changed

+156
-0
lines changed

3 files changed

+156
-0
lines changed

ports/unix/modtime.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include <sys/time.h>
3636
#include <math.h>
3737

38+
#include "py/runtime.h"
3839
#include "py/runtime.h"
3940
#include "py/smallint.h"
4041
#include "py/mphal.h"
@@ -161,6 +162,38 @@ STATIC mp_obj_t mod_time_localtime(size_t n_args, const mp_obj_t *args) {
161162
}
162163
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_time_localtime_obj, 0, 1, mod_time_localtime);
163164

165+
STATIC mp_obj_t mod_time_mktime(mp_obj_t tuple) {
166+
size_t len;
167+
mp_obj_t *elem;
168+
mp_obj_get_array(tuple, &len, &elem);
169+
170+
// localtime generates a tuple of len 8. CPython uses 9, so we accept both.
171+
if (len < 8 || len > 9) {
172+
mp_raise_TypeError("mktime needs a tuple of length 8 or 9");
173+
}
174+
175+
struct tm time = {
176+
.tm_year = mp_obj_get_int(elem[0]) - 1900,
177+
.tm_mon = mp_obj_get_int(elem[1]) - 1,
178+
.tm_mday = mp_obj_get_int(elem[2]),
179+
.tm_hour = mp_obj_get_int(elem[3]),
180+
.tm_min = mp_obj_get_int(elem[4]),
181+
.tm_sec = mp_obj_get_int(elem[5]),
182+
};
183+
if (len == 9) {
184+
time.tm_isdst = mp_obj_get_int(elem[8]);
185+
} else {
186+
time.tm_isdst = -1; // auto-detect
187+
}
188+
time_t ret = mktime(&time);
189+
if (ret == -1) {
190+
mp_raise_msg(&mp_type_OverflowError, "invalid mktime usage");
191+
}
192+
return mp_obj_new_int(ret);
193+
}
194+
MP_DEFINE_CONST_FUN_OBJ_1(mod_time_mktime_obj, mod_time_mktime);
195+
196+
164197
STATIC const mp_rom_map_elem_t mp_module_time_globals_table[] = {
165198
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) },
166199
{ MP_ROM_QSTR(MP_QSTR_clock), MP_ROM_PTR(&mod_time_clock_obj) },
@@ -174,6 +207,7 @@ STATIC const mp_rom_map_elem_t mp_module_time_globals_table[] = {
174207
{ MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) },
175208
{ MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) },
176209
{ MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&mod_time_localtime_obj) },
210+
{ MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&mod_time_mktime_obj) },
177211
};
178212

179213
STATIC MP_DEFINE_CONST_DICT(mp_module_time_globals, mp_module_time_globals_table);

tests/unix/time.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import utime as time
2+
import uos
3+
4+
DAYS_PER_MONTH = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
5+
6+
def get_timezone():
7+
"""
8+
Read the computer timezone hour offset in jan and jul and return the lowest (without dst)
9+
"""
10+
uos.system('date -d "1 Jan" +"%z" > .tzinfo; date -d "1 Jul" +"%z" >> .tzinfo')
11+
seconds = []
12+
with open('.tzinfo') as _tzinfo:
13+
for tzstring in _tzinfo:
14+
if tzstring:
15+
seconds.append(((int(tzstring[:-3]) * 60) + int(tzstring[-3:])) * 60)
16+
return min(*seconds)
17+
18+
tzseconds = get_timezone()
19+
20+
def is_leap(year):
21+
return (year % 4) == 0
22+
23+
def test():
24+
seconds = 0
25+
wday = 3 # Jan 1, 1970 was a Thursday
26+
for year in range(1970, 2038):
27+
print("Testing %d" % year)
28+
yday = 1
29+
for month in range(1, 13):
30+
if month == 2 and is_leap(year):
31+
DAYS_PER_MONTH[2] = 29
32+
else:
33+
DAYS_PER_MONTH[2] = 28
34+
for day in range(1, DAYS_PER_MONTH[month] + 1):
35+
secs = time.mktime((year, month, day, 0, 0, 0, 0, 0, 0)) + tzseconds
36+
if secs != seconds:
37+
print("mktime failed for %d-%02d-%02d got %d expected %d" % (year, month, day, secs, seconds))
38+
return
39+
tuple = time.localtime(seconds)
40+
secs = time.mktime(tuple)
41+
if secs != seconds:
42+
print("localtime failed for %d-%02d-%02d got %d expected %d" % (year, month, day, secs, seconds))
43+
return
44+
seconds += 86400
45+
if yday != tuple[7]:
46+
print("locatime for %d-%02d-%02d got yday %d, expecting %d" % (year, month, day, tuple[7], yday))
47+
return
48+
if wday != tuple[6]:
49+
print("locatime for %d-%02d-%02d got wday %d, expecting %d" % (year, month, day, tuple[6], wday))
50+
return
51+
yday += 1
52+
wday = (wday + 1) % 7
53+
54+
test()

tests/unix/time.py.exp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
Testing 1970
2+
Testing 1971
3+
Testing 1972
4+
Testing 1973
5+
Testing 1974
6+
Testing 1975
7+
Testing 1976
8+
Testing 1977
9+
Testing 1978
10+
Testing 1979
11+
Testing 1980
12+
Testing 1981
13+
Testing 1982
14+
Testing 1983
15+
Testing 1984
16+
Testing 1985
17+
Testing 1986
18+
Testing 1987
19+
Testing 1988
20+
Testing 1989
21+
Testing 1990
22+
Testing 1991
23+
Testing 1992
24+
Testing 1993
25+
Testing 1994
26+
Testing 1995
27+
Testing 1996
28+
Testing 1997
29+
Testing 1998
30+
Testing 1999
31+
Testing 2000
32+
Testing 2001
33+
Testing 2002
34+
Testing 2003
35+
Testing 2004
36+
Testing 2005
37+
Testing 2006
38+
Testing 2007
39+
Testing 2008
40+
Testing 2009
41+
Testing 2010
42+
Testing 2011
43+
Testing 2012
44+
Testing 2013
45+
Testing 2014
46+
Testing 2015
47+
Testing 2016
48+
Testing 2017
49+
Testing 2018
50+
Testing 2019
51+
Testing 2020
52+
Testing 2021
53+
Testing 2022
54+
Testing 2023
55+
Testing 2024
56+
Testing 2025
57+
Testing 2026
58+
Testing 2027
59+
Testing 2028
60+
Testing 2029
61+
Testing 2030
62+
Testing 2031
63+
Testing 2032
64+
Testing 2033
65+
Testing 2034
66+
Testing 2035
67+
Testing 2036
68+
Testing 2037

0 commit comments

Comments
 (0)
0