mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-24 03:29:57 -07:00
FuriHalRtc refactor: new datetime lib (#3386)
* datetimelib created * datetimelib unit tests added * firmware fixes to new datetimelib * typo fix * merge artifacts fixed, datetimelib renamed to datetime Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
22
lib/datetime/SConscript
Normal file
22
lib/datetime/SConscript
Normal file
@@ -0,0 +1,22 @@
|
||||
Import("env")
|
||||
|
||||
env.Append(
|
||||
LINT_SOURCES=[
|
||||
Dir("."),
|
||||
],
|
||||
CPPPATH=[
|
||||
"#/lib/datetime",
|
||||
],
|
||||
SDK_HEADERS=[
|
||||
File("datetime.h"),
|
||||
],
|
||||
)
|
||||
|
||||
libenv = env.Clone(FW_LIB_NAME="datetime")
|
||||
libenv.ApplyLibFlags()
|
||||
|
||||
sources = libenv.GlobRecursive("*.c*")
|
||||
|
||||
lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources)
|
||||
libenv.Install("${LIB_DIST_DIR}", lib)
|
||||
Return("lib")
|
||||
104
lib/datetime/datetime.c
Normal file
104
lib/datetime/datetime.c
Normal file
@@ -0,0 +1,104 @@
|
||||
#include "datetime.h"
|
||||
|
||||
#define TAG "DateTime"
|
||||
|
||||
#define SECONDS_PER_MINUTE 60
|
||||
#define SECONDS_PER_HOUR (SECONDS_PER_MINUTE * 60)
|
||||
#define SECONDS_PER_DAY (SECONDS_PER_HOUR * 24)
|
||||
#define MONTHS_COUNT 12
|
||||
#define EPOCH_START_YEAR 1970
|
||||
|
||||
static const uint8_t datetime_days_per_month[2][MONTHS_COUNT] = {
|
||||
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
|
||||
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
|
||||
|
||||
static const uint16_t datetime_days_per_year[] = {365, 366};
|
||||
|
||||
bool datetime_validate_datetime(DateTime* datetime) {
|
||||
bool invalid = false;
|
||||
|
||||
invalid |= (datetime->second > 59);
|
||||
invalid |= (datetime->minute > 59);
|
||||
invalid |= (datetime->hour > 23);
|
||||
|
||||
invalid |= (datetime->year < 2000);
|
||||
invalid |= (datetime->year > 2099);
|
||||
|
||||
invalid |= (datetime->month == 0);
|
||||
invalid |= (datetime->month > 12);
|
||||
|
||||
invalid |= (datetime->day == 0);
|
||||
invalid |= (datetime->day > 31);
|
||||
|
||||
invalid |= (datetime->weekday == 0);
|
||||
invalid |= (datetime->weekday > 7);
|
||||
|
||||
return !invalid;
|
||||
}
|
||||
|
||||
uint32_t datetime_datetime_to_timestamp(DateTime* datetime) {
|
||||
uint32_t timestamp = 0;
|
||||
uint8_t years = 0;
|
||||
uint8_t leap_years = 0;
|
||||
|
||||
for(uint16_t y = EPOCH_START_YEAR; y < datetime->year; y++) {
|
||||
if(datetime_is_leap_year(y)) {
|
||||
leap_years++;
|
||||
} else {
|
||||
years++;
|
||||
}
|
||||
}
|
||||
|
||||
timestamp += ((years * datetime_days_per_year[0]) + (leap_years * datetime_days_per_year[1])) *
|
||||
SECONDS_PER_DAY;
|
||||
|
||||
bool leap_year = datetime_is_leap_year(datetime->year);
|
||||
|
||||
for(uint8_t m = 1; m < datetime->month; m++) {
|
||||
timestamp += datetime_get_days_per_month(leap_year, m) * SECONDS_PER_DAY;
|
||||
}
|
||||
|
||||
timestamp += (datetime->day - 1) * SECONDS_PER_DAY;
|
||||
timestamp += datetime->hour * SECONDS_PER_HOUR;
|
||||
timestamp += datetime->minute * SECONDS_PER_MINUTE;
|
||||
timestamp += datetime->second;
|
||||
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
void datetime_timestamp_to_datetime(uint32_t timestamp, DateTime* datetime) {
|
||||
uint32_t days = timestamp / SECONDS_PER_DAY;
|
||||
uint32_t seconds_in_day = timestamp % SECONDS_PER_DAY;
|
||||
|
||||
datetime->year = EPOCH_START_YEAR;
|
||||
|
||||
while(days >= datetime_get_days_per_year(datetime->year)) {
|
||||
days -= datetime_get_days_per_year(datetime->year);
|
||||
(datetime->year)++;
|
||||
}
|
||||
|
||||
datetime->month = 1;
|
||||
while(days >=
|
||||
datetime_get_days_per_month(datetime_is_leap_year(datetime->year), datetime->month)) {
|
||||
days -=
|
||||
datetime_get_days_per_month(datetime_is_leap_year(datetime->year), datetime->month);
|
||||
(datetime->month)++;
|
||||
}
|
||||
|
||||
datetime->day = days + 1;
|
||||
datetime->hour = seconds_in_day / SECONDS_PER_HOUR;
|
||||
datetime->minute = (seconds_in_day % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE;
|
||||
datetime->second = seconds_in_day % SECONDS_PER_MINUTE;
|
||||
}
|
||||
|
||||
uint16_t datetime_get_days_per_year(uint16_t year) {
|
||||
return datetime_days_per_year[datetime_is_leap_year(year) ? 1 : 0];
|
||||
}
|
||||
|
||||
bool datetime_is_leap_year(uint16_t year) {
|
||||
return (((year) % 4 == 0) && ((year) % 100 != 0)) || ((year) % 400 == 0);
|
||||
}
|
||||
|
||||
uint8_t datetime_get_days_per_month(bool leap_year, uint8_t month) {
|
||||
return datetime_days_per_month[leap_year ? 1 : 0][month - 1];
|
||||
}
|
||||
75
lib/datetime/datetime.h
Normal file
75
lib/datetime/datetime.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
// Time
|
||||
uint8_t hour; /**< Hour in 24H format: 0-23 */
|
||||
uint8_t minute; /**< Minute: 0-59 */
|
||||
uint8_t second; /**< Second: 0-59 */
|
||||
// Date
|
||||
uint8_t day; /**< Current day: 1-31 */
|
||||
uint8_t month; /**< Current month: 1-12 */
|
||||
uint16_t year; /**< Current year: 2000-2099 */
|
||||
uint8_t weekday; /**< Current weekday: 1-7 */
|
||||
} DateTime;
|
||||
|
||||
/** Validate Date Time
|
||||
*
|
||||
* @param datetime The datetime to validate
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool datetime_validate_datetime(DateTime* datetime);
|
||||
|
||||
/** Convert DateTime to UNIX timestamp
|
||||
*
|
||||
* @warning Mind timezone when perform conversion
|
||||
*
|
||||
* @param datetime The datetime (UTC)
|
||||
*
|
||||
* @return UNIX Timestamp in seconds from UNIX epoch start
|
||||
*/
|
||||
uint32_t datetime_datetime_to_timestamp(DateTime* datetime);
|
||||
|
||||
/** Convert UNIX timestamp to DateTime
|
||||
*
|
||||
* @warning Mind timezone when perform conversion
|
||||
*
|
||||
* @param[in] timestamp UNIX Timestamp in seconds from UNIX epoch start
|
||||
* @param[out] datetime The datetime (UTC)
|
||||
*/
|
||||
void datetime_timestamp_to_datetime(uint32_t timestamp, DateTime* datetime);
|
||||
|
||||
/** Gets the number of days in the year according to the Gregorian calendar.
|
||||
*
|
||||
* @param year Input year.
|
||||
*
|
||||
* @return number of days in `year`.
|
||||
*/
|
||||
uint16_t datetime_get_days_per_year(uint16_t year);
|
||||
|
||||
/** Check if a year a leap year in the Gregorian calendar.
|
||||
*
|
||||
* @param year Input year.
|
||||
*
|
||||
* @return true if `year` is a leap year.
|
||||
*/
|
||||
bool datetime_is_leap_year(uint16_t year);
|
||||
|
||||
/** Get the number of days in the month.
|
||||
*
|
||||
* @param leap_year true to calculate based on leap years
|
||||
* @param month month to check, where 1 = January
|
||||
* @return the number of days in the month
|
||||
*/
|
||||
uint8_t datetime_get_days_per_month(bool leap_year, uint8_t month);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user