diff --git a/libs/datetime/date_functions.c b/libs/datetime/date_functions.c new file mode 100644 index 0000000..7da6ec0 --- /dev/null +++ b/libs/datetime/date_functions.c @@ -0,0 +1,422 @@ +#include "date_functions.h" +#include + +GroundValue tmToGroundValue(struct tm t) { + GroundStruct timeStruct = groundCreateStruct(); + groundAddFieldToStruct(&timeStruct, "year", groundCreateValue(INT, t.tm_year + 1900)); + groundAddFieldToStruct(&timeStruct, "month", groundCreateValue(INT, t.tm_mon + 1)); + groundAddFieldToStruct(&timeStruct, "day", groundCreateValue(INT, t.tm_mday)); + groundAddFieldToStruct(&timeStruct, "hour", groundCreateValue(INT, t.tm_hour)); + groundAddFieldToStruct(&timeStruct, "minute", groundCreateValue(INT, t.tm_min)); + groundAddFieldToStruct(&timeStruct, "second", groundCreateValue(INT, t.tm_sec)); + groundAddFieldToStruct(&timeStruct, "weekDay", groundCreateValue(INT, t.tm_wday)); + groundAddFieldToStruct(&timeStruct, "yearDay", groundCreateValue(INT, t.tm_yday + 1)); + groundAddFieldToStruct(&timeStruct, "isDaylightSavingsTime", groundCreateValue(BOOL, t.tm_isdst)); + + GroundValue value = groundCreateValue(CUSTOM, &timeStruct); + value.type = CUSTOM; + + return value; +} + +GroundValue datetime_Now(GroundScope* scope, List args) { + time_t now = time(NULL); + struct tm t = {0}; + + localtime_r(&now, &t); + + // return a -datetime struct + return tmToGroundValue(t); +} + +GroundValue datetime_FromEpochLocal(GroundScope* scope, List args) { + struct tm t = {0}; + time_t ts = args.values[0].data.doubleVal; + + localtime_r(&ts, &t); + + return tmToGroundValue(t); +} + +GroundValue datetime_FromEpochUTC(GroundScope* scope, List args) { + struct tm t = {0}; + time_t ts = args.values[0].data.doubleVal; + + gmtime_r(&ts, &t); + + return tmToGroundValue(t); +} + +GroundValue datetime_ToEpochLocal(GroundScope* scope, List args) { + GroundObject obj = *args.values[0].data.customVal; + + // check args + GroundObjectField* year = groundFindField(obj, "year"); + if (year == NULL || year->value.type != INT) ERROR("Object does not have year field as int", "ValueError"); + GroundObjectField* month = groundFindField(obj, "month"); + if (month == NULL || month->value.type != INT) ERROR("Object does not have month field as int", "ValueError"); + GroundObjectField* day = groundFindField(obj, "day"); + if (day == NULL || day->value.type != INT) ERROR("Object does not have day field as int", "ValueError"); + GroundObjectField* hour = groundFindField(obj, "hour"); + if (hour == NULL || hour->value.type != INT) ERROR("Object does not have hour field as int", "ValueError"); + GroundObjectField* minute = groundFindField(obj, "minute"); + if (minute == NULL || minute->value.type != INT) ERROR("Object does not have minute field as int", "ValueError"); + GroundObjectField* second = groundFindField(obj, "second"); + if (second == NULL || second->value.type != INT) ERROR("Object does not have second field as int", "ValueError"); + GroundObjectField* weekDay = groundFindField(obj, "weekDay"); + if (weekDay == NULL || weekDay->value.type != INT) ERROR("Object does not have weekDay field as int", "ValueError"); + GroundObjectField* yearDay = groundFindField(obj, "yearDay"); + if (yearDay == NULL || yearDay->value.type != INT) ERROR("Object does not have yearDay field as int", "ValueError"); + GroundObjectField* isDaylightSavingsTime = groundFindField(obj, "isDaylightSavingsTime"); + if (isDaylightSavingsTime == NULL || isDaylightSavingsTime->value.type != BOOL) ERROR("Object does not have isDaylightSavingsTime field as bool", "ValueError"); + + // construct tm struct from our ground struct + struct tm t = { + .tm_sec = second->value.data.intVal, + .tm_min = minute->value.data.intVal, + .tm_hour = hour->value.data.intVal, + .tm_mday = day->value.data.intVal, + .tm_mon = month->value.data.intVal - 1, + .tm_year = year->value.data.intVal - 1900, + .tm_wday = 0, + .tm_yday = 0, + .tm_isdst = -1 + }; + + time_t ts = mktime(&t); + return groundCreateValue(INT, (long long)ts); +} + +GroundValue datetime_ToEpochUTC(GroundScope* scope, List args) { + GroundObject obj = *args.values[0].data.customVal; + + // check args + GroundObjectField* year = groundFindField(obj, "year"); + if (year == NULL || year->value.type != INT) ERROR("Object does not have year field as int", "ValueError"); + GroundObjectField* month = groundFindField(obj, "month"); + if (month == NULL || month->value.type != INT) ERROR("Object does not have month field as int", "ValueError"); + GroundObjectField* day = groundFindField(obj, "day"); + if (day == NULL || day->value.type != INT) ERROR("Object does not have day field as int", "ValueError"); + GroundObjectField* hour = groundFindField(obj, "hour"); + if (hour == NULL || hour->value.type != INT) ERROR("Object does not have hour field as int", "ValueError"); + GroundObjectField* minute = groundFindField(obj, "minute"); + if (minute == NULL || minute->value.type != INT) ERROR("Object does not have minute field as int", "ValueError"); + GroundObjectField* second = groundFindField(obj, "second"); + if (second == NULL || second->value.type != INT) ERROR("Object does not have second field as int", "ValueError"); + GroundObjectField* weekDay = groundFindField(obj, "weekDay"); + if (weekDay == NULL || weekDay->value.type != INT) ERROR("Object does not have weekDay field as int", "ValueError"); + GroundObjectField* yearDay = groundFindField(obj, "yearDay"); + if (yearDay == NULL || yearDay->value.type != INT) ERROR("Object does not have yearDay field as int", "ValueError"); + GroundObjectField* isDaylightSavingsTime = groundFindField(obj, "isDaylightSavingsTime"); + if (isDaylightSavingsTime == NULL || isDaylightSavingsTime->value.type != BOOL) ERROR("Object does not have isDaylightSavingsTime field as bool", "ValueError"); + + // construct tm struct from our ground struct + struct tm t = { + .tm_sec = second->value.data.intVal, + .tm_min = minute->value.data.intVal, + .tm_hour = hour->value.data.intVal, + .tm_mday = day->value.data.intVal, + .tm_mon = month->value.data.intVal - 1, + .tm_year = year->value.data.intVal - 1900, + .tm_wday = 0, + .tm_yday = 0, + .tm_isdst = -1 + }; + + time_t ts = timegm(&t); + return groundCreateValue(INT, (long long)ts); +} + +GroundValue formatDatetimeObj(GroundObject obj, char* formatString) { + // check args + GroundObjectField* year = groundFindField(obj, "year"); + if (year == NULL || year->value.type != INT) ERROR("Object does not have year field as int", "ValueError"); + GroundObjectField* month = groundFindField(obj, "month"); + if (month == NULL || month->value.type != INT) ERROR("Object does not have month field as int", "ValueError"); + GroundObjectField* day = groundFindField(obj, "day"); + if (day == NULL || day->value.type != INT) ERROR("Object does not have day field as int", "ValueError"); + GroundObjectField* hour = groundFindField(obj, "hour"); + if (hour == NULL || hour->value.type != INT) ERROR("Object does not have hour field as int", "ValueError"); + GroundObjectField* minute = groundFindField(obj, "minute"); + if (minute == NULL || minute->value.type != INT) ERROR("Object does not have minute field as int", "ValueError"); + GroundObjectField* second = groundFindField(obj, "second"); + if (second == NULL || second->value.type != INT) ERROR("Object does not have second field as int", "ValueError"); + GroundObjectField* weekDay = groundFindField(obj, "weekDay"); + if (weekDay == NULL || weekDay->value.type != INT) ERROR("Object does not have weekDay field as int", "ValueError"); + GroundObjectField* yearDay = groundFindField(obj, "yearDay"); + if (yearDay == NULL || yearDay->value.type != INT) ERROR("Object does not have yearDay field as int", "ValueError"); + GroundObjectField* isDaylightSavingsTime = groundFindField(obj, "isDaylightSavingsTime"); + if (isDaylightSavingsTime == NULL || isDaylightSavingsTime->value.type != BOOL) ERROR("Object does not have isDaylightSavingsTime field as bool", "ValueError"); + + // construct tm struct from our ground struct + struct tm t = { + .tm_sec = second->value.data.intVal, + .tm_min = minute->value.data.intVal, + .tm_hour = hour->value.data.intVal, + .tm_mday = day->value.data.intVal, + .tm_mon = month->value.data.intVal - 1, + .tm_year = year->value.data.intVal - 1900, + .tm_wday = 0, + .tm_yday = 0, + .tm_isdst = -1 + }; + + mktime(&t); // normalise time + + // create a buffer for the string + char* buffer = (char*)malloc(128); + strftime(buffer, 128, formatString, &t); + + // return ground version of string + return groundCreateValue(STRING, buffer); +} + +GroundValue datetime_Format(GroundScope* scope, List args) { + return formatDatetimeObj( + *args.values[0].data.customVal, + args.values[1].data.stringVal + ); +} + +GroundValue datetime_FromFormatted(GroundScope* scope, List args) { + char* timeString = args.values[0].data.stringVal; + char* formatString = args.values[1].data.stringVal; + + struct tm t = {0}; + t.tm_isdst = -1; + char* result = strptime(timeString, formatString, &t); + + if (result == NULL) { + ERROR("Time string does not match format!", "ValueError"); + } + + mktime(&t); + + return tmToGroundValue(t); +} + +GroundValue datetime_ToISO8601UTC(GroundScope* scope, List args) { + GroundObject obj = *args.values[0].data.customVal; + + // check args + GroundObjectField* year = groundFindField(obj, "year"); + if (year == NULL || year->value.type != INT) ERROR("Object does not have year field as int", "ValueError"); + GroundObjectField* month = groundFindField(obj, "month"); + if (month == NULL || month->value.type != INT) ERROR("Object does not have month field as int", "ValueError"); + GroundObjectField* day = groundFindField(obj, "day"); + if (day == NULL || day->value.type != INT) ERROR("Object does not have day field as int", "ValueError"); + GroundObjectField* hour = groundFindField(obj, "hour"); + if (hour == NULL || hour->value.type != INT) ERROR("Object does not have hour field as int", "ValueError"); + GroundObjectField* minute = groundFindField(obj, "minute"); + if (minute == NULL || minute->value.type != INT) ERROR("Object does not have minute field as int", "ValueError"); + GroundObjectField* second = groundFindField(obj, "second"); + if (second == NULL || second->value.type != INT) ERROR("Object does not have second field as int", "ValueError"); + GroundObjectField* weekDay = groundFindField(obj, "weekDay"); + if (weekDay == NULL || weekDay->value.type != INT) ERROR("Object does not have weekDay field as int", "ValueError"); + GroundObjectField* yearDay = groundFindField(obj, "yearDay"); + if (yearDay == NULL || yearDay->value.type != INT) ERROR("Object does not have yearDay field as int", "ValueError"); + GroundObjectField* isDaylightSavingsTime = groundFindField(obj, "isDaylightSavingsTime"); + if (isDaylightSavingsTime == NULL || isDaylightSavingsTime->value.type != BOOL) ERROR("Object does not have isDaylightSavingsTime field as bool", "ValueError"); + + // construct tm struct from our ground struct + struct tm t = { + .tm_sec = second->value.data.intVal, + .tm_min = minute->value.data.intVal, + .tm_hour = hour->value.data.intVal, + .tm_mday = day->value.data.intVal, + .tm_mon = month->value.data.intVal - 1, + .tm_year = year->value.data.intVal - 1900, + .tm_wday = 0, + .tm_yday = 0, + .tm_isdst = -1 + }; + + time_t ts = mktime(&t); + gmtime_r(&ts, &t); + + char* buffer = (char*)malloc(128); + strftime(buffer, 128, "%Y-%m-%dT%H:%M:%SZ", &t); + + return groundCreateValue(STRING, buffer); +} + +GroundValue datetime_ToISO8601Local(GroundScope* scope, List args) { + GroundObject obj = *args.values[0].data.customVal; + + // check args + GroundObjectField* year = groundFindField(obj, "year"); + if (year == NULL || year->value.type != INT) ERROR("Object does not have year field as int", "ValueError"); + GroundObjectField* month = groundFindField(obj, "month"); + if (month == NULL || month->value.type != INT) ERROR("Object does not have month field as int", "ValueError"); + GroundObjectField* day = groundFindField(obj, "day"); + if (day == NULL || day->value.type != INT) ERROR("Object does not have day field as int", "ValueError"); + GroundObjectField* hour = groundFindField(obj, "hour"); + if (hour == NULL || hour->value.type != INT) ERROR("Object does not have hour field as int", "ValueError"); + GroundObjectField* minute = groundFindField(obj, "minute"); + if (minute == NULL || minute->value.type != INT) ERROR("Object does not have minute field as int", "ValueError"); + GroundObjectField* second = groundFindField(obj, "second"); + if (second == NULL || second->value.type != INT) ERROR("Object does not have second field as int", "ValueError"); + GroundObjectField* weekDay = groundFindField(obj, "weekDay"); + if (weekDay == NULL || weekDay->value.type != INT) ERROR("Object does not have weekDay field as int", "ValueError"); + GroundObjectField* yearDay = groundFindField(obj, "yearDay"); + if (yearDay == NULL || yearDay->value.type != INT) ERROR("Object does not have yearDay field as int", "ValueError"); + GroundObjectField* isDaylightSavingsTime = groundFindField(obj, "isDaylightSavingsTime"); + if (isDaylightSavingsTime == NULL || isDaylightSavingsTime->value.type != BOOL) ERROR("Object does not have isDaylightSavingsTime field as bool", "ValueError"); + + // construct tm struct from our ground struct + struct tm t = { + .tm_sec = second->value.data.intVal, + .tm_min = minute->value.data.intVal, + .tm_hour = hour->value.data.intVal, + .tm_mday = day->value.data.intVal, + .tm_mon = month->value.data.intVal - 1, + .tm_year = year->value.data.intVal - 1900, + .tm_wday = 0, + .tm_yday = 0, + .tm_isdst = -1 + }; + + time_t ts = mktime(&t); + localtime_r(&ts, &t); + + char* buffer = (char*)malloc(128); + strftime(buffer, 128, "%Y-%m-%dT%H:%M:%S%z", &t); + + return groundCreateValue(STRING, buffer); +} + +GroundValue datetime_Diff(GroundScope* scope, List args) { + GroundObject obj1 = *args.values[0].data.customVal; + GroundObject obj2 = *args.values[1].data.customVal; + + // check first timedate object + GroundObjectField* year = groundFindField(obj1, "year"); + if (year == NULL || year->value.type != INT) ERROR("Object 1 does not have year field as int", "ValueError"); + GroundObjectField* month = groundFindField(obj1, "month"); + if (month == NULL || month->value.type != INT) ERROR("Object 1 does not have month field as int", "ValueError"); + GroundObjectField* day = groundFindField(obj1, "day"); + if (day == NULL || day->value.type != INT) ERROR("Object 1 does not have day field as int", "ValueError"); + GroundObjectField* hour = groundFindField(obj1, "hour"); + if (hour == NULL || hour->value.type != INT) ERROR("Object 1 does not have hour field as int", "ValueError"); + GroundObjectField* minute = groundFindField(obj1, "minute"); + if (minute == NULL || minute->value.type != INT) ERROR("Object 1 does not have minute field as int", "ValueError"); + GroundObjectField* second = groundFindField(obj1, "second"); + if (second == NULL || second->value.type != INT) ERROR("Object 1 does not have second field as int", "ValueError"); + GroundObjectField* weekDay = groundFindField(obj1, "weekDay"); + if (weekDay == NULL || weekDay->value.type != INT) ERROR("Object 1 does not have weekDay field as int", "ValueError"); + GroundObjectField* yearDay = groundFindField(obj1, "yearDay"); + if (yearDay == NULL || yearDay->value.type != INT) ERROR("Object 1 does not have yearDay field as int", "ValueError"); + GroundObjectField* isDaylightSavingsTime = groundFindField(obj1, "isDaylightSavingsTime"); + if (isDaylightSavingsTime == NULL || isDaylightSavingsTime->value.type != BOOL) ERROR("Object 1 does not have isDaylightSavingsTime field as bool", "ValueError"); + + // construct tm struct from our ground struct + struct tm t1 = { + .tm_sec = second->value.data.intVal, + .tm_min = minute->value.data.intVal, + .tm_hour = hour->value.data.intVal, + .tm_mday = day->value.data.intVal, + .tm_mon = month->value.data.intVal - 1, + .tm_year = year->value.data.intVal - 1900, + .tm_wday = 0, + .tm_yday = 0, + .tm_isdst = -1 + }; + + + // check second timedate object + year = groundFindField(obj2, "year"); + if (year == NULL || year->value.type != INT) ERROR("Object does not have year field as int", "ValueError"); + month = groundFindField(obj2, "month"); + if (month == NULL || month->value.type != INT) ERROR("Object does not have month field as int", "ValueError"); + day = groundFindField(obj2, "day"); + if (day == NULL || day->value.type != INT) ERROR("Object does not have day field as int", "ValueError"); + hour = groundFindField(obj2, "hour"); + if (hour == NULL || hour->value.type != INT) ERROR("Object does not have hour field as int", "ValueError"); + minute = groundFindField(obj2, "minute"); + if (minute == NULL || minute->value.type != INT) ERROR("Object does not have minute field as int", "ValueError"); + second = groundFindField(obj2, "second"); + if (second == NULL || second->value.type != INT) ERROR("Object does not have second field as int", "ValueError"); + weekDay = groundFindField(obj2, "weekDay"); + if (weekDay == NULL || weekDay->value.type != INT) ERROR("Object does not have weekDay field as int", "ValueError"); + yearDay = groundFindField(obj2, "yearDay"); + if (yearDay == NULL || yearDay->value.type != INT) ERROR("Object does not have yearDay field as int", "ValueError"); + isDaylightSavingsTime = groundFindField(obj2, "isDaylightSavingsTime"); + if (isDaylightSavingsTime == NULL || isDaylightSavingsTime->value.type != BOOL) ERROR("Object does not have isDaylightSavingsTime field as bool", "ValueError"); + + // construct tm struct from our ground struct + struct tm t2 = { + .tm_sec = second->value.data.intVal, + .tm_min = minute->value.data.intVal, + .tm_hour = hour->value.data.intVal, + .tm_mday = day->value.data.intVal, + .tm_mon = month->value.data.intVal - 1, + .tm_year = year->value.data.intVal - 1900, + .tm_wday = 0, + .tm_yday = 0, + .tm_isdst = -1 + }; + + + time_t ts1 = mktime(&t1); + time_t ts2 = mktime(&t2); + + return groundCreateValue(INT, ts2 - ts1); +} + +GroundValue datetime_Add(GroundScope* scope, List args) { + GroundObject obj = *args.values[0].data.customVal; + + long long secs = args.values[1].data.intVal; + long long mins = args.values[2].data.intVal; + long long hours = args.values[3].data.intVal; + long long days = args.values[4].data.intVal; + + // check args + GroundObjectField* year = groundFindField(obj, "year"); + if (year == NULL || year->value.type != INT) ERROR("Object does not have year field as int", "ValueError"); + GroundObjectField* month = groundFindField(obj, "month"); + if (month == NULL || month->value.type != INT) ERROR("Object does not have month field as int", "ValueError"); + GroundObjectField* day = groundFindField(obj, "day"); + if (day == NULL || day->value.type != INT) ERROR("Object does not have day field as int", "ValueError"); + GroundObjectField* hour = groundFindField(obj, "hour"); + if (hour == NULL || hour->value.type != INT) ERROR("Object does not have hour field as int", "ValueError"); + GroundObjectField* minute = groundFindField(obj, "minute"); + if (minute == NULL || minute->value.type != INT) ERROR("Object does not have minute field as int", "ValueError"); + GroundObjectField* second = groundFindField(obj, "second"); + if (second == NULL || second->value.type != INT) ERROR("Object does not have second field as int", "ValueError"); + GroundObjectField* weekDay = groundFindField(obj, "weekDay"); + if (weekDay == NULL || weekDay->value.type != INT) ERROR("Object does not have weekDay field as int", "ValueError"); + GroundObjectField* yearDay = groundFindField(obj, "yearDay"); + if (yearDay == NULL || yearDay->value.type != INT) ERROR("Object does not have yearDay field as int", "ValueError"); + GroundObjectField* isDaylightSavingsTime = groundFindField(obj, "isDaylightSavingsTime"); + if (isDaylightSavingsTime == NULL || isDaylightSavingsTime->value.type != BOOL) ERROR("Object does not have isDaylightSavingsTime field as bool", "ValueError"); + + // construct tm struct from our ground struct + struct tm t = { + .tm_sec = second->value.data.intVal, + .tm_min = minute->value.data.intVal, + .tm_hour = hour->value.data.intVal, + .tm_mday = day->value.data.intVal, + .tm_mon = month->value.data.intVal - 1, + .tm_year = year->value.data.intVal - 1900, + .tm_wday = 0, + .tm_yday = 0, + .tm_isdst = -1 + }; + + time_t base = mktime(&t); + + long long totalSeconds = + secs + + mins * 60 + + hours * 3600 + + days * 86400; + + base += totalSeconds; + + struct tm newT; + localtime_r(&base, &newT); + + return tmToGroundValue(newT); + +} \ No newline at end of file diff --git a/libs/datetime/date_functions.h b/libs/datetime/date_functions.h new file mode 100644 index 0000000..7d90812 --- /dev/null +++ b/libs/datetime/date_functions.h @@ -0,0 +1,18 @@ +#pragma once +#define _XOPEN_SOURCE // to make gcc happy lol + +#include +#include +#include + +GroundValue datetime_Now(GroundScope* scope, List args); +GroundValue datetime_Format(GroundScope* scope, List args); +GroundValue datetime_FromFormatted(GroundScope* scope, List args); +GroundValue datetime_ToISO8601UTC(GroundScope* scope, List args); +GroundValue datetime_ToISO8601Local(GroundScope* scope, List args); +GroundValue datetime_FromEpochLocal(GroundScope* scope, List args); +GroundValue datetime_FromEpochUTC(GroundScope* scope, List args); +GroundValue datetime_ToEpochLocal(GroundScope* scope, List args); +GroundValue datetime_ToEpochUTC(GroundScope* scope, List args); +GroundValue datetime_Diff(GroundScope* scope, List args); +GroundValue datetime_Add(GroundScope* scope, List args); \ No newline at end of file diff --git a/libs/datetime/datetime.c b/libs/datetime/datetime.c new file mode 100644 index 0000000..3c56e4c --- /dev/null +++ b/libs/datetime/datetime.c @@ -0,0 +1,18 @@ +#include "time_functions.h" +#include "date_functions.h" + + +void ground_init(GroundScope* scope) { + groundAddNativeFunction(scope, "datetime_NowEpoch", datetime_NowEpoch, DOUBLE, 0); + groundAddNativeFunction(scope, "datetime_Now", datetime_Now, CUSTOM, 0); + groundAddNativeFunction(scope, "datetime_Format", datetime_Format, STRING, 2, CUSTOM, "datetime", STRING, "format"); + groundAddNativeFunction(scope, "datetime_FromFormatted", datetime_FromFormatted, CUSTOM, 2, STRING, "datetimeString", STRING, "format"); + groundAddNativeFunction(scope, "datetime_ToISO8601UTC", datetime_ToISO8601UTC, STRING, 1, CUSTOM, "datetime"); + groundAddNativeFunction(scope, "datetime_ToISO8601Local", datetime_ToISO8601Local, STRING, 1, CUSTOM, "datetime"); + groundAddNativeFunction(scope, "datetime_FromEpochUTC", datetime_FromEpochUTC, CUSTOM, 1, DOUBLE, "epoch"); + groundAddNativeFunction(scope, "datetime_FromEpochLocal", datetime_FromEpochLocal, CUSTOM, 1, DOUBLE, "epoch"); + groundAddNativeFunction(scope, "datetime_ToEpochUTC", datetime_ToEpochUTC, INT, 1, CUSTOM, "datetime"); + groundAddNativeFunction(scope, "datetime_ToEpochLocal", datetime_ToEpochLocal, INT, 1, CUSTOM, "datetime"); + groundAddNativeFunction(scope, "datetime_Diff", datetime_Diff, INT, 2, CUSTOM, "datetime1", CUSTOM, "datetime2"); + groundAddNativeFunction(scope, "datetime_Add", datetime_Add, CUSTOM, 5, CUSTOM, "datetime", INT, "seconds", INT, "minutes", INT, "hours", INT, "days"); +} \ No newline at end of file diff --git a/libs/datetime/time_functions.c b/libs/datetime/time_functions.c new file mode 100644 index 0000000..a682c91 --- /dev/null +++ b/libs/datetime/time_functions.c @@ -0,0 +1,12 @@ +#include "time_functions.h" + +GroundValue datetime_NowEpoch(GroundScope* scope, List args) { + // grab time from system clock + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + + // convert it to secs and return it + double secsSinceEpoch = (double)ts.tv_sec + (double)ts.tv_nsec / 1e9; + + return groundCreateValue(DOUBLE, secsSinceEpoch); +} \ No newline at end of file diff --git a/libs/datetime/time_functions.h b/libs/datetime/time_functions.h new file mode 100644 index 0000000..17e0256 --- /dev/null +++ b/libs/datetime/time_functions.h @@ -0,0 +1,5 @@ +#pragma once +#include +#include + +GroundValue datetime_NowEpoch(GroundScope* scope, List args); \ No newline at end of file