diff --git a/app/include/rtc/rtctime.h b/app/include/rtc/rtctime.h index f8a94b7b..3677b949 100644 --- a/app/include/rtc/rtctime.h +++ b/app/include/rtc/rtctime.h @@ -49,6 +49,17 @@ struct rtc_timeval }; #endif +struct rtc_tm{ + int tm_sec; /* Seconds. [0-60] (1 leap second) */ + int tm_min; /* Minutes. [0-59] */ + int tm_hour; /* Hours. [0-23] */ + int tm_mday; /* Day. [1-31] */ + int tm_mon; /* Month. [0-11] */ + int tm_year; /* Year - 1900. */ + int tm_wday; /* Day of week. [0-6] */ + int tm_yday; /* Days in year.[0-365] */ +}; + void TEXT_SECTION_ATTR rtctime_early_startup (void); void rtctime_late_startup (void); void rtctime_gettimeofday (struct rtc_timeval *tv); @@ -56,5 +67,6 @@ void rtctime_settimeofday (const struct rtc_timeval *tv); bool rtctime_have_time (void); void rtctime_deep_sleep_us (uint32_t us); void rtctime_deep_sleep_until_aligned_us (uint32_t align_us, uint32_t min_us); +void rtctime_gmtime (const int32 stamp, struct rtc_tm *r); #endif diff --git a/app/modules/rtctime.c b/app/modules/rtctime.c index 9d3d0a6e..6505bb2d 100644 --- a/app/modules/rtctime.c +++ b/app/modules/rtctime.c @@ -7,6 +7,33 @@ #include "rtc/rtctime.h" +/* seconds per day */ +#define SPD 24*60*60 + +/* days per month -- nonleap! */ +static const short __spm[13] = + { 0, + (31), + (31+28), + (31+28+31), + (31+28+31+30), + (31+28+31+30+31), + (31+28+31+30+31+30), + (31+28+31+30+31+30+31), + (31+28+31+30+31+30+31+31), + (31+28+31+30+31+30+31+31+30), + (31+28+31+30+31+30+31+31+30+31), + (31+28+31+30+31+30+31+31+30+31+30), + (31+28+31+30+31+30+31+31+30+31+30+31), + }; + +static int __isleap (int year) { + /* every fourth year is a leap year except for century years that are + * not divisible by 400. */ + /* return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); */ + return (!(year % 4) && ((year % 100) || !(year % 400))); +} + // ******* C API functions ************* void rtctime_early_startup (void) @@ -49,6 +76,36 @@ void rtctime_deep_sleep_until_aligned_us (uint32_t align_us, uint32_t min_us) rtc_time_deep_sleep_until_aligned (align_us, min_us); } +void rtctime_gmtime (const int32 stamp, struct rtc_tm *r) +{ + int32_t i; + int32_t work = stamp % (SPD); + r->tm_sec = work % 60; work /= 60; + r->tm_min = work % 60; r->tm_hour = work / 60; + work = stamp / (SPD); + r->tm_wday = (4 + work) % 7; + for (i = 1970; ; ++i) { + int32_t k = __isleap (i) ? 366 : 365; + if (work >= k) { + work -= k; + } else { + break; + } + } + r->tm_year = i - 1900; + r->tm_yday = work; + + r->tm_mday = 1; + if (__isleap (i) && (work > 58)) { + if (work == 59) r->tm_mday = 2; /* 29.2. */ + work -= 1; + } + + for (i = 11; i && (__spm[i] > work); --i) ; + r->tm_mon = i; + r->tm_mday += work - __spm[i]; +} + // ******* Lua API functions ************* @@ -115,12 +172,43 @@ static int rtctime_dsleep_aligned (lua_State *L) } +static void add_table_item (lua_State *L, const char *key, int val) +{ + lua_pushstring (L, key); + lua_pushinteger (L, val); + lua_rawset (L, -3); +} + +// rtctime.epoch2cal (stamp) +static int rtctime_epoch2cal (lua_State *L) +{ + struct rtc_tm date; + int32_t stamp = luaL_checkint (L, 1); + luaL_argcheck (L, stamp >= 0, 1, "wrong arg range"); + + rtctime_gmtime (stamp, &date); + + /* construct Lua table */ + lua_createtable (L, 0, 8); + add_table_item (L, "yday", date.tm_yday + 1); + add_table_item (L, "wday", date.tm_wday + 1); + add_table_item (L, "year", date.tm_year + 1900); + add_table_item (L, "mon", date.tm_mon + 1); + add_table_item (L, "day", date.tm_mday); + add_table_item (L, "hour", date.tm_hour); + add_table_item (L, "min", date.tm_min); + add_table_item (L, "sec", date.tm_sec); + + return 1; +} + // Module function map static const LUA_REG_TYPE rtctime_map[] = { { LSTRKEY("set"), LFUNCVAL(rtctime_set) }, { LSTRKEY("get"), LFUNCVAL(rtctime_get) }, { LSTRKEY("dsleep"), LFUNCVAL(rtctime_dsleep) }, { LSTRKEY("dsleep_aligned"), LFUNCVAL(rtctime_dsleep_aligned) }, + { LSTRKEY("epoch2cal"), LFUNCVAL(rtctime_epoch2cal) }, { LNILKEY, LNILVAL } }; diff --git a/docs/en/modules/rtctime.md b/docs/en/modules/rtctime.md index ea175c0c..be63d547 100644 --- a/docs/en/modules/rtctime.md +++ b/docs/en/modules/rtctime.md @@ -67,6 +67,34 @@ For applications where it is necessary to take samples with high regularity, thi rtctime.dsleep_aligned(5*1000000, 3*1000000) ``` +## rtctime.epoch2cal() + +Converts a Unix timestamp to calendar format. Neither timezone nor DST correction is performed - the result is UTC time. + +#### Syntax +`rtctime.epoch2cal(timestamp)` + +#### Parameters +`timestamp` seconds since Unix epoch + +#### Returns +A table containing the fields: + +- `year` 1970 ~ 2038 +- `mon` month 1 ~ 12 in current year +- `day` day 1 ~ 31 in current month +- `hour` +- `min` +- `sec` +- `yday` day 1 ~ 366 in current year +- `wday` day 1 ~ 7 in current weak (Sunday is 1) + +#### Example +```lua +tm = rtctime.epoch2cal(rtctime.get()) +print(string.format("%04d/%02d/%02d %02d:%02d:%02d", tm["year"], tm["mon"], tm["day"], tm["hour"], tm["min"], tm["sec"])) +``` + ## rtctime.get() Returns the current time. If current time is not available, zero is returned. @@ -114,4 +142,4 @@ Values very close to the epoch are not supported. This is a side effect of keepi rtctime.set(1436430589, 0) ``` #### See also -[`sntp.sync()`](sntp.md#sntpsync) \ No newline at end of file +[`sntp.sync()`](sntp.md#sntpsync)