Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-or-later
3 : *
4 : * This file is part of colopresso
5 : *
6 : * Copyright (C) 2025-2026 COLOPL, Inc.
7 : *
8 : * Author: Go Kudo <g-kudo@colopl.co.jp>
9 : * Developed with AI (LLM) code assistance. See `NOTICE` for details.
10 : */
11 :
12 : #include <stdbool.h>
13 : #include <stdio.h>
14 : #include <stdlib.h>
15 :
16 : #include <time.h>
17 :
18 : #include <colopresso/datetime.h>
19 : #include <colopresso/portable.h>
20 :
21 : struct _cpres_datetime_t {
22 : uint16_t year;
23 : uint8_t month;
24 : uint8_t day;
25 : uint8_t hour;
26 : uint8_t min;
27 : uint8_t sec;
28 : };
29 :
30 2 : extern cpres_datetime_timestamp_t cpres_datetime_timestamp(void)
31 : {
32 : time_t tm;
33 :
34 2 : tm = time(NULL);
35 2 : if (tm == -1) {
36 0 : return 0;
37 : }
38 :
39 2 : return (cpres_datetime_timestamp_t)tm;
40 : }
41 :
42 12 : extern void cpres_datetime_destroy(cpres_datetime_t *pdt)
43 : {
44 12 : if (!pdt) {
45 1 : return;
46 : }
47 :
48 11 : free(pdt);
49 : }
50 :
51 11 : extern cpres_datetime_t *cpres_datetime_create_from_timestamp(cpres_datetime_timestamp_t timestamp)
52 : {
53 : cpres_datetime_t *pdt;
54 : time_t t;
55 : struct tm tm;
56 :
57 11 : t = (time_t)timestamp;
58 11 : if (!gmtime_r(&t, &tm)) {
59 0 : return NULL;
60 : }
61 :
62 11 : pdt = (cpres_datetime_t *)malloc(sizeof(cpres_datetime_t));
63 11 : if (!pdt) {
64 0 : return NULL;
65 : }
66 :
67 11 : pdt->year = (uint16_t)(tm.tm_year + 1900);
68 11 : pdt->month = (uint8_t)tm.tm_mon + 1;
69 11 : pdt->day = (uint8_t)tm.tm_mday;
70 11 : pdt->hour = (uint8_t)tm.tm_hour;
71 11 : pdt->min = (uint8_t)tm.tm_min;
72 11 : pdt->sec = (uint8_t)tm.tm_sec;
73 :
74 11 : return pdt;
75 : }
76 :
77 1 : extern cpres_datetime_t *cpres_datetime_create(void)
78 : {
79 1 : return cpres_datetime_create_from_timestamp(cpres_datetime_timestamp());
80 : }
81 :
82 3 : extern cpres_datetime_timestamp_t cpres_datetime_get_timestamp(const cpres_datetime_t *pdt)
83 : {
84 3 : struct tm tm = {0}, gmt_tm;
85 : time_t local_time, gmt_time;
86 :
87 3 : if (!pdt) {
88 2 : return 0;
89 : }
90 :
91 1 : tm.tm_year = pdt->year - 1900;
92 1 : tm.tm_mon = pdt->month - 1;
93 1 : tm.tm_mday = pdt->day;
94 1 : tm.tm_hour = pdt->hour;
95 1 : tm.tm_min = pdt->min;
96 1 : tm.tm_sec = pdt->sec;
97 1 : tm.tm_isdst = -1;
98 1 : colopresso_tm_set_gmt_offset(&tm);
99 :
100 1 : local_time = mktime(&tm);
101 1 : if (local_time == -1) {
102 0 : return 0;
103 : }
104 :
105 1 : gmtime_r(&local_time, &gmt_tm);
106 1 : gmt_time = mktime(&gmt_tm);
107 :
108 1 : return (cpres_datetime_timestamp_t)local_time + (local_time - gmt_time);
109 : }
110 :
111 5 : extern uint16_t cpres_datetime_get_year(const cpres_datetime_t *pdt)
112 : {
113 5 : if (!pdt) {
114 2 : return 0;
115 : }
116 :
117 3 : return pdt->year;
118 : }
119 :
120 4 : extern uint8_t cpres_datetime_get_mon(const cpres_datetime_t *pdt)
121 : {
122 4 : if (!pdt) {
123 2 : return 0;
124 : }
125 :
126 2 : return pdt->month;
127 : }
128 :
129 4 : extern uint8_t cpres_datetime_get_day(const cpres_datetime_t *pdt)
130 : {
131 4 : if (!pdt) {
132 2 : return 0;
133 : }
134 :
135 2 : return pdt->day;
136 : }
137 :
138 3 : extern uint8_t cpres_datetime_get_hour(const cpres_datetime_t *pdt)
139 : {
140 3 : if (!pdt) {
141 2 : return 0;
142 : }
143 :
144 1 : return pdt->hour;
145 : }
146 :
147 3 : extern uint8_t cpres_datetime_get_min(const cpres_datetime_t *pdt)
148 : {
149 3 : if (!pdt) {
150 2 : return 0;
151 : }
152 :
153 1 : return pdt->min;
154 : }
155 :
156 3 : extern uint8_t cpres_datetime_get_sec(const cpres_datetime_t *pdt)
157 : {
158 3 : if (!pdt) {
159 2 : return 0;
160 : }
161 :
162 1 : return pdt->sec;
163 : }
164 :
165 : /**
166 : * 32bit buildtime structure
167 : *
168 : * - UTC only.
169 : * - Theses are not supported:
170 : * - summer time
171 : * - time zone
172 : *
173 : * year (Y) : 12bit => 2^12-1 = 4095 use: ALL
174 : * month (M) : 4bit => 2^4-1 = 15 use: 1-12
175 : * day (D) : 5bit => 2^5-1 = 31 use: 1-31
176 : * hour (H) : 5bit => 2^5-1 = 31 use: 0-23
177 : * minute (M) : 6bit => 2^6-1 = 63 use: 0-59
178 : *
179 : * HIGH LOW
180 : * |--------------------------------|
181 : * |YYYYYYYYYYYYMMMMDDDDDHHHHHMMMMMM|
182 : * |--------------------------------|
183 : * 32 20 16 11 6 0
184 : *
185 : * e.g.
186 : * - Min: 0000-01-01 00:00 => 00000000000000010000100000000000 => 0x0010800
187 : * - Max: 4095-12-31 23:59 => 11111111111111001111110111111011 => 0xFFFCFDFB
188 : */
189 : extern cpres_datetime_buildtime_t
190 4 : cpres_datetime_encode_buildtime(cpres_datetime_timestamp_t timestamp)
191 : {
192 : cpres_datetime_t *pdt;
193 : cpres_datetime_buildtime_t bt;
194 :
195 4 : pdt = cpres_datetime_create_from_timestamp(timestamp);
196 4 : if (!pdt) {
197 0 : return 0;
198 : }
199 :
200 4 : bt = 0;
201 4 : bt |= ((cpres_datetime_buildtime_t)(pdt->year) & 0xFFF) << 20;
202 4 : bt |= ((cpres_datetime_buildtime_t)(pdt->month) & 0xF) << 16;
203 4 : bt |= ((cpres_datetime_buildtime_t)(pdt->day) & 0x1F) << 11;
204 4 : bt |= ((cpres_datetime_buildtime_t)(pdt->hour) & 0x1F) << 6;
205 4 : bt |= ((cpres_datetime_buildtime_t)(pdt->min) & 0x3F);
206 :
207 4 : cpres_datetime_destroy(pdt);
208 :
209 4 : return bt;
210 : }
211 :
212 : extern cpres_datetime_timestamp_t
213 4 : cpres_datetime_decode_buildtime(cpres_datetime_buildtime_t buildtime)
214 : {
215 4 : struct tm t = {0}, gmt_tm;
216 : time_t local_time, gmt_time;
217 :
218 4 : t.tm_year = ((buildtime >> 20) & 0xFFF) - 1900;
219 4 : t.tm_mon = ((buildtime >> 16) & 0xF) - 1;
220 4 : t.tm_mday = (buildtime >> 11) & 0x1F;
221 4 : t.tm_hour = (buildtime >> 6) & 0x1F;
222 4 : t.tm_min = buildtime & 0x3F;
223 4 : t.tm_sec = 0;
224 4 : t.tm_isdst = -1;
225 4 : colopresso_tm_set_gmt_offset(&t);
226 :
227 4 : local_time = mktime(&t);
228 4 : if (local_time == -1) {
229 0 : return 0;
230 : }
231 :
232 4 : gmtime_r(&local_time, &gmt_tm);
233 4 : gmt_time = mktime(&gmt_tm);
234 :
235 4 : return (cpres_datetime_timestamp_t)local_time + (local_time - gmt_time);
236 : }
237 :
238 2 : extern bool cpres_datetime_buildtime2str(cpres_datetime_buildtime_t buildtime,
239 : cpres_datetime_buildtime_str_t str)
240 : {
241 : cpres_datetime_t *pdt;
242 :
243 2 : pdt = cpres_datetime_create_from_timestamp(cpres_datetime_decode_buildtime(buildtime));
244 2 : if (pdt == NULL) {
245 0 : return false;
246 : }
247 :
248 2 : snprintf(str, CPRES_DT_BUILDTIME_LENGTH, "%04u-%02u-%02u %02u:%02u UTC", pdt->year, pdt->month,
249 2 : pdt->day, pdt->hour, pdt->min);
250 :
251 2 : cpres_datetime_destroy(pdt);
252 :
253 2 : return true;
254 : }
|