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