main
xs_time.h
1/* copyright (c) 2022 - 2026 grunfink et al. / MIT license */
2
3#ifndef _XS_TIME_H
4
5#define _XS_TIME_H
6
7#include "xs.h"
8#include <time.h>
9
10xs_str *xs_str_time(time_t t, const char *fmt, int local);
11#define xs_str_localtime(t, fmt) xs_str_time(t, fmt, 1)
12#define xs_str_utctime(t, fmt) xs_str_time(t, fmt, 0)
13#define xs_str_iso_date(t) xs_str_time(t, "%Y-%m-%dT%H:%M:%SZ", 0)
14time_t xs_parse_iso_date(const char *iso_date, int local);
15time_t xs_parse_time(const char *str, const char *fmt, int local);
16#define xs_parse_localtime(str, fmt) xs_parse_time(str, fmt, 1)
17#define xs_parse_utctime(str, fmt) xs_parse_time(str, fmt, 0)
18xs_str *xs_str_time_diff(time_t time_diff);
19xs_list *xs_tz_list(void);
20int xs_tz_offset(const char *tz);
21
22#ifdef XS_IMPLEMENTATION
23
24xs_str *xs_str_time(time_t t, const char *fmt, int local)
25/* returns a string with a formated time */
26{
27 struct tm tm;
28 char tmp[64];
29
30 if (t == 0)
31 t = time(NULL);
32
33 if (local)
34 localtime_r(&t, &tm);
35 else
36 gmtime_r(&t, &tm);
37
38 strftime(tmp, sizeof(tmp), fmt, &tm);
39
40 return xs_str_new(tmp);
41}
42
43
44xs_str *xs_str_time_diff(time_t time_diff)
45/* returns time_diff in seconds to 'human' units (d:hh:mm:ss) */
46{
47 int secs = time_diff % 60;
48 int mins = (time_diff /= 60) % 60;
49 int hours = (time_diff /= 60) % 24;
50 int days = (time_diff /= 24);
51
52 return xs_fmt("%d:%02d:%02d:%02d", days, hours, mins, secs);
53}
54
55
56char *strptime(const char *s, const char *format, struct tm *tm);
57
58time_t xs_parse_time(const char *str, const char *fmt, int local)
59{
60 time_t t = 0;
61
62#ifndef WITHOUT_STRPTIME
63
64 struct tm tm = {0};
65
66 strptime(str, fmt, &tm);
67
68 /* try to guess the Daylight Saving Time */
69 if (local)
70 tm.tm_isdst = -1;
71
72 t = local ? mktime(&tm) : timegm(&tm);
73
74#endif /* WITHOUT_STRPTIME */
75
76 return t;
77}
78
79
80time_t xs_parse_iso_date(const char *iso_date, int local)
81/* parses a YYYY-MM-DDTHH:MM:SS date string */
82{
83 time_t t = 0;
84
85#ifndef WITHOUT_STRPTIME
86
87 t = xs_parse_time(iso_date, "%Y-%m-%dT%H:%M:%S", local);
88
89#else /* WITHOUT_STRPTIME */
90
91 struct tm tm = {0};
92
93 if (sscanf(iso_date, "%d-%d-%dT%d:%d:%d",
94 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
95 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6) {
96
97 tm.tm_year -= 1900;
98 tm.tm_mon -= 1;
99
100 if (local)
101 tm.tm_isdst = -1;
102
103 t = local ? mktime(&tm) : timegm(&tm);
104 }
105
106#endif /* WITHOUT_STRPTIME */
107
108 return t;
109}
110
111
112/** timezones **/
113
114/* intentionally dead simple */
115
116struct {
117 const char *tz; /* timezone name */
118 float h_offset; /* hour offset */
119} xs_tz[] = {
120 { "UTC", 0 },
121 { "WET (Western European Time)", 0 },
122 { "WEST (Western European Summer Time)", 1 },
123 { "CET (Central European Time)", 1 },
124 { "CEST (Central European Summer Time)", 2 },
125 { "EET (Eastern European Time)", 2 },
126 { "EEST (Eastern European Summer Time)", 3 },
127 { "MSK (Moskow Time Zone)", 3 },
128 { "EST (Eastern Time Zone)", -5 },
129 { "AST (Atlantic Time Zone)", -4 },
130 { "ADT (Atlantic Daylight Time Zone)", -3 },
131 { "CST (Central Time Zone)", -6 },
132 { "CDT (Central Daylight Time Zone)", -5 },
133 { "MST (Mountain Time Zone)", -7 },
134 { "MDT (Mountain Daylight Time Zone)", -6 },
135 { "PST (Pacific Time Zone)", -8 },
136 { "PDT (Pacific Daylight Time Zone)", -7 },
137 { "AKST (Alaska Time Zone)", -9 },
138 { "AKDT (Alaska Daylight Time Zone)", -8 },
139 { "China Time Zone", 8 },
140 { "IST (Indian Standard Time)", 5.5 },
141 { "IDT (Israel Daylight Standard Time)", 3 },
142 { "WIB (Western Indonesia Time)", 7 },
143 { "WITA (Central Indonesia Time)", 8 },
144 { "WIT (Eastern Indonesia Time)", 9 },
145 { "AWST (Australian Western Time)", 8 },
146 { "ACST (Australian Eastern Time)", 9.5 },
147 { "ACDT (Australian Daylight Eastern Time)", 10.5 },
148 { "AEST (Australian Eastern Time)", 10 },
149 { "AEDT (Australian Daylight Eastern Time)", 11 },
150 { "NZST (New Zealand Time)", 12 },
151 { "NZDT (New Zealand Daylight Time)", 13 },
152 { "UTC", 0 },
153 { "UTC+1", 1 },
154 { "UTC+2", 2 },
155 { "UTC+3", 3 },
156 { "UTC+4", 4 },
157 { "UTC+5", 5 },
158 { "UTC+6", 6 },
159 { "UTC+7", 7 },
160 { "UTC+8", 8 },
161 { "UTC+9", 9 },
162 { "UTC+10", 10 },
163 { "UTC+11", 11 },
164 { "UTC+12", 12 },
165 { "UTC-1", -1 },
166 { "UTC-2", -2 },
167 { "UTC-3", -3 },
168 { "UTC-4", -4 },
169 { "UTC-5", -5 },
170 { "UTC-6", -6 },
171 { "UTC-7", -7 },
172 { "UTC-8", -8 },
173 { "UTC-9", -9 },
174 { "UTC-10", -10 },
175 { "UTC-11", -11 },
176 { "UTC-12", -12 },
177 { "UTC-13", -13 },
178 { "UTC-14", -14 },
179 { "GMT", 0 },
180 { "GMT+1", 1 },
181 { "GMT+2", 2 },
182 { "GMT+3", 3 },
183 { "GMT+4", 4 },
184 { "GMT+5", 5 },
185 { "GMT+6", 6 },
186 { "GMT+7", 7 },
187 { "GMT+8", 8 },
188 { "GMT+9", 9 },
189 { "GMT+10", 10 },
190 { "GMT+11", 11 },
191 { "GMT+12", 12 },
192 { "GMT-1", -1 },
193 { "GMT-2", -2 },
194 { "GMT-3", -3 },
195 { "GMT-4", -4 },
196 { "GMT-5", -5 },
197 { "GMT-6", -6 },
198 { "GMT-7", -7 },
199 { "GMT-8", -8 },
200 { "GMT-9", -9 },
201 { "GMT-10", -10 },
202 { "GMT-11", -11 },
203 { "GMT-12", -12 },
204 { "GMT-13", -13 },
205 { "GMT-14", -14 },
206 { NULL, 0 }
207};
208
209
210xs_list *xs_tz_list(void)
211/* returns the list of supported timezones */
212{
213 xs_list *l = xs_list_new();
214
215 for (int n = 0; xs_tz[n].tz != NULL; n++)
216 l = xs_list_append(l, xs_tz[n].tz);
217
218 return l;
219}
220
221
222int xs_tz_offset(const char *tz)
223/* returns the offset in seconds from the specified Time Zone to UTC */
224{
225 for (int n = 0; xs_tz[n].tz != NULL; n++) {
226 if (strcmp(xs_tz[n].tz, tz) == 0)
227 return xs_tz[n].h_offset * 3600;
228 }
229
230 return 0;
231}
232
233
234#endif /* XS_IMPLEMENTATION */
235
236#endif /* _XS_TIME_H */