1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

periph_common/rtc: add rtc_mktime()

Add a function to convert a time struct to an unsigned timestamp (non-UNIX).
This commit is contained in:
Benjamin Valentin 2020-02-04 15:08:03 +01:00 committed by Benjamin Valentin
parent 6dd69e7134
commit becff61e20
3 changed files with 85 additions and 1 deletions

View File

@ -37,6 +37,7 @@
#ifndef PERIPH_RTC_H
#define PERIPH_RTC_H
#include <stdint.h>
#include <time.h>
#include "periph_conf.h"
@ -147,6 +148,19 @@ void rtc_tm_normalize(struct tm *time);
*/
int rtc_tm_compare(const struct tm *a, const struct tm *b);
/**
* @brief Convert time struct into timestamp.
*
* @pre The time structs @p a and @p b are assumed to be normalized.
* Use @ref rtc_tm_normalize to normalize a struct tm that has been
* manually edited.
*
* @param[in] t The time struct to convert
*
* @return elapsed seconds since `RIOT_EPOCH`
*/
uint32_t rtc_mktime(struct tm *t);
#ifdef __cplusplus
}
#endif

View File

@ -26,6 +26,14 @@
#define RTC_NORMALIZE_COMPAT (0)
#endif
#define MINUTE (60U)
#define HOUR (60U * MINUTE)
#define DAY (24U * HOUR)
#ifndef RIOT_EPOCH
#define RIOT_EPOCH (2020)
#endif
/*
* The rules here are (to be checked in that explicit order):
* 1. If the year is not a multiple of four, it is not a leap year.
@ -52,6 +60,26 @@ static int _is_leap_year(int year)
return !!(year % 25) || !(year & 15);
}
/*
* 1. Every fourth year was a leap year.
* 2. Subtract all years divisible by 100, those are divisible by 4 but no leap years.
* 3. Add back all years divisible by 400, those are divisible by 100 but leap years.
*/
static unsigned _leap_years_before(unsigned year)
{
--year;
return (year / 4) - (year / 100) + (year / 400);
}
static unsigned _leap_years_since_epoch(unsigned year)
{
if (year < RIOT_EPOCH) {
return 0;
}
return _leap_years_before(year) - _leap_years_before(RIOT_EPOCH);
}
static int _month_length(int month, int year)
{
if (month == 1) {
@ -81,6 +109,7 @@ static int _wday(int day, int month, int year)
year -= month < 2;
return (year + year/4 - year/100 + year/400 + t[month] + day) % 7;
}
#endif /* RTC_NORMALIZE_COMPAT */
static int _yday(int day, int month, int year)
{
@ -104,7 +133,6 @@ static int _yday(int day, int month, int year)
2019-01-01 will be be day 0 in year 2019 */
return d[month] + day - 1;
}
#endif /* RTC_NORMALIZE_COMPAT */
void rtc_tm_normalize(struct tm *t)
{
@ -148,6 +176,22 @@ void rtc_tm_normalize(struct tm *t)
#endif
}
uint32_t rtc_mktime(struct tm *t)
{
unsigned year = t->tm_year + 1900;
uint32_t time = t->tm_sec
+ t->tm_min * MINUTE
+ t->tm_hour * HOUR
+ _yday(t->tm_mday, t->tm_mon, year) * DAY;
unsigned leap_years = _leap_years_since_epoch(year);
unsigned common_years = (year - RIOT_EPOCH) - leap_years;
time += (leap_years * 366 + common_years * 365) * DAY;
return time;
}
#define RETURN_IF_DIFFERENT(a, b, member) \
if (a->member != b->member) { \
return a->member-b->member; \

View File

@ -199,6 +199,31 @@ static void test_rtc_compare(void)
TEST_ASSERT(rtc_tm_compare(&t1, &t2) < 0);
}
static void test_rtc_mktime(void)
{
struct tm t = {
.tm_sec = 11,
.tm_min = 12,
.tm_hour = 13,
.tm_mday = 1,
.tm_mon = 0,
.tm_year = 120,
.tm_wday = 0,
.tm_yday = 1,
};
mktime(&t);
TEST_ASSERT_EQUAL_INT(47531, rtc_mktime(&t));
t.tm_mday += 40;
mktime(&t);
TEST_ASSERT_EQUAL_INT(3503531, rtc_mktime(&t));
t.tm_year += 3;
mktime(&t);
TEST_ASSERT_EQUAL_INT(98197931, rtc_mktime(&t));
}
Test *tests_rtc_tests(void)
{
EMB_UNIT_TESTFIXTURES(fixtures) {
@ -209,6 +234,7 @@ Test *tests_rtc_tests(void)
new_TestFixture(test_rtc_ywrap),
new_TestFixture(test_rtc_year),
new_TestFixture(test_rtc_compare),
new_TestFixture(test_rtc_mktime),
};
EMB_UNIT_TESTCALLER(rtc_tests, NULL, NULL, fixtures);