2026-01-06 09:48:38 +08:00
|
|
|
#include "common/time.h"
|
|
|
|
|
#include "common/printing.h"
|
|
|
|
|
#include "common/jsonconfig.h"
|
|
|
|
|
#include "common/stringUtils.h"
|
2026-01-05 16:19:47 +08:00
|
|
|
#include "modules/datetime/datetime.h"
|
2023-03-09 19:38:03 +08:00
|
|
|
|
2023-09-12 15:53:58 +08:00
|
|
|
#include <time.h>
|
|
|
|
|
|
2023-10-31 21:55:17 +08:00
|
|
|
#pragma GCC diagnostic ignored "-Wformat" // warning: unknown conversion type character 'F' in format
|
|
|
|
|
|
2023-03-09 19:38:03 +08:00
|
|
|
#define FF_DATETIME_DISPLAY_NAME "Date & Time"
|
|
|
|
|
|
2023-09-12 15:53:58 +08:00
|
|
|
typedef struct FFDateTimeResult
|
|
|
|
|
{
|
|
|
|
|
//Examples for 21.02.2022 - 15:18:37
|
|
|
|
|
uint16_t year; //2022
|
|
|
|
|
uint8_t yearShort; //22
|
|
|
|
|
uint8_t month; //2
|
2024-01-23 21:21:30 +08:00
|
|
|
char monthPretty[FASTFETCH_STRBUF_DEFAULT_ALLOC]; //02
|
|
|
|
|
char monthName[FASTFETCH_STRBUF_DEFAULT_ALLOC]; //February
|
|
|
|
|
char monthNameShort[FASTFETCH_STRBUF_DEFAULT_ALLOC]; //Feb
|
2023-09-12 15:53:58 +08:00
|
|
|
uint8_t week; //8
|
2024-01-23 21:21:30 +08:00
|
|
|
char weekday[FASTFETCH_STRBUF_DEFAULT_ALLOC]; //Monday
|
|
|
|
|
char weekdayShort[FASTFETCH_STRBUF_DEFAULT_ALLOC]; //Mon
|
2023-09-12 15:53:58 +08:00
|
|
|
uint16_t dayInYear; //52
|
|
|
|
|
uint8_t dayInMonth; //21
|
|
|
|
|
uint8_t dayInWeek; //1
|
2024-10-01 17:44:23 +08:00
|
|
|
char dayPretty[FASTFETCH_STRBUF_DEFAULT_ALLOC]; //01
|
2023-09-12 15:53:58 +08:00
|
|
|
uint8_t hour; //15
|
2024-01-23 21:21:30 +08:00
|
|
|
char hourPretty[FASTFETCH_STRBUF_DEFAULT_ALLOC]; //15
|
2023-09-12 15:53:58 +08:00
|
|
|
uint8_t hour12; //3
|
2024-01-23 21:21:30 +08:00
|
|
|
char hour12Pretty[FASTFETCH_STRBUF_DEFAULT_ALLOC]; //03
|
2023-09-12 15:53:58 +08:00
|
|
|
uint8_t minute; //18
|
2024-01-23 21:21:30 +08:00
|
|
|
char minutePretty[FASTFETCH_STRBUF_DEFAULT_ALLOC]; //18
|
2023-09-12 15:53:58 +08:00
|
|
|
uint8_t second; //37
|
2024-01-23 21:21:30 +08:00
|
|
|
char secondPretty[FASTFETCH_STRBUF_DEFAULT_ALLOC]; //37
|
|
|
|
|
char offsetFromUtc[FASTFETCH_STRBUF_DEFAULT_ALLOC];
|
|
|
|
|
char timezoneName[FASTFETCH_STRBUF_DEFAULT_ALLOC];
|
2023-09-12 15:53:58 +08:00
|
|
|
} FFDateTimeResult;
|
|
|
|
|
|
2025-08-18 13:38:30 +08:00
|
|
|
static void printDateTimeFormat(struct tm* tm, const FFModuleArgs* moduleArgs)
|
2023-03-09 19:38:03 +08:00
|
|
|
{
|
2023-09-12 15:53:58 +08:00
|
|
|
FFDateTimeResult result;
|
|
|
|
|
|
|
|
|
|
result.year = (uint16_t) (tm->tm_year + 1900);
|
|
|
|
|
result.yearShort = (uint8_t) (result.year % 100);
|
|
|
|
|
result.month = (uint8_t) (tm->tm_mon + 1);
|
2024-01-23 21:21:30 +08:00
|
|
|
strftime(result.monthPretty, sizeof(result.monthPretty), "%m", tm);
|
|
|
|
|
strftime(result.monthName, sizeof(result.monthName), "%B", tm);
|
|
|
|
|
strftime(result.monthNameShort, sizeof(result.monthNameShort), "%b", tm);
|
2023-09-12 15:53:58 +08:00
|
|
|
result.week = (uint8_t) (tm->tm_yday / 7 + 1);
|
2024-01-23 21:21:30 +08:00
|
|
|
strftime(result.weekday, sizeof(result.weekday), "%A", tm);
|
|
|
|
|
strftime(result.weekdayShort, sizeof(result.weekdayShort), "%a", tm);
|
2023-09-12 15:53:58 +08:00
|
|
|
result.dayInYear = (uint8_t) (tm->tm_yday + 1);
|
|
|
|
|
result.dayInMonth = (uint8_t) tm->tm_mday;
|
|
|
|
|
result.dayInWeek = tm->tm_wday == 0 ? 7 : (uint8_t) tm->tm_wday;
|
2025-02-20 19:47:27 +08:00
|
|
|
strftime(result.dayPretty, sizeof(result.dayPretty), "%d", tm);
|
2023-09-12 15:53:58 +08:00
|
|
|
result.hour = (uint8_t) tm->tm_hour;
|
2024-01-23 21:21:30 +08:00
|
|
|
strftime(result.hourPretty, sizeof(result.hourPretty), "%H", tm);
|
2023-09-12 15:53:58 +08:00
|
|
|
result.hour12 = (uint8_t) (result.hour % 12);
|
2024-01-23 21:21:30 +08:00
|
|
|
strftime(result.hour12Pretty, sizeof(result.hour12Pretty), "%I", tm);
|
2023-09-12 15:53:58 +08:00
|
|
|
result.minute = (uint8_t) tm->tm_min;
|
2024-01-23 21:21:30 +08:00
|
|
|
strftime(result.minutePretty, sizeof(result.minutePretty), "%M", tm);
|
2023-09-12 15:53:58 +08:00
|
|
|
result.second = (uint8_t) tm->tm_sec;
|
2024-01-23 21:21:30 +08:00
|
|
|
strftime(result.secondPretty, sizeof(result.secondPretty), "%S", tm);
|
|
|
|
|
strftime(result.offsetFromUtc, sizeof(result.offsetFromUtc), "%z", tm);
|
|
|
|
|
strftime(result.timezoneName, sizeof(result.timezoneName), "%Z", tm);
|
2023-09-12 15:53:58 +08:00
|
|
|
|
2024-12-11 10:47:02 +08:00
|
|
|
FF_PRINT_FORMAT_CHECKED(FF_DATETIME_DISPLAY_NAME, 0, moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
|
2026-03-12 15:07:19 +08:00
|
|
|
FF_ARG(result.year, "year"), // 1
|
|
|
|
|
FF_ARG(result.yearShort, "year-short"), // 2
|
|
|
|
|
FF_ARG(result.month, "month"), // 3
|
|
|
|
|
FF_ARG(result.monthPretty, "month-pretty"), // 4
|
|
|
|
|
FF_ARG(result.monthName, "month-name"), // 5
|
|
|
|
|
FF_ARG(result.monthNameShort, "month-name-short"), // 6
|
|
|
|
|
FF_ARG(result.week, "week"), // 7
|
|
|
|
|
FF_ARG(result.weekday, "weekday"), // 8
|
|
|
|
|
FF_ARG(result.weekdayShort, "weekday-short"), // 9
|
|
|
|
|
FF_ARG(result.dayInYear, "day-in-year"), // 10
|
|
|
|
|
FF_ARG(result.dayInMonth, "day-in-month"), // 11
|
|
|
|
|
FF_ARG(result.dayInWeek, "day-in-week"), // 12
|
|
|
|
|
FF_ARG(result.hour, "hour"), // 13
|
|
|
|
|
FF_ARG(result.hourPretty, "hour-pretty"), // 14
|
|
|
|
|
FF_ARG(result.hour12, "hour-12"), // 15
|
|
|
|
|
FF_ARG(result.hour12Pretty, "hour-12-pretty"), // 16
|
|
|
|
|
FF_ARG(result.minute, "minute"), // 17
|
|
|
|
|
FF_ARG(result.minutePretty, "minute-pretty"), // 18
|
|
|
|
|
FF_ARG(result.second, "second"), // 19
|
|
|
|
|
FF_ARG(result.secondPretty, "second-pretty"), // 20
|
|
|
|
|
FF_ARG(result.offsetFromUtc, "offset-from-utc"), // 21
|
|
|
|
|
FF_ARG(result.timezoneName, "timezone-name"), // 22
|
|
|
|
|
FF_ARG(result.dayPretty, "day-pretty"), // 23
|
2024-03-07 10:47:28 +08:00
|
|
|
}));
|
2023-03-09 19:38:03 +08:00
|
|
|
}
|
|
|
|
|
|
2025-08-18 13:38:30 +08:00
|
|
|
bool ffPrintDateTime(FFDateTimeOptions* options)
|
2023-03-09 19:38:03 +08:00
|
|
|
{
|
2023-09-12 15:53:58 +08:00
|
|
|
uint64_t msNow = ffTimeGetNow();
|
2023-09-13 17:42:22 +08:00
|
|
|
time_t sNow = (time_t) (msNow / 1000);
|
2023-09-12 15:53:58 +08:00
|
|
|
struct tm* tm = localtime(&sNow);
|
|
|
|
|
|
2023-03-09 19:38:03 +08:00
|
|
|
if(options->moduleArgs.outputFormat.length > 0)
|
|
|
|
|
{
|
2025-08-18 13:38:30 +08:00
|
|
|
printDateTimeFormat(tm, &options->moduleArgs);
|
|
|
|
|
return true;
|
2023-09-12 15:53:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char buffer[32];
|
2024-10-18 16:15:48 +08:00
|
|
|
if (strftime(buffer, ARRAY_SIZE(buffer), "%F %T", tm) == 0) //yyyy-MM-dd HH:mm:ss
|
2023-09-12 15:53:58 +08:00
|
|
|
{
|
2024-03-07 11:10:18 +08:00
|
|
|
ffPrintError(FF_DATETIME_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "strftime() failed");
|
2025-08-18 13:38:30 +08:00
|
|
|
return false;
|
2023-03-09 19:38:03 +08:00
|
|
|
}
|
|
|
|
|
|
2023-08-15 21:40:22 +08:00
|
|
|
ffPrintLogoAndKey(FF_DATETIME_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
|
2023-03-09 19:38:03 +08:00
|
|
|
|
2023-09-12 15:53:58 +08:00
|
|
|
puts(buffer);
|
2025-08-18 13:38:30 +08:00
|
|
|
return true;
|
2023-03-09 19:38:03 +08:00
|
|
|
}
|
|
|
|
|
|
2023-08-17 10:56:54 +08:00
|
|
|
void ffParseDateTimeJsonObject(FFDateTimeOptions* options, yyjson_val* module)
|
2023-03-09 19:38:03 +08:00
|
|
|
{
|
2025-08-02 18:51:03 +08:00
|
|
|
yyjson_val *key, *val;
|
2023-08-17 16:09:41 +08:00
|
|
|
size_t idx, max;
|
2025-08-02 18:51:03 +08:00
|
|
|
yyjson_obj_foreach(module, idx, max, key, val)
|
2023-03-09 19:38:03 +08:00
|
|
|
{
|
2023-08-17 16:09:41 +08:00
|
|
|
if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs))
|
|
|
|
|
continue;
|
2023-03-09 19:38:03 +08:00
|
|
|
|
2025-08-02 18:51:03 +08:00
|
|
|
ffPrintError(FF_DATETIME_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
|
2023-03-09 19:38:03 +08:00
|
|
|
}
|
|
|
|
|
}
|
2023-08-31 11:24:15 +08:00
|
|
|
|
2023-10-24 14:41:29 +08:00
|
|
|
void ffGenerateDateTimeJsonConfig(FFDateTimeOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
|
|
|
|
|
{
|
2025-08-04 16:46:28 +08:00
|
|
|
ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
|
2023-10-24 14:41:29 +08:00
|
|
|
}
|
|
|
|
|
|
2025-08-18 13:38:30 +08:00
|
|
|
bool ffGenerateDateTimeJsonResult(FF_MAYBE_UNUSED FFDateTimeOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
|
2023-08-31 11:24:15 +08:00
|
|
|
{
|
2024-05-03 13:56:19 +08:00
|
|
|
yyjson_mut_obj_add_strcpy(doc, module, "result", ffTimeToFullStr(ffTimeGetNow()));
|
2025-08-18 13:38:30 +08:00
|
|
|
return true;
|
2023-08-31 11:24:15 +08:00
|
|
|
}
|
2023-10-07 13:40:40 +08:00
|
|
|
|
2025-08-04 14:25:14 +08:00
|
|
|
void ffInitDateTimeOptions(FFDateTimeOptions* options)
|
|
|
|
|
{
|
|
|
|
|
ffOptionInitModuleArg(&options->moduleArgs, "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ffDestroyDateTimeOptions(FFDateTimeOptions* options)
|
|
|
|
|
{
|
|
|
|
|
ffOptionDestroyModuleArg(&options->moduleArgs);
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-03 22:50:56 +08:00
|
|
|
FFModuleBaseInfo ffDateTimeModuleInfo = {
|
2024-12-11 10:47:02 +08:00
|
|
|
.name = FF_DATETIME_MODULE_NAME,
|
|
|
|
|
.description = "Print current date and time",
|
2025-08-03 18:39:41 +08:00
|
|
|
.initOptions = (void*) ffInitDateTimeOptions,
|
|
|
|
|
.destroyOptions = (void*) ffDestroyDateTimeOptions,
|
2024-12-11 10:47:02 +08:00
|
|
|
.parseJsonObject = (void*) ffParseDateTimeJsonObject,
|
|
|
|
|
.printModule = (void*) ffPrintDateTime,
|
|
|
|
|
.generateJsonResult = (void*) ffGenerateDateTimeJsonResult,
|
|
|
|
|
.generateJsonConfig = (void*) ffGenerateDateTimeJsonConfig,
|
|
|
|
|
.formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) {
|
|
|
|
|
{"Year", "year"},
|
|
|
|
|
{"Last two digits of year", "year-short"},
|
|
|
|
|
{"Month", "month"},
|
|
|
|
|
{"Month with leading zero", "month-pretty"},
|
|
|
|
|
{"Month name", "month-name"},
|
|
|
|
|
{"Month name short", "month-name-short"},
|
|
|
|
|
{"Week number on year", "week"},
|
|
|
|
|
{"Weekday", "weekday"},
|
|
|
|
|
{"Weekday short", "weekday-short"},
|
|
|
|
|
{"Day in year", "day-in-year"},
|
|
|
|
|
{"Day in month", "day-in-month"},
|
|
|
|
|
{"Day in week", "day-in-week"},
|
|
|
|
|
{"Hour", "hour"},
|
|
|
|
|
{"Hour with leading zero", "hour-pretty"},
|
|
|
|
|
{"Hour 12h format", "hour-12"},
|
|
|
|
|
{"Hour 12h format with leading zero", "hour-12-pretty"},
|
|
|
|
|
{"Minute", "minute"},
|
|
|
|
|
{"Minute with leading zero", "minute-pretty"},
|
|
|
|
|
{"Second", "second"},
|
|
|
|
|
{"Second with leading zero", "second-pretty"},
|
|
|
|
|
{"Offset from UTC in the ISO 8601 format", "offset-from-utc"},
|
|
|
|
|
{"Locale-dependent timezone name or abbreviation", "timezone-name"},
|
|
|
|
|
{"Day in month with leading zero", "day-pretty"},
|
|
|
|
|
}))
|
|
|
|
|
};
|