Branch data Line data Source code
1 : : /*
2 : : * This file is part of the MicroPython project, http://micropython.org/
3 : : *
4 : : * The MIT License (MIT)
5 : : *
6 : : * Copyright (c) 2014-2017 Paul Sokolovsky
7 : : * Copyright (c) 2014-2023 Damien P. George
8 : : *
9 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
10 : : * of this software and associated documentation files (the "Software"), to deal
11 : : * in the Software without restriction, including without limitation the rights
12 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 : : * copies of the Software, and to permit persons to whom the Software is
14 : : * furnished to do so, subject to the following conditions:
15 : : *
16 : : * The above copyright notice and this permission notice shall be included in
17 : : * all copies or substantial portions of the Software.
18 : : *
19 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 : : * THE SOFTWARE.
26 : : */
27 : :
28 : : #include <unistd.h>
29 : : #include <errno.h>
30 : : #include <string.h>
31 : : #include <time.h>
32 : : #include <sys/time.h>
33 : : #include <math.h>
34 : :
35 : : #include "py/mphal.h"
36 : : #include "py/runtime.h"
37 : :
38 : : #ifdef _WIN32
39 : : static inline int msec_sleep_tv(struct timeval *tv) {
40 : : msec_sleep(tv->tv_sec * 1000.0 + tv->tv_usec / 1000.0);
41 : : return 0;
42 : : }
43 : : #define sleep_select(a, b, c, d, e) msec_sleep_tv((e))
44 : : #else
45 : : #define sleep_select select
46 : : #endif
47 : :
48 : : // mingw32 defines CLOCKS_PER_SEC as ((clock_t)<somevalue>) but preprocessor does not handle casts
49 : : #if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
50 : : #define MP_REMOVE_BRACKETSA(x)
51 : : #define MP_REMOVE_BRACKETSB(x) MP_REMOVE_BRACKETSA x
52 : : #define MP_REMOVE_BRACKETSC(x) MP_REMOVE_BRACKETSB x
53 : : #define MP_CLOCKS_PER_SEC MP_REMOVE_BRACKETSC(CLOCKS_PER_SEC)
54 : : #else
55 : : #define MP_CLOCKS_PER_SEC CLOCKS_PER_SEC
56 : : #endif
57 : :
58 : : #if defined(MP_CLOCKS_PER_SEC)
59 : : #define CLOCK_DIV (MP_CLOCKS_PER_SEC / MICROPY_FLOAT_CONST(1000.0))
60 : : #else
61 : : #error Unsupported clock() implementation
62 : : #endif
63 : :
64 : 172 : static mp_obj_t mp_time_time_get(void) {
65 : : #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
66 : 172 : struct timeval tv;
67 : 172 : gettimeofday(&tv, NULL);
68 : 172 : mp_float_t val = tv.tv_sec + (mp_float_t)tv.tv_usec / 1000000;
69 : 172 : return mp_obj_new_float(val);
70 : : #else
71 : : return mp_obj_new_int((mp_int_t)time(NULL));
72 : : #endif
73 : : }
74 : :
75 : : // Note: this is deprecated since CPy3.3, but pystone still uses it.
76 : 0 : static mp_obj_t mod_time_clock(void) {
77 : : #if MICROPY_PY_BUILTINS_FLOAT
78 : : // float cannot represent full range of int32 precisely, so we pre-divide
79 : : // int to reduce resolution, and then actually do float division hoping
80 : : // to preserve integer part resolution.
81 : 0 : return mp_obj_new_float((clock() / 1000) / CLOCK_DIV);
82 : : #else
83 : : return mp_obj_new_int((mp_int_t)clock());
84 : : #endif
85 : : }
86 : : static MP_DEFINE_CONST_FUN_OBJ_0(mod_time_clock_obj, mod_time_clock);
87 : :
88 : 6704 : static mp_obj_t mp_time_sleep(mp_obj_t arg) {
89 : : #if MICROPY_PY_BUILTINS_FLOAT
90 : 6704 : struct timeval tv;
91 : 6704 : mp_float_t val = mp_obj_get_float(arg);
92 : 6704 : mp_float_t ipart;
93 : 6704 : tv.tv_usec = (time_t)MICROPY_FLOAT_C_FUN(round)(MICROPY_FLOAT_C_FUN(modf)(val, &ipart) * MICROPY_FLOAT_CONST(1000000.));
94 : 6704 : tv.tv_sec = (suseconds_t)ipart;
95 : 6708 : int res;
96 : 6712 : while (1) {
97 : 6708 : MP_THREAD_GIL_EXIT();
98 : 6708 : res = sleep_select(0, NULL, NULL, NULL, &tv);
99 : 6708 : MP_THREAD_GIL_ENTER();
100 : : #if MICROPY_SELECT_REMAINING_TIME
101 : : // TODO: This assumes Linux behavior of modifying tv to the remaining
102 : : // time.
103 [ + + + - ]: 6708 : if (res != -1 || errno != EINTR) {
104 : : break;
105 : : }
106 : 4 : mp_handle_pending(true);
107 : : // printf("select: EINTR: %ld:%ld\n", tv.tv_sec, tv.tv_usec);
108 : : #else
109 : : break;
110 : : #endif
111 : : }
112 [ - + ]: 6704 : RAISE_ERRNO(res, errno);
113 : : #else
114 : : int seconds = mp_obj_get_int(arg);
115 : : for (;;) {
116 : : MP_THREAD_GIL_EXIT();
117 : : seconds = sleep(seconds);
118 : : MP_THREAD_GIL_ENTER();
119 : : if (seconds == 0) {
120 : : break;
121 : : }
122 : : mp_handle_pending(true);
123 : : }
124 : : #endif
125 : 6704 : return mp_const_none;
126 : : }
127 : :
128 : 49874 : static mp_obj_t mod_time_gm_local_time(size_t n_args, const mp_obj_t *args, struct tm *(*time_func)(const time_t *timep)) {
129 : 49874 : time_t t;
130 [ + + ]: 49874 : if (n_args == 0) {
131 : 100 : t = time(NULL);
132 : : } else {
133 : : #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
134 : 49774 : mp_float_t val = mp_obj_get_float(args[0]);
135 : 49774 : t = (time_t)MICROPY_FLOAT_C_FUN(trunc)(val);
136 : : #else
137 : : t = mp_obj_get_int(args[0]);
138 : : #endif
139 : : }
140 : 49874 : struct tm *tm = time_func(&t);
141 : :
142 : 49874 : mp_obj_t ret = mp_obj_new_tuple(9, NULL);
143 : :
144 : 49874 : mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(ret);
145 : 49874 : tuple->items[0] = MP_OBJ_NEW_SMALL_INT(tm->tm_year + 1900);
146 : 49874 : tuple->items[1] = MP_OBJ_NEW_SMALL_INT(tm->tm_mon + 1);
147 : 49874 : tuple->items[2] = MP_OBJ_NEW_SMALL_INT(tm->tm_mday);
148 : 49874 : tuple->items[3] = MP_OBJ_NEW_SMALL_INT(tm->tm_hour);
149 : 49874 : tuple->items[4] = MP_OBJ_NEW_SMALL_INT(tm->tm_min);
150 : 49874 : tuple->items[5] = MP_OBJ_NEW_SMALL_INT(tm->tm_sec);
151 : 49874 : int wday = tm->tm_wday - 1;
152 [ + + ]: 49874 : if (wday < 0) {
153 : 7096 : wday = 6;
154 : : }
155 : 49874 : tuple->items[6] = MP_OBJ_NEW_SMALL_INT(wday);
156 : 49874 : tuple->items[7] = MP_OBJ_NEW_SMALL_INT(tm->tm_yday + 1);
157 : 49874 : tuple->items[8] = MP_OBJ_NEW_SMALL_INT(tm->tm_isdst);
158 : :
159 : 49874 : return ret;
160 : : }
161 : :
162 : 100 : static mp_obj_t mod_time_gmtime(size_t n_args, const mp_obj_t *args) {
163 : 100 : return mod_time_gm_local_time(n_args, args, gmtime);
164 : : }
165 : : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_time_gmtime_obj, 0, 1, mod_time_gmtime);
166 : :
167 : 49774 : static mp_obj_t mod_time_localtime(size_t n_args, const mp_obj_t *args) {
168 : 49774 : return mod_time_gm_local_time(n_args, args, localtime);
169 : : }
170 : : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_time_localtime_obj, 0, 1, mod_time_localtime);
171 : :
172 : 99350 : static mp_obj_t mod_time_mktime(mp_obj_t tuple) {
173 : 99350 : size_t len;
174 : 99350 : mp_obj_t *elem;
175 : 99350 : mp_obj_get_array(tuple, &len, &elem);
176 : :
177 : : // localtime generates a tuple of len 8. CPython uses 9, so we accept both.
178 [ - + ]: 99350 : if (len < 8 || len > 9) {
179 : 0 : mp_raise_TypeError(MP_ERROR_TEXT("mktime needs a tuple of length 8 or 9"));
180 : : }
181 : :
182 : 695450 : struct tm time = {
183 : 198700 : .tm_year = mp_obj_get_int(elem[0]) - 1900,
184 : 99350 : .tm_mon = mp_obj_get_int(elem[1]) - 1,
185 : 99350 : .tm_mday = mp_obj_get_int(elem[2]),
186 : 99350 : .tm_hour = mp_obj_get_int(elem[3]),
187 : 99350 : .tm_min = mp_obj_get_int(elem[4]),
188 : 99350 : .tm_sec = mp_obj_get_int(elem[5]),
189 : : };
190 [ + - ]: 99350 : if (len == 9) {
191 : 99350 : time.tm_isdst = mp_obj_get_int(elem[8]);
192 : : } else {
193 : 0 : time.tm_isdst = -1; // auto-detect
194 : : }
195 : 99350 : time_t ret = mktime(&time);
196 [ - + ]: 99350 : if (ret == -1) {
197 : 0 : mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("invalid mktime usage"));
198 : : }
199 : 99350 : return mp_obj_new_int(ret);
200 : : }
201 : : MP_DEFINE_CONST_FUN_OBJ_1(mod_time_mktime_obj, mod_time_mktime);
202 : :
203 : : #define MICROPY_PY_TIME_EXTRA_GLOBALS \
204 : : { MP_ROM_QSTR(MP_QSTR_clock), MP_ROM_PTR(&mod_time_clock_obj) }, \
205 : : { MP_ROM_QSTR(MP_QSTR_gmtime), MP_ROM_PTR(&mod_time_gmtime_obj) }, \
206 : : { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&mod_time_localtime_obj) }, \
207 : : { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&mod_time_mktime_obj) },
|