Browse Source

Add rtctime.epoch2cal() (#1386)

Arnim Läuger 8 years ago
parent
commit
56839fb20b
3 changed files with 129 additions and 1 deletions
  1. 12 0
      app/include/rtc/rtctime.h
  2. 88 0
      app/modules/rtctime.c
  3. 29 1
      docs/en/modules/rtctime.md

+ 12 - 0
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

+ 88 - 0
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 }
 };
 

+ 29 - 1
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)
+[`sntp.sync()`](sntp.md#sntpsync)