snac2

Fork of https://codeberg.org/grunfink/snac2
git clone https://git.inz.fi/snac2
Log | Files | Refs | README | LICENSE

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 */