aboutsummaryrefslogtreecommitdiff
path: root/src/date.c
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2024-02-08 21:19:38 +0200
committerKimplul <kimi.h.kuparinen@gmail.com>2024-02-08 21:19:38 +0200
commitc035571d85e3d756804519d82de8b354f3910b29 (patch)
tree89714e13753d200d6e9a04f0d19d6dd1f7a55b2e /src/date.c
downloadposthaste-c035571d85e3d756804519d82de8b354f3910b29.tar.gz
posthaste-c035571d85e3d756804519d82de8b354f3910b29.zip
project work phase 1
Diffstat (limited to 'src/date.c')
-rw-r--r--src/date.c72
1 files changed, 72 insertions, 0 deletions
diff --git a/src/date.c b/src/date.c
new file mode 100644
index 0000000..7e6bc77
--- /dev/null
+++ b/src/date.c
@@ -0,0 +1,72 @@
+#include <time.h>
+
+#include <posthaste/date.h>
+
+ph_date_t date_from_string(const char str[static 11])
+{
+ unsigned year = (str[0] - '0') * 1000
+ + (str[1] - '0') * 100
+ + (str[2] - '0') * 10
+ + (str[3] - '0');
+
+ unsigned month = (str[5] - '0') * 10
+ + (str[6] - '0');
+
+ unsigned day = (str[8] - '0') * 10
+ + (str[9] - '0');
+
+ return date_from_numbers(year, month, day);
+}
+
+ph_date_t date_from_numbers(unsigned year, unsigned month, unsigned day)
+{
+ return year << 9 | month << 5 | day;
+}
+
+void date_split(ph_date_t date, unsigned *year, unsigned *month, unsigned *day)
+{
+ if (year) *year = date >> 9;
+ if (month) *month = (date >> 5) & 0xf;
+ if (day) *day = date & 0x1f;
+}
+
+void date_to_string(char str[static 11], ph_date_t date)
+{
+ unsigned year, month, day;
+ date_split(date, &year, &month, &day);
+
+ str[0] = '0' + (year / 1000) % 10;
+ str[1] = '0' + (year / 100) % 10;
+ str[2] = '0' + (year / 10) % 10;
+ str[3] = '0' + year % 10;
+ str[4] = '-';
+ str[5] = '0' + (month / 10) % 10;
+ str[6] = '0' + month % 10;
+ str[7] = '-';
+ str[8] = '0' + (day / 10) % 10;
+ str[9] = '0' + day % 10;
+ str[10] = '\0';
+}
+
+bool date_valid(ph_date_t date)
+{
+ unsigned year, month, day;
+ date_split(date, &year, &month, &day);
+
+ struct tm tm = {0};
+ tm.tm_year = year;
+ /* goddammit */
+ tm.tm_mon = month - 1;
+ tm.tm_mday = day;
+
+ time_t r = mktime(&tm);
+ /* if mktime fails to represent our time, it returns -1. mktime somewhat
+ * curiously accepts dates outside regular ranges, like negative time,
+ * but adjusts the tm structure to be 'correct', so we can check if any
+ * of the times were modified to see if this is a valid time. */
+ if (r == -1 || (int)year != tm.tm_year
+ || (int)month != tm.tm_mon + 1|| (int)day != tm.tm_mday)
+ return false;
+
+ return true;
+}