Commit 8ba83245 authored by Damien George's avatar Damien George
Browse files

stmhal, modtime: Small changes, reduced code size by around 80 bytes.

Also added test for modtime.
parent 6678595e
...@@ -36,21 +36,6 @@ ...@@ -36,21 +36,6 @@
#include "portmodules.h" #include "portmodules.h"
#include "rtc.h" #include "rtc.h"
#define DAYS_PER_400Y (365*400 + 97)
#define DAYS_PER_100Y (365*100 + 24)
#define DAYS_PER_4Y (365*4 + 1)
typedef struct {
uint16_t tm_year; // i.e. 2014
uint8_t tm_mon; // 1..12
uint8_t tm_mday; // 1..31
uint8_t tm_hour; // 0..23
uint8_t tm_min; // 0..59
uint8_t tm_sec; // 0..59
uint8_t tm_wday; // 0..6 0 = Monday
uint16_t tm_yday; // 1..366
} mod_struct_time;
/// \module time - time related functions /// \module time - time related functions
/// ///
/// The `time` module provides functions for getting the current time and date, /// The `time` module provides functions for getting the current time and date,
...@@ -63,7 +48,7 @@ STATIC bool is_leap_year(mp_uint_t year) { ...@@ -63,7 +48,7 @@ STATIC bool is_leap_year(mp_uint_t year) {
} }
// Month is one based // Month is one based
STATIC mp_uint_t days_in_month(mp_uint_t year, mp_uint_t month) { STATIC mp_uint_t mod_time_days_in_month(mp_uint_t year, mp_uint_t month) {
mp_uint_t mdays = days_since_jan1[month] - days_since_jan1[month - 1]; mp_uint_t mdays = days_since_jan1[month] - days_since_jan1[month - 1];
if (month == 2 && is_leap_year(year)) { if (month == 2 && is_leap_year(year)) {
mdays++; mdays++;
...@@ -73,7 +58,7 @@ STATIC mp_uint_t days_in_month(mp_uint_t year, mp_uint_t month) { ...@@ -73,7 +58,7 @@ STATIC mp_uint_t days_in_month(mp_uint_t year, mp_uint_t month) {
// compute the day of the year, between 1 and 366 // compute the day of the year, between 1 and 366
// month should be between 1 and 12, date should start at 1 // month should be between 1 and 12, date should start at 1
mp_uint_t mod_time_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date) { STATIC mp_uint_t mod_time_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date) {
mp_uint_t yday = days_since_jan1[month - 1] + date; mp_uint_t yday = days_since_jan1[month - 1] + date;
if (month >= 3 && is_leap_year(year)) { if (month >= 3 && is_leap_year(year)) {
yday += 1; yday += 1;
...@@ -102,11 +87,24 @@ mp_uint_t mod_time_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t ...@@ -102,11 +87,24 @@ mp_uint_t mod_time_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t
#define LEAPOCH ((31 + 29) * 86400) #define LEAPOCH ((31 + 29) * 86400)
void mod_time_seconds_since_2000_to_struct_time(mp_uint_t t, mod_struct_time *tm) { #define DAYS_PER_400Y (365*400 + 97)
memset(tm, 0, sizeof(*tm)); #define DAYS_PER_100Y (365*100 + 24)
#define DAYS_PER_4Y (365*4 + 1)
typedef struct {
uint16_t tm_year; // i.e. 2014
uint8_t tm_mon; // 1..12
uint8_t tm_mday; // 1..31
uint8_t tm_hour; // 0..23
uint8_t tm_min; // 0..59
uint8_t tm_sec; // 0..59
uint8_t tm_wday; // 0..6 0 = Monday
uint16_t tm_yday; // 1..366
} mod_struct_time;
STATIC void mod_time_seconds_since_2000_to_struct_time(mp_uint_t t, mod_struct_time *tm) {
// The following algorithm was adapted from musl's __secs_to_tm and adapted // The following algorithm was adapted from musl's __secs_to_tm and adapted
// for differences in MicroPython's timebase. // for differences in Micro Python's timebase.
mp_int_t seconds = t - LEAPOCH; mp_int_t seconds = t - LEAPOCH;
...@@ -146,6 +144,7 @@ void mod_time_seconds_since_2000_to_struct_time(mp_uint_t t, mod_struct_time *tm ...@@ -146,6 +144,7 @@ void mod_time_seconds_since_2000_to_struct_time(mp_uint_t t, mod_struct_time *tm
} }
days -= (years * 365); days -= (years * 365);
/* We will compute tm_yday at the very end
mp_int_t leap = !years && (q_cycles || !c_cycles); mp_int_t leap = !years && (q_cycles || !c_cycles);
tm->tm_yday = days + 31 + 28 + leap; tm->tm_yday = days + 31 + 28 + leap;
...@@ -153,10 +152,13 @@ void mod_time_seconds_since_2000_to_struct_time(mp_uint_t t, mod_struct_time *tm ...@@ -153,10 +152,13 @@ void mod_time_seconds_since_2000_to_struct_time(mp_uint_t t, mod_struct_time *tm
tm->tm_yday -= 365 + leap; tm->tm_yday -= 365 + leap;
} }
tm->tm_yday++; // Make one based
*/
tm->tm_year = 2000 + years + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles; tm->tm_year = 2000 + years + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles;
// Note: days_in_month[0] corresponds to March // Note: days_in_month[0] corresponds to March
static const int8_t days_in_month[] = {31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29}; STATIC const int8_t days_in_month[] = {31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29};
mp_int_t month; mp_int_t month;
for (month = 0; days_in_month[month] <= days; month++) { for (month = 0; days_in_month[month] <= days; month++) {
...@@ -170,9 +172,9 @@ void mod_time_seconds_since_2000_to_struct_time(mp_uint_t t, mod_struct_time *tm ...@@ -170,9 +172,9 @@ void mod_time_seconds_since_2000_to_struct_time(mp_uint_t t, mod_struct_time *tm
} }
tm->tm_mday = days + 1; // Make one based tm->tm_mday = days + 1; // Make one based
tm->tm_mon++; // Make one based tm->tm_mon++; // Make one based
tm->tm_yday++; // Make one based
}
tm->tm_yday = mod_time_year_day(tm->tm_year, tm->tm_mon, tm->tm_mday);
}
/// \function localtime([secs]) /// \function localtime([secs])
/// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which /// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which
...@@ -205,22 +207,22 @@ STATIC mp_obj_t time_localtime(uint n_args, const mp_obj_t *args) { ...@@ -205,22 +207,22 @@ STATIC mp_obj_t time_localtime(uint n_args, const mp_obj_t *args) {
mp_obj_new_int(mod_time_year_day(2000 + date.Year, date.Month, date.Date)), mp_obj_new_int(mod_time_year_day(2000 + date.Year, date.Month, date.Date)),
}; };
return mp_obj_new_tuple(8, tuple); return mp_obj_new_tuple(8, tuple);
} else {
mp_int_t seconds = mp_obj_get_int(args[0]);
mod_struct_time tm;
mod_time_seconds_since_2000_to_struct_time(seconds, &tm);
mp_obj_t tuple[8] = {
tuple[0] = mp_obj_new_int(tm.tm_year),
tuple[1] = mp_obj_new_int(tm.tm_mon),
tuple[2] = mp_obj_new_int(tm.tm_mday),
tuple[3] = mp_obj_new_int(tm.tm_hour),
tuple[4] = mp_obj_new_int(tm.tm_min),
tuple[5] = mp_obj_new_int(tm.tm_sec),
tuple[6] = mp_obj_new_int(tm.tm_wday),
tuple[7] = mp_obj_new_int(tm.tm_yday),
};
return mp_obj_new_tuple(8, tuple);
} }
mp_int_t seconds = mp_obj_get_int(args[0]);
mod_struct_time tm;
mod_time_seconds_since_2000_to_struct_time(seconds, &tm);
mp_obj_t tuple[8] = {
mp_obj_new_int(tm.tm_year),
mp_obj_new_int(tm.tm_mon),
mp_obj_new_int(tm.tm_mday),
mp_obj_new_int(tm.tm_hour),
mp_obj_new_int(tm.tm_min),
mp_obj_new_int(tm.tm_sec),
mp_obj_new_int(tm.tm_wday),
mp_obj_new_int(tm.tm_yday),
};
return mp_obj_new_tuple(8, tuple);
} }
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime);
...@@ -248,12 +250,12 @@ STATIC mp_obj_t time_mktime(mp_obj_t tuple) { ...@@ -248,12 +250,12 @@ STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
mp_int_t minutes = mp_obj_get_int(elem[4]); mp_int_t minutes = mp_obj_get_int(elem[4]);
mp_int_t seconds = mp_obj_get_int(elem[5]); mp_int_t seconds = mp_obj_get_int(elem[5]);
// Normalize the tuple. This allows things like: // Normalise the tuple. This allows things like:
// //
// tm_tomorrow = list(time.localtime()) // tm_tomorrow = list(time.localtime())
// tm_tomorrow[2] += 1 # Adds 1 to mday // tm_tomorrow[2] += 1 # Adds 1 to mday
// tomorrow = time.mktime(tm_tommorrow) // tomorrow = time.mktime(tm_tommorrow)
// //
// And not have to worry about all the weird overflows. // And not have to worry about all the weird overflows.
// //
// You can subtract dates/times this way as well. // You can subtract dates/times this way as well.
...@@ -289,10 +291,10 @@ STATIC mp_obj_t time_mktime(mp_obj_t tuple) { ...@@ -289,10 +291,10 @@ STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
month = 12; month = 12;
year--; year--;
} }
mday += days_in_month(year, month); mday += mod_time_days_in_month(year, month);
} }
while (mday > days_in_month(year, month)) { while (mday > mod_time_days_in_month(year, month)) {
mday -= days_in_month(year, month); mday -= mod_time_days_in_month(year, month);
if (++month == 13) { if (++month == 13) {
month = 1; month = 1;
year++; year++;
......
...@@ -31,5 +31,4 @@ extern const mp_obj_module_t time_module; ...@@ -31,5 +31,4 @@ extern const mp_obj_module_t time_module;
// additional helper functions exported by the modules // additional helper functions exported by the modules
mp_uint_t mod_time_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date);
mp_uint_t mod_time_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second); mp_uint_t mod_time_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second);
import time
DAYS_PER_MONTH = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
def is_leap(year):
return (year % 4) == 0
def test():
seconds = 0
wday = 5 # Jan 1, 2000 was a Saturday
for year in range(2000, 2034):
print("Testing %d" % year)
yday = 1
for month in range(1, 13):
if month == 2 and is_leap(year):
DAYS_PER_MONTH[2] = 29
else:
DAYS_PER_MONTH[2] = 28
for day in range(1, DAYS_PER_MONTH[month] + 1):
secs = time.mktime((year, month, day, 0, 0, 0, 0, 0))
if secs != seconds:
print("mktime failed for %d-%02d-%02d got %d expected %d" % (year, month, day, secs, seconds))
tuple = time.localtime(seconds)
secs = time.mktime(tuple)
if secs != seconds:
print("localtime failed for %d-%02d-%02d got %d expected %d" % (year, month, day, secs, seconds))
return
seconds += 86400
if yday != tuple[7]:
print("locatime for %d-%02d-%02d got yday %d, expecting %d" % (year, month, day, tuple[7], yday))
return
if wday != tuple[6]:
print("locatime for %d-%02d-%02d got wday %d, expecting %d" % (year, month, day, tuple[6], wday))
return
yday += 1
wday = (wday + 1) % 7
test()
Testing 2000
Testing 2001
Testing 2002
Testing 2003
Testing 2004
Testing 2005
Testing 2006
Testing 2007
Testing 2008
Testing 2009
Testing 2010
Testing 2011
Testing 2012
Testing 2013
Testing 2014
Testing 2015
Testing 2016
Testing 2017
Testing 2018
Testing 2019
Testing 2020
Testing 2021
Testing 2022
Testing 2023
Testing 2024
Testing 2025
Testing 2026
Testing 2027
Testing 2028
Testing 2029
Testing 2030
Testing 2031
Testing 2032
Testing 2033
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment