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 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 : cpres_datetime_timestamp_t cpres_datetime_timestamp(void) {
31 : time_t tm;
32 :
33 2 : tm = time(NULL);
34 2 : if (tm == -1) {
35 0 : return 0;
36 : }
37 :
38 2 : return (cpres_datetime_timestamp_t)tm;
39 : }
40 :
41 12 : void cpres_datetime_destroy(cpres_datetime_t *pdt) {
42 12 : if (!pdt) {
43 1 : return;
44 : }
45 :
46 11 : free(pdt);
47 : }
48 :
49 11 : cpres_datetime_t *cpres_datetime_create_from_timestamp(cpres_datetime_timestamp_t timestamp) {
50 : cpres_datetime_t *pdt;
51 : time_t t;
52 : struct tm tm;
53 :
54 11 : t = (time_t)timestamp;
55 11 : if (!gmtime_r(&t, &tm)) {
56 0 : return NULL;
57 : }
58 :
59 11 : pdt = (cpres_datetime_t *)malloc(sizeof(cpres_datetime_t));
60 11 : if (!pdt) {
61 0 : return NULL;
62 : }
63 :
64 11 : pdt->year = (uint16_t)(tm.tm_year + 1900);
65 11 : pdt->month = (uint8_t)tm.tm_mon + 1;
66 11 : pdt->day = (uint8_t)tm.tm_mday;
67 11 : pdt->hour = (uint8_t)tm.tm_hour;
68 11 : pdt->min = (uint8_t)tm.tm_min;
69 11 : pdt->sec = (uint8_t)tm.tm_sec;
70 :
71 11 : return pdt;
72 : }
73 :
74 1 : cpres_datetime_t *cpres_datetime_create(void) { return cpres_datetime_create_from_timestamp(cpres_datetime_timestamp()); }
75 :
76 3 : cpres_datetime_timestamp_t cpres_datetime_get_timestamp(const cpres_datetime_t *pdt) {
77 3 : struct tm tm = {0};
78 : time_t local_time, gmt_time;
79 : struct tm gmt_tm;
80 :
81 3 : if (!pdt) {
82 2 : return 0;
83 : }
84 :
85 1 : tm.tm_year = pdt->year - 1900;
86 1 : tm.tm_mon = pdt->month - 1;
87 1 : tm.tm_mday = pdt->day;
88 1 : tm.tm_hour = pdt->hour;
89 1 : tm.tm_min = pdt->min;
90 1 : tm.tm_sec = pdt->sec;
91 1 : tm.tm_isdst = -1;
92 1 : colopresso_tm_set_gmt_offset(&tm);
93 :
94 1 : local_time = mktime(&tm);
95 1 : if (local_time == -1) {
96 0 : return 0;
97 : }
98 :
99 1 : gmtime_r(&local_time, &gmt_tm);
100 1 : gmt_time = mktime(&gmt_tm);
101 :
102 1 : return (cpres_datetime_timestamp_t)local_time + (local_time - gmt_time);
103 : }
104 :
105 5 : uint16_t cpres_datetime_get_year(const cpres_datetime_t *pdt) {
106 5 : if (!pdt) {
107 2 : return 0;
108 : }
109 :
110 3 : return pdt->year;
111 : }
112 :
113 4 : uint8_t cpres_datetime_get_mon(const cpres_datetime_t *pdt) {
114 4 : if (!pdt) {
115 2 : return 0;
116 : }
117 :
118 2 : return pdt->month;
119 : }
120 :
121 4 : uint8_t cpres_datetime_get_day(const cpres_datetime_t *pdt) {
122 4 : if (!pdt) {
123 2 : return 0;
124 : }
125 :
126 2 : return pdt->day;
127 : }
128 :
129 3 : uint8_t cpres_datetime_get_hour(const cpres_datetime_t *pdt) {
130 3 : if (!pdt) {
131 2 : return 0;
132 : }
133 :
134 1 : return pdt->hour;
135 : }
136 :
137 3 : uint8_t cpres_datetime_get_min(const cpres_datetime_t *pdt) {
138 3 : if (!pdt) {
139 2 : return 0;
140 : }
141 :
142 1 : return pdt->min;
143 : }
144 :
145 3 : uint8_t cpres_datetime_get_sec(const cpres_datetime_t *pdt) {
146 3 : if (!pdt) {
147 2 : return 0;
148 : }
149 :
150 1 : return pdt->sec;
151 : }
152 :
153 : /**
154 : * 32bit buildtime structure
155 : *
156 : * - UTC only.
157 : * - Theses are not supported:
158 : * - summer time
159 : * - time zone
160 : *
161 : * year (Y) : 12bit => 2^12-1 = 4095 use: ALL
162 : * month (M) : 4bit => 2^4-1 = 15 use: 1-12
163 : * day (D) : 5bit => 2^5-1 = 31 use: 1-31
164 : * hour (H) : 5bit => 2^5-1 = 31 use: 0-23
165 : * minute (M) : 6bit => 2^6-1 = 63 use: 0-59
166 : *
167 : * HIGH LOW
168 : * |--------------------------------|
169 : * |YYYYYYYYYYYYMMMMDDDDDHHHHHMMMMMM|
170 : * |--------------------------------|
171 : * 32 20 16 11 6 0
172 : *
173 : * e.g.
174 : * - Min: 0000-01-01 00:00 => 00000000000000010000100000000000 => 0x0010800
175 : * - Max: 4095-12-31 23:59 => 11111111111111001111110111111011 => 0xFFFCFDFB
176 : */
177 4 : cpres_datetime_buildtime_t cpres_datetime_encode_buildtime(cpres_datetime_timestamp_t timestamp) {
178 : cpres_datetime_t *pdt;
179 : cpres_datetime_buildtime_t bt;
180 :
181 4 : pdt = cpres_datetime_create_from_timestamp(timestamp);
182 4 : if (!pdt) {
183 0 : return 0;
184 : }
185 :
186 4 : bt = 0;
187 4 : bt |= ((cpres_datetime_buildtime_t)(pdt->year) & 0xFFF) << 20;
188 4 : bt |= ((cpres_datetime_buildtime_t)(pdt->month) & 0xF) << 16;
189 4 : bt |= ((cpres_datetime_buildtime_t)(pdt->day) & 0x1F) << 11;
190 4 : bt |= ((cpres_datetime_buildtime_t)(pdt->hour) & 0x1F) << 6;
191 4 : bt |= ((cpres_datetime_buildtime_t)(pdt->min) & 0x3F);
192 :
193 4 : cpres_datetime_destroy(pdt);
194 :
195 4 : return bt;
196 : }
197 :
198 4 : cpres_datetime_timestamp_t cpres_datetime_decode_buildtime(cpres_datetime_buildtime_t buildtime) {
199 4 : struct tm t = {0};
200 : time_t local_time, gmt_time;
201 : struct tm gmt_tm;
202 :
203 4 : t.tm_year = ((buildtime >> 20) & 0xFFF) - 1900;
204 4 : t.tm_mon = ((buildtime >> 16) & 0xF) - 1;
205 4 : t.tm_mday = (buildtime >> 11) & 0x1F;
206 4 : t.tm_hour = (buildtime >> 6) & 0x1F;
207 4 : t.tm_min = buildtime & 0x3F;
208 4 : t.tm_sec = 0;
209 4 : t.tm_isdst = -1;
210 4 : colopresso_tm_set_gmt_offset(&t);
211 :
212 4 : local_time = mktime(&t);
213 4 : if (local_time == -1) {
214 0 : return 0;
215 : }
216 :
217 4 : gmtime_r(&local_time, &gmt_tm);
218 4 : gmt_time = mktime(&gmt_tm);
219 :
220 4 : return (cpres_datetime_timestamp_t)local_time + (local_time - gmt_time);
221 : }
222 :
223 2 : bool cpres_datetime_buildtime2str(cpres_datetime_buildtime_t buildtime, cpres_datetime_buildtime_str_t str) {
224 : cpres_datetime_t *pdt;
225 :
226 2 : pdt = cpres_datetime_create_from_timestamp(cpres_datetime_decode_buildtime(buildtime));
227 2 : if (pdt == NULL) {
228 0 : return false;
229 : }
230 :
231 2 : snprintf(str, CPRES_DT_BUILDTIME_LENGTH, "%04u-%02u-%02u %02u:%02u UTC", pdt->year, pdt->month, pdt->day, pdt->hour, pdt->min);
232 :
233 2 : cpres_datetime_destroy(pdt);
234 :
235 2 : return true;
236 : }
|