bfc1508d (kx 2023-03-24 03:55:33 +0300 1)
bfc1508d (kx 2023-03-24 03:55:33 +0300 2) #ifdef HAVE_CONFIG_H
bfc1508d (kx 2023-03-24 03:55:33 +0300 3) #include <config.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 4) #endif
bfc1508d (kx 2023-03-24 03:55:33 +0300 5)
bfc1508d (kx 2023-03-24 03:55:33 +0300 6) #include <stdlib.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 7) #include <stdio.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 8) #include <sys/sysinfo.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 9) #include <sys/types.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 10) #ifdef HAVE_INTTYPES_H
bfc1508d (kx 2023-03-24 03:55:33 +0300 11) #include <inttypes.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 12) #else
bfc1508d (kx 2023-03-24 03:55:33 +0300 13) #include <stdint.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 14) #endif
bfc1508d (kx 2023-03-24 03:55:33 +0300 15) #include <stddef.h> /* offsetof(3) */
bfc1508d (kx 2023-03-24 03:55:33 +0300 16) #include <dirent.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 17) #include <sys/stat.h> /* chmod(2) */
bfc1508d (kx 2023-03-24 03:55:33 +0300 18) #include <sys/file.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 19) #include <sys/mman.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 20) #include <fcntl.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 21) #include <limits.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 22) #include <string.h> /* strdup(3) */
bfc1508d (kx 2023-03-24 03:55:33 +0300 23) #include <libgen.h> /* basename(3) */
bfc1508d (kx 2023-03-24 03:55:33 +0300 24) #include <ctype.h> /* tolower(3) */
bfc1508d (kx 2023-03-24 03:55:33 +0300 25) #include <errno.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 26) #include <time.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 27) #include <sys/time.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 28) #include <pwd.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 29) #include <grp.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 30) #include <stdarg.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 31) #include <unistd.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 32)
bfc1508d (kx 2023-03-24 03:55:33 +0300 33) #include <nls.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 34)
bfc1508d (kx 2023-03-24 03:55:33 +0300 35) #include <defs.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 36)
bfc1508d (kx 2023-03-24 03:55:33 +0300 37) #include <strbuf.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 38) #include <date.h>
bfc1508d (kx 2023-03-24 03:55:33 +0300 39)
bfc1508d (kx 2023-03-24 03:55:33 +0300 40)
bfc1508d (kx 2023-03-24 03:55:33 +0300 41) /* Valid rule actions */
bfc1508d (kx 2023-03-24 03:55:33 +0300 42) enum rule_action
bfc1508d (kx 2023-03-24 03:55:33 +0300 43) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 44) ACCUM, /* Accumulate a decimal value */
bfc1508d (kx 2023-03-24 03:55:33 +0300 45) MICRO, /* Accumulate microseconds */
bfc1508d (kx 2023-03-24 03:55:33 +0300 46) TZIND, /* Handle +, -, Z */
bfc1508d (kx 2023-03-24 03:55:33 +0300 47) NOOP, /* Do nothing */
bfc1508d (kx 2023-03-24 03:55:33 +0300 48) SKIPFROM, /* If at end-of-value, accept the match. Otherwise,
bfc1508d (kx 2023-03-24 03:55:33 +0300 49) if the next template character matches the current
bfc1508d (kx 2023-03-24 03:55:33 +0300 50) value character, continue processing as normal.
bfc1508d (kx 2023-03-24 03:55:33 +0300 51) Otherwise, attempt to complete matching starting
bfc1508d (kx 2023-03-24 03:55:33 +0300 52) immediately after the first subsequent occurrance of
bfc1508d (kx 2023-03-24 03:55:33 +0300 53) ']' in the template. */
bfc1508d (kx 2023-03-24 03:55:33 +0300 54) SKIP, /* Ignore this template character */
bfc1508d (kx 2023-03-24 03:55:33 +0300 55) ACCEPT /* Accept the value */
bfc1508d (kx 2023-03-24 03:55:33 +0300 56) };
bfc1508d (kx 2023-03-24 03:55:33 +0300 57)
bfc1508d (kx 2023-03-24 03:55:33 +0300 58) /* How to handle a particular character in a template */
bfc1508d (kx 2023-03-24 03:55:33 +0300 59) struct rule
bfc1508d (kx 2023-03-24 03:55:33 +0300 60) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 61) char key; /* The template char that this rule matches */
bfc1508d (kx 2023-03-24 03:55:33 +0300 62) const char *valid; /* String of valid chars for this rule */
bfc1508d (kx 2023-03-24 03:55:33 +0300 63) enum rule_action action; /* What action to take when the rule is matched */
bfc1508d (kx 2023-03-24 03:55:33 +0300 64) int offset; /* Where to store the any results of the action,
bfc1508d (kx 2023-03-24 03:55:33 +0300 65) expressed in terms of bytes relative to the
bfc1508d (kx 2023-03-24 03:55:33 +0300 66) base of a match_state object. */
bfc1508d (kx 2023-03-24 03:55:33 +0300 67) };
bfc1508d (kx 2023-03-24 03:55:33 +0300 68)
bfc1508d (kx 2023-03-24 03:55:33 +0300 69) struct match_state
bfc1508d (kx 2023-03-24 03:55:33 +0300 70) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 71) struct tm base;
bfc1508d (kx 2023-03-24 03:55:33 +0300 72) struct timeval tv;
bfc1508d (kx 2023-03-24 03:55:33 +0300 73) int gmtoff;
bfc1508d (kx 2023-03-24 03:55:33 +0300 74) int gmtoff_hours;
bfc1508d (kx 2023-03-24 03:55:33 +0300 75) int gmtoff_minutes;
bfc1508d (kx 2023-03-24 03:55:33 +0300 76) };
bfc1508d (kx 2023-03-24 03:55:33 +0300 77)
bfc1508d (kx 2023-03-24 03:55:33 +0300 78)
bfc1508d (kx 2023-03-24 03:55:33 +0300 79) #define DIGITS "0123456789"
bfc1508d (kx 2023-03-24 03:55:33 +0300 80)
bfc1508d (kx 2023-03-24 03:55:33 +0300 81) /*
bfc1508d (kx 2023-03-24 03:55:33 +0300 82) A declarative specification of how each template character
bfc1508d (kx 2023-03-24 03:55:33 +0300 83) should be processed, using a rule for each valid symbol.
bfc1508d (kx 2023-03-24 03:55:33 +0300 84) */
bfc1508d (kx 2023-03-24 03:55:33 +0300 85) static const struct rule rules[] =
bfc1508d (kx 2023-03-24 03:55:33 +0300 86) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 87) { 'Y', DIGITS, ACCUM, offsetof(struct match_state, base.tm_year) },
bfc1508d (kx 2023-03-24 03:55:33 +0300 88) { 'M', DIGITS, ACCUM, offsetof(struct match_state, base.tm_mon) },
bfc1508d (kx 2023-03-24 03:55:33 +0300 89) { 'D', DIGITS, ACCUM, offsetof(struct match_state, base.tm_mday) },
bfc1508d (kx 2023-03-24 03:55:33 +0300 90) { 'h', DIGITS, ACCUM, offsetof(struct match_state, base.tm_hour) },
bfc1508d (kx 2023-03-24 03:55:33 +0300 91) { 'm', DIGITS, ACCUM, offsetof(struct match_state, base.tm_min) },
bfc1508d (kx 2023-03-24 03:55:33 +0300 92) { 's', DIGITS, ACCUM, offsetof(struct match_state, base.tm_sec) },
bfc1508d (kx 2023-03-24 03:55:33 +0300 93) { 'u', DIGITS, MICRO, offsetof(struct match_state, tv.tv_usec) },
bfc1508d (kx 2023-03-24 03:55:33 +0300 94) { 'O', DIGITS, ACCUM, offsetof(struct match_state, gmtoff_hours) },
bfc1508d (kx 2023-03-24 03:55:33 +0300 95) { 'o', DIGITS, ACCUM, offsetof(struct match_state, gmtoff_minutes) },
bfc1508d (kx 2023-03-24 03:55:33 +0300 96) { '+', "-+", TZIND, 0 },
bfc1508d (kx 2023-03-24 03:55:33 +0300 97) { 'Z', "Z", TZIND, 0 },
bfc1508d (kx 2023-03-24 03:55:33 +0300 98) { ':', ":", NOOP, 0 },
bfc1508d (kx 2023-03-24 03:55:33 +0300 99) { '-', "-", NOOP, 0 },
bfc1508d (kx 2023-03-24 03:55:33 +0300 100) { 'T', "T", NOOP, 0 },
bfc1508d (kx 2023-03-24 03:55:33 +0300 101) { ' ', " ", NOOP, 0 },
bfc1508d (kx 2023-03-24 03:55:33 +0300 102) { '.', ".,", NOOP, 0 },
bfc1508d (kx 2023-03-24 03:55:33 +0300 103) { '[', NULL, SKIPFROM, 0 },
bfc1508d (kx 2023-03-24 03:55:33 +0300 104) { ']', NULL, SKIP, 0 },
bfc1508d (kx 2023-03-24 03:55:33 +0300 105) { '\0', NULL, ACCEPT, 0 },
bfc1508d (kx 2023-03-24 03:55:33 +0300 106) };
bfc1508d (kx 2023-03-24 03:55:33 +0300 107)
bfc1508d (kx 2023-03-24 03:55:33 +0300 108) /* Return the rule associated with TCHAR, or NULL if there is no such rule. */
bfc1508d (kx 2023-03-24 03:55:33 +0300 109) static const struct rule *find_rule( char tchar )
bfc1508d (kx 2023-03-24 03:55:33 +0300 110) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 111) int i = sizeof(rules)/sizeof(rules[0]);
bfc1508d (kx 2023-03-24 03:55:33 +0300 112) while( i-- )
bfc1508d (kx 2023-03-24 03:55:33 +0300 113) if( rules[i].key == tchar )
bfc1508d (kx 2023-03-24 03:55:33 +0300 114) return &rules[i];
bfc1508d (kx 2023-03-24 03:55:33 +0300 115) return NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300 116) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 117)
bfc1508d (kx 2023-03-24 03:55:33 +0300 118) /*
bfc1508d (kx 2023-03-24 03:55:33 +0300 119) Attempt to match the date-string in VALUE to the provided TEMPLATE,
bfc1508d (kx 2023-03-24 03:55:33 +0300 120) using the rules defined above. Return TRUE on successful match,
bfc1508d (kx 2023-03-24 03:55:33 +0300 121) FALSE otherwise. On successful match, fill in *TM with the
bfc1508d (kx 2023-03-24 03:55:33 +0300 122) matched values and set *LOCALTZ to GMT-offset if the local time zone
bfc1508d (kx 2023-03-24 03:55:33 +0300 123) should be used to interpret the match.
bfc1508d (kx 2023-03-24 03:55:33 +0300 124) */
bfc1508d (kx 2023-03-24 03:55:33 +0300 125) static int template_match( struct tm *tm, int *localtz, const char *template, const char *value )
bfc1508d (kx 2023-03-24 03:55:33 +0300 126) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 127) int multiplier = 100000;
bfc1508d (kx 2023-03-24 03:55:33 +0300 128) int tzind = 0;
bfc1508d (kx 2023-03-24 03:55:33 +0300 129) struct match_state ms;
bfc1508d (kx 2023-03-24 03:55:33 +0300 130) char *base = (char *)&ms;
bfc1508d (kx 2023-03-24 03:55:33 +0300 131)
bfc1508d (kx 2023-03-24 03:55:33 +0300 132) memset( &ms, 0, sizeof(ms) );
bfc1508d (kx 2023-03-24 03:55:33 +0300 133)
bfc1508d (kx 2023-03-24 03:55:33 +0300 134) for( ;; )
bfc1508d (kx 2023-03-24 03:55:33 +0300 135) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 136) const struct rule *match = find_rule(*template++);
bfc1508d (kx 2023-03-24 03:55:33 +0300 137) char vchar = *value++;
bfc1508d (kx 2023-03-24 03:55:33 +0300 138) int *place;
bfc1508d (kx 2023-03-24 03:55:33 +0300 139)
bfc1508d (kx 2023-03-24 03:55:33 +0300 140) if( !match || (match->valid && (!vchar || !strchr(match->valid, vchar))) )
bfc1508d (kx 2023-03-24 03:55:33 +0300 141) return FALSE;
bfc1508d (kx 2023-03-24 03:55:33 +0300 142)
bfc1508d (kx 2023-03-24 03:55:33 +0300 143) /* Compute the address of memory location affected by this
bfc1508d (kx 2023-03-24 03:55:33 +0300 144) rule by adding match->offset bytes to the address of ms.
bfc1508d (kx 2023-03-24 03:55:33 +0300 145) Because this is a byte-quantity, it is necessary to cast
bfc1508d (kx 2023-03-24 03:55:33 +0300 146) &ms to char *. */
bfc1508d (kx 2023-03-24 03:55:33 +0300 147) place = (int *)(base + match->offset);
bfc1508d (kx 2023-03-24 03:55:33 +0300 148) switch( match->action )
bfc1508d (kx 2023-03-24 03:55:33 +0300 149) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 150) case ACCUM:
bfc1508d (kx 2023-03-24 03:55:33 +0300 151) *place = *place * 10 + vchar - '0';
bfc1508d (kx 2023-03-24 03:55:33 +0300 152) continue;
bfc1508d (kx 2023-03-24 03:55:33 +0300 153) case MICRO:
bfc1508d (kx 2023-03-24 03:55:33 +0300 154) *place += (vchar - '0') * multiplier;
bfc1508d (kx 2023-03-24 03:55:33 +0300 155) multiplier /= 10;
bfc1508d (kx 2023-03-24 03:55:33 +0300 156) continue;
bfc1508d (kx 2023-03-24 03:55:33 +0300 157) case TZIND:
bfc1508d (kx 2023-03-24 03:55:33 +0300 158) tzind = vchar;
bfc1508d (kx 2023-03-24 03:55:33 +0300 159) continue;
bfc1508d (kx 2023-03-24 03:55:33 +0300 160) case SKIP:
bfc1508d (kx 2023-03-24 03:55:33 +0300 161) value--;
bfc1508d (kx 2023-03-24 03:55:33 +0300 162) continue;
bfc1508d (kx 2023-03-24 03:55:33 +0300 163) case NOOP:
bfc1508d (kx 2023-03-24 03:55:33 +0300 164) continue;
bfc1508d (kx 2023-03-24 03:55:33 +0300 165) case SKIPFROM:
bfc1508d (kx 2023-03-24 03:55:33 +0300 166) if( !vchar )
bfc1508d (kx 2023-03-24 03:55:33 +0300 167) break;
bfc1508d (kx 2023-03-24 03:55:33 +0300 168) match = find_rule(*template);
bfc1508d (kx 2023-03-24 03:55:33 +0300 169) if (!strchr(match->valid, vchar))
bfc1508d (kx 2023-03-24 03:55:33 +0300 170) template = strchr(template, ']') + 1;
bfc1508d (kx 2023-03-24 03:55:33 +0300 171) value--;
bfc1508d (kx 2023-03-24 03:55:33 +0300 172) continue;
bfc1508d (kx 2023-03-24 03:55:33 +0300 173) case ACCEPT:
bfc1508d (kx 2023-03-24 03:55:33 +0300 174) if( vchar )
bfc1508d (kx 2023-03-24 03:55:33 +0300 175) return FALSE;
bfc1508d (kx 2023-03-24 03:55:33 +0300 176) break;
bfc1508d (kx 2023-03-24 03:55:33 +0300 177) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 178)
bfc1508d (kx 2023-03-24 03:55:33 +0300 179) break;
bfc1508d (kx 2023-03-24 03:55:33 +0300 180) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 181)
bfc1508d (kx 2023-03-24 03:55:33 +0300 182) /* Validate gmt offset here, since we can't reliably do it later. */
bfc1508d (kx 2023-03-24 03:55:33 +0300 183) if( ms.gmtoff_hours > 23 || ms.gmtoff_minutes > 59 )
bfc1508d (kx 2023-03-24 03:55:33 +0300 184) return FALSE;
bfc1508d (kx 2023-03-24 03:55:33 +0300 185)
bfc1508d (kx 2023-03-24 03:55:33 +0300 186) /*
bfc1508d (kx 2023-03-24 03:55:33 +0300 187) tzind will be '+' or '-' for an explicit time zone,
bfc1508d (kx 2023-03-24 03:55:33 +0300 188) 'Z' to indicate UTC, or 0 to indicate local time.
bfc1508d (kx 2023-03-24 03:55:33 +0300 189) */
bfc1508d (kx 2023-03-24 03:55:33 +0300 190) switch( tzind )
bfc1508d (kx 2023-03-24 03:55:33 +0300 191) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 192) case '+':
bfc1508d (kx 2023-03-24 03:55:33 +0300 193) ms.gmtoff = ms.gmtoff_hours * 3600 + ms.gmtoff_minutes * 60;
bfc1508d (kx 2023-03-24 03:55:33 +0300 194) break;
bfc1508d (kx 2023-03-24 03:55:33 +0300 195) case '-':
bfc1508d (kx 2023-03-24 03:55:33 +0300 196) ms.gmtoff = -(ms.gmtoff_hours * 3600 + ms.gmtoff_minutes * 60);
bfc1508d (kx 2023-03-24 03:55:33 +0300 197) break;
bfc1508d (kx 2023-03-24 03:55:33 +0300 198) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 199)
bfc1508d (kx 2023-03-24 03:55:33 +0300 200) *tm = ms.base;
bfc1508d (kx 2023-03-24 03:55:33 +0300 201) *localtz = ms.gmtoff;
bfc1508d (kx 2023-03-24 03:55:33 +0300 202) return TRUE;
bfc1508d (kx 2023-03-24 03:55:33 +0300 203) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 204)
bfc1508d (kx 2023-03-24 03:55:33 +0300 205) static int valid_days_by_month[] =
bfc1508d (kx 2023-03-24 03:55:33 +0300 206) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 207) 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
bfc1508d (kx 2023-03-24 03:55:33 +0300 208) };
bfc1508d (kx 2023-03-24 03:55:33 +0300 209)
bfc1508d (kx 2023-03-24 03:55:33 +0300 210) /*
bfc1508d (kx 2023-03-24 03:55:33 +0300 211) Returns -1 on error,
bfc1508d (kx 2023-03-24 03:55:33 +0300 212) time_t as the number of seconds since Epoch, 1970-01-01 00:00:00 +0000 (UTC)
bfc1508d (kx 2023-03-24 03:55:33 +0300 213) on success.
bfc1508d (kx 2023-03-24 03:55:33 +0300 214) */
bfc1508d (kx 2023-03-24 03:55:33 +0300 215) time_t parse_date( struct tm *tm, const char *text )
bfc1508d (kx 2023-03-24 03:55:33 +0300 216) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 217) time_t n, ret = (time_t)-1;
bfc1508d (kx 2023-03-24 03:55:33 +0300 218) struct tm pt, *now;
bfc1508d (kx 2023-03-24 03:55:33 +0300 219) int localtz;
bfc1508d (kx 2023-03-24 03:55:33 +0300 220)
bfc1508d (kx 2023-03-24 03:55:33 +0300 221) n = time( NULL ); /* current UTC time */
bfc1508d (kx 2023-03-24 03:55:33 +0300 222) now = gmtime( &n );
bfc1508d (kx 2023-03-24 03:55:33 +0300 223)
bfc1508d (kx 2023-03-24 03:55:33 +0300 224)
bfc1508d (kx 2023-03-24 03:55:33 +0300 225) if( /* ISO-8601 extended, date only: */
bfc1508d (kx 2023-03-24 03:55:33 +0300 226) template_match( &pt, &localtz, "YYYY-M[M]-D[D]", text ) ||
bfc1508d (kx 2023-03-24 03:55:33 +0300 227) /* ISO-8601 extended, UTC: */
bfc1508d (kx 2023-03-24 03:55:33 +0300 228) template_match( &pt, &localtz, "YYYY-M[M]-D[D]Th[h]:mm[:ss[.u[u[u[u[u[u][Z]", text ) ||
bfc1508d (kx 2023-03-24 03:55:33 +0300 229) /* ISO-8601 extended, with offset: */
bfc1508d (kx 2023-03-24 03:55:33 +0300 230) template_match( &pt, &localtz, "YYYY-M[M]-D[D]Th[h]:mm[:ss[.u[u[u[u[u[u]+OO[:oo]", text ) ||
bfc1508d (kx 2023-03-24 03:55:33 +0300 231) /* ISO-8601 basic, date only */
bfc1508d (kx 2023-03-24 03:55:33 +0300 232) template_match( &pt, &localtz, "YYYYMMDD", text ) ||
bfc1508d (kx 2023-03-24 03:55:33 +0300 233) /* ISO-8601 basic, UTC: */
bfc1508d (kx 2023-03-24 03:55:33 +0300 234) template_match( &pt, &localtz, "YYYYMMDDThhmm[ss[.u[u[u[u[u[u][Z]", text ) ||
bfc1508d (kx 2023-03-24 03:55:33 +0300 235) /* ISO-8601 basic, with offset: */
bfc1508d (kx 2023-03-24 03:55:33 +0300 236) template_match( &pt, &localtz, "YYYYMMDDThhmm[ss[.u[u[u[u[u[u]+OO[oo]", text ) ||
bfc1508d (kx 2023-03-24 03:55:33 +0300 237) /* "svn log" format: */
bfc1508d (kx 2023-03-24 03:55:33 +0300 238) template_match( &pt, &localtz, "YYYY-M[M]-D[D] h[h]:mm[:ss[.u[u[u[u[u[u][ +OO[oo]", text ) ||
bfc1508d (kx 2023-03-24 03:55:33 +0300 239) /* GNU date's iso-8601: */
bfc1508d (kx 2023-03-24 03:55:33 +0300 240) template_match( &pt, &localtz, "YYYY-M[M]-D[D]Th[h]:mm[:ss[.u[u[u[u[u[u]+OO[oo]", text ) )
bfc1508d (kx 2023-03-24 03:55:33 +0300 241) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 242) pt.tm_year -= 1900;
bfc1508d (kx 2023-03-24 03:55:33 +0300 243) pt.tm_mon -= 1;
bfc1508d (kx 2023-03-24 03:55:33 +0300 244) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 245) else if( template_match( &pt, &localtz, "h[h]:mm[:ss[.u[u[u[u[u[u]", text) ) /* Just a time */
bfc1508d (kx 2023-03-24 03:55:33 +0300 246) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 247) pt.tm_year = now->tm_year;
bfc1508d (kx 2023-03-24 03:55:33 +0300 248) pt.tm_mon = now->tm_mon;
bfc1508d (kx 2023-03-24 03:55:33 +0300 249) pt.tm_mday = now->tm_mday;
bfc1508d (kx 2023-03-24 03:55:33 +0300 250) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 251)
bfc1508d (kx 2023-03-24 03:55:33 +0300 252) /* Range validation, allowing for leap seconds */
bfc1508d (kx 2023-03-24 03:55:33 +0300 253) if( pt.tm_mon < 0 ||
bfc1508d (kx 2023-03-24 03:55:33 +0300 254) pt.tm_mon > 11 ||
bfc1508d (kx 2023-03-24 03:55:33 +0300 255) pt.tm_mday > valid_days_by_month[pt.tm_mon] ||
bfc1508d (kx 2023-03-24 03:55:33 +0300 256) pt.tm_mday < 1 ||
bfc1508d (kx 2023-03-24 03:55:33 +0300 257) pt.tm_hour > 23 ||
bfc1508d (kx 2023-03-24 03:55:33 +0300 258) pt.tm_min > 59 ||
bfc1508d (kx 2023-03-24 03:55:33 +0300 259) pt.tm_sec > 60 )
bfc1508d (kx 2023-03-24 03:55:33 +0300 260) return ret;
bfc1508d (kx 2023-03-24 03:55:33 +0300 261)
bfc1508d (kx 2023-03-24 03:55:33 +0300 262) /*
bfc1508d (kx 2023-03-24 03:55:33 +0300 263) february/leap-year day checking. tm_year is bias-1900, so
bfc1508d (kx 2023-03-24 03:55:33 +0300 264) centuries that equal 100 (mod 400) are multiples of 400.
bfc1508d (kx 2023-03-24 03:55:33 +0300 265) */
bfc1508d (kx 2023-03-24 03:55:33 +0300 266) if( pt.tm_mon == 1 &&
bfc1508d (kx 2023-03-24 03:55:33 +0300 267) pt.tm_mday == 29 &&
bfc1508d (kx 2023-03-24 03:55:33 +0300 268) (pt.tm_year % 4 != 0 || (pt.tm_year % 100 == 0 && pt.tm_year % 400 != 100)) )
bfc1508d (kx 2023-03-24 03:55:33 +0300 269) return ret;
bfc1508d (kx 2023-03-24 03:55:33 +0300 270)
bfc1508d (kx 2023-03-24 03:55:33 +0300 271) if( localtz )
bfc1508d (kx 2023-03-24 03:55:33 +0300 272) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 273) struct tm *gmt = NULL;
bfc1508d (kx 2023-03-24 03:55:33 +0300 274) time_t time;
bfc1508d (kx 2023-03-24 03:55:33 +0300 275)
bfc1508d (kx 2023-03-24 03:55:33 +0300 276) time = mktime( &pt ); /* brocken-down tm asumed as localtime */
bfc1508d (kx 2023-03-24 03:55:33 +0300 277) if( time == -1 )
bfc1508d (kx 2023-03-24 03:55:33 +0300 278) return ret;
bfc1508d (kx 2023-03-24 03:55:33 +0300 279)
bfc1508d (kx 2023-03-24 03:55:33 +0300 280) time -= (time_t)localtz;
bfc1508d (kx 2023-03-24 03:55:33 +0300 281)
bfc1508d (kx 2023-03-24 03:55:33 +0300 282) gmt = localtime( &time );
bfc1508d (kx 2023-03-24 03:55:33 +0300 283) if( !gmt )
bfc1508d (kx 2023-03-24 03:55:33 +0300 284) return ret;
bfc1508d (kx 2023-03-24 03:55:33 +0300 285)
bfc1508d (kx 2023-03-24 03:55:33 +0300 286) memcpy( (void *)&pt, (const void *)gmt, sizeof(struct tm) );
bfc1508d (kx 2023-03-24 03:55:33 +0300 287) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 288)
bfc1508d (kx 2023-03-24 03:55:33 +0300 289) memcpy( (void *)tm, (const void *)&pt, sizeof(struct tm) );
bfc1508d (kx 2023-03-24 03:55:33 +0300 290)
bfc1508d (kx 2023-03-24 03:55:33 +0300 291) return mktime( &pt );
bfc1508d (kx 2023-03-24 03:55:33 +0300 292) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 293)
bfc1508d (kx 2023-03-24 03:55:33 +0300 294)
bfc1508d (kx 2023-03-24 03:55:33 +0300 295) void show_date_relative( struct strbuf *sb, time_t t )
bfc1508d (kx 2023-03-24 03:55:33 +0300 296) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 297) time_t now, diff;
bfc1508d (kx 2023-03-24 03:55:33 +0300 298)
bfc1508d (kx 2023-03-24 03:55:33 +0300 299) if( !sb || !t ) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300 300)
bfc1508d (kx 2023-03-24 03:55:33 +0300 301) now = time( NULL );
bfc1508d (kx 2023-03-24 03:55:33 +0300 302) if( now < t )
bfc1508d (kx 2023-03-24 03:55:33 +0300 303) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 304) strbuf_addstr( sb, _("in the future") );
bfc1508d (kx 2023-03-24 03:55:33 +0300 305) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300 306) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 307) diff = now - t;
bfc1508d (kx 2023-03-24 03:55:33 +0300 308) if( diff < 90 )
bfc1508d (kx 2023-03-24 03:55:33 +0300 309) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 310) strbuf_addf( sb, Q_("%"PRIdMAX" second ago", "%"PRIdMAX" seconds ago", diff), diff );
bfc1508d (kx 2023-03-24 03:55:33 +0300 311) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300 312) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 313) /* Turn it into minutes */
bfc1508d (kx 2023-03-24 03:55:33 +0300 314) diff = (diff + 30) / 60;
bfc1508d (kx 2023-03-24 03:55:33 +0300 315) if( diff < 90 )
bfc1508d (kx 2023-03-24 03:55:33 +0300 316) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 317) strbuf_addf( sb, Q_("%"PRIdMAX" minute ago", "%"PRIdMAX" minutes ago", diff), diff );
bfc1508d (kx 2023-03-24 03:55:33 +0300 318) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300 319) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 320) /* Turn it into hours */
bfc1508d (kx 2023-03-24 03:55:33 +0300 321) diff = (diff + 30) / 60;
bfc1508d (kx 2023-03-24 03:55:33 +0300 322) if( diff < 36 )
bfc1508d (kx 2023-03-24 03:55:33 +0300 323) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 324) strbuf_addf( sb, Q_("%"PRIdMAX" hour ago", "%"PRIdMAX" hours ago", diff), diff );
bfc1508d (kx 2023-03-24 03:55:33 +0300 325) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300 326) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 327) /* We deal with number of days from here on */
bfc1508d (kx 2023-03-24 03:55:33 +0300 328) diff = (diff + 12) / 24;
bfc1508d (kx 2023-03-24 03:55:33 +0300 329) if( diff < 14 )
bfc1508d (kx 2023-03-24 03:55:33 +0300 330) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 331) strbuf_addf( sb, Q_("%"PRIdMAX" day ago", "%"PRIdMAX" days ago", diff), diff );
bfc1508d (kx 2023-03-24 03:55:33 +0300 332) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300 333) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 334) /* Say weeks for the past 10 weeks or so */
bfc1508d (kx 2023-03-24 03:55:33 +0300 335) if( diff < 70 )
bfc1508d (kx 2023-03-24 03:55:33 +0300 336) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 337) strbuf_addf( sb, Q_("%"PRIdMAX" week ago", "%"PRIdMAX" weeks ago", (diff+3)/7), (diff+3)/7 );
bfc1508d (kx 2023-03-24 03:55:33 +0300 338) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300 339) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 340) /* Say months for the past 12 months or so */
bfc1508d (kx 2023-03-24 03:55:33 +0300 341) if( diff < 365 )
bfc1508d (kx 2023-03-24 03:55:33 +0300 342) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 343) strbuf_addf( sb, Q_("%"PRIdMAX" month ago", "%"PRIdMAX" months ago", (diff+15)/30), (diff+15)/30 );
bfc1508d (kx 2023-03-24 03:55:33 +0300 344) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300 345) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 346) /* Give years and months for 5 years or so */
bfc1508d (kx 2023-03-24 03:55:33 +0300 347) if( diff < 1825 )
bfc1508d (kx 2023-03-24 03:55:33 +0300 348) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 349) time_t totalmonths = (diff * 12 * 2 + 365) / (365 * 2);
bfc1508d (kx 2023-03-24 03:55:33 +0300 350) time_t years = totalmonths / 12;
bfc1508d (kx 2023-03-24 03:55:33 +0300 351) time_t months = totalmonths % 12;
bfc1508d (kx 2023-03-24 03:55:33 +0300 352) if( months )
bfc1508d (kx 2023-03-24 03:55:33 +0300 353) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 354) struct strbuf buf = STRBUF_INIT;
bfc1508d (kx 2023-03-24 03:55:33 +0300 355) strbuf_addf( &buf, Q_("%"PRIdMAX" year", "%"PRIdMAX" years", years), years );
bfc1508d (kx 2023-03-24 03:55:33 +0300 356) strbuf_addf( sb,
bfc1508d (kx 2023-03-24 03:55:33 +0300 357) /* TRANSLATORS: "%s" is "<n> months" */
bfc1508d (kx 2023-03-24 03:55:33 +0300 358) Q_("%s, %"PRIdMAX" month ago", "%s, %"PRIdMAX" months ago", months), buf.buf, months );
bfc1508d (kx 2023-03-24 03:55:33 +0300 359) strbuf_release( &buf );
bfc1508d (kx 2023-03-24 03:55:33 +0300 360) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 361) else
bfc1508d (kx 2023-03-24 03:55:33 +0300 362) strbuf_addf( sb, Q_("%"PRIdMAX" year ago", "%"PRIdMAX" years ago", years), years );
bfc1508d (kx 2023-03-24 03:55:33 +0300 363) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300 364) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 365) /* Otherwise, just years. Centuries is probably overkill. */
bfc1508d (kx 2023-03-24 03:55:33 +0300 366) strbuf_addf( sb, Q_("%"PRIdMAX" year ago", "%"PRIdMAX" years ago", (diff+183)/365), (diff+183)/365 );
bfc1508d (kx 2023-03-24 03:55:33 +0300 367) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 368)
bfc1508d (kx 2023-03-24 03:55:33 +0300 369) struct date_mode *date_mode_from_type( enum date_mode_type type )
bfc1508d (kx 2023-03-24 03:55:33 +0300 370) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 371) static struct date_mode mode;
bfc1508d (kx 2023-03-24 03:55:33 +0300 372) mode.type = type;
bfc1508d (kx 2023-03-24 03:55:33 +0300 373) mode.local = 0;
bfc1508d (kx 2023-03-24 03:55:33 +0300 374) return &mode;
bfc1508d (kx 2023-03-24 03:55:33 +0300 375) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 376)
bfc1508d (kx 2023-03-24 03:55:33 +0300 377) static const char *month_names[] = {
bfc1508d (kx 2023-03-24 03:55:33 +0300 378) "January", "February", "March", "April", "May", "June",
bfc1508d (kx 2023-03-24 03:55:33 +0300 379) "July", "August", "September", "October", "November", "December"
bfc1508d (kx 2023-03-24 03:55:33 +0300 380) };
bfc1508d (kx 2023-03-24 03:55:33 +0300 381)
bfc1508d (kx 2023-03-24 03:55:33 +0300 382) static const char *weekday_names[] = {
bfc1508d (kx 2023-03-24 03:55:33 +0300 383) "Sundays", "Mondays", "Tuesdays", "Wednesdays", "Thursdays", "Fridays", "Saturdays"
bfc1508d (kx 2023-03-24 03:55:33 +0300 384) };
bfc1508d (kx 2023-03-24 03:55:33 +0300 385)
bfc1508d (kx 2023-03-24 03:55:33 +0300 386) static time_t gm_time_t( time_t time, int tz )
bfc1508d (kx 2023-03-24 03:55:33 +0300 387) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 388) int minutes;
bfc1508d (kx 2023-03-24 03:55:33 +0300 389)
bfc1508d (kx 2023-03-24 03:55:33 +0300 390) minutes = tz < 0 ? -tz : tz;
bfc1508d (kx 2023-03-24 03:55:33 +0300 391) minutes = (minutes / 100)*60 + (minutes % 100);
bfc1508d (kx 2023-03-24 03:55:33 +0300 392) minutes = tz < 0 ? -minutes : minutes;
bfc1508d (kx 2023-03-24 03:55:33 +0300 393)
bfc1508d (kx 2023-03-24 03:55:33 +0300 394) time += minutes * 60;
bfc1508d (kx 2023-03-24 03:55:33 +0300 395)
bfc1508d (kx 2023-03-24 03:55:33 +0300 396) return time;
bfc1508d (kx 2023-03-24 03:55:33 +0300 397) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 398)
bfc1508d (kx 2023-03-24 03:55:33 +0300 399) static struct tm *time_to_tm( time_t time, int tz, struct tm *tm )
bfc1508d (kx 2023-03-24 03:55:33 +0300 400) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 401) time_t t = gm_time_t( time, tz );
bfc1508d (kx 2023-03-24 03:55:33 +0300 402) return gmtime_r( &t, tm );
bfc1508d (kx 2023-03-24 03:55:33 +0300 403) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 404)
bfc1508d (kx 2023-03-24 03:55:33 +0300 405) static struct tm *time_to_tm_local( time_t time, struct tm *tm )
bfc1508d (kx 2023-03-24 03:55:33 +0300 406) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 407) time_t t = time;
bfc1508d (kx 2023-03-24 03:55:33 +0300 408) return localtime_r( &t, tm );
bfc1508d (kx 2023-03-24 03:55:33 +0300 409) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 410)
bfc1508d (kx 2023-03-24 03:55:33 +0300 411) /**********************************************************
bfc1508d (kx 2023-03-24 03:55:33 +0300 412) Fill in the localtime 'struct tm' for the supplied time,
bfc1508d (kx 2023-03-24 03:55:33 +0300 413) and return the local tz.
bfc1508d (kx 2023-03-24 03:55:33 +0300 414) */
bfc1508d (kx 2023-03-24 03:55:33 +0300 415) static int local_time_tzoffset( time_t t, struct tm *tm )
bfc1508d (kx 2023-03-24 03:55:33 +0300 416) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 417) time_t t_local;
bfc1508d (kx 2023-03-24 03:55:33 +0300 418) int offset, eastwest;
bfc1508d (kx 2023-03-24 03:55:33 +0300 419)
bfc1508d (kx 2023-03-24 03:55:33 +0300 420) localtime_r( &t, tm );
bfc1508d (kx 2023-03-24 03:55:33 +0300 421) t_local = mktime( tm );
bfc1508d (kx 2023-03-24 03:55:33 +0300 422) if( t_local == -1 )
bfc1508d (kx 2023-03-24 03:55:33 +0300 423) return 0; /* error; just use +0000 */
bfc1508d (kx 2023-03-24 03:55:33 +0300 424) if( t_local < t )
bfc1508d (kx 2023-03-24 03:55:33 +0300 425) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 426) eastwest = -1;
bfc1508d (kx 2023-03-24 03:55:33 +0300 427) offset = t - t_local;
bfc1508d (kx 2023-03-24 03:55:33 +0300 428) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 429) else
bfc1508d (kx 2023-03-24 03:55:33 +0300 430) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 431) eastwest = 1;
bfc1508d (kx 2023-03-24 03:55:33 +0300 432) offset = t_local - t;
bfc1508d (kx 2023-03-24 03:55:33 +0300 433) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 434) offset /= 60; /* in minutes */
bfc1508d (kx 2023-03-24 03:55:33 +0300 435) offset = (offset % 60) + ((offset / 60) * 100);
bfc1508d (kx 2023-03-24 03:55:33 +0300 436) return offset * eastwest;
bfc1508d (kx 2023-03-24 03:55:33 +0300 437) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 438)
bfc1508d (kx 2023-03-24 03:55:33 +0300 439) static int local_tzoffset( time_t time )
bfc1508d (kx 2023-03-24 03:55:33 +0300 440) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 441) struct tm tm;
bfc1508d (kx 2023-03-24 03:55:33 +0300 442) return local_time_tzoffset( time, &tm );
bfc1508d (kx 2023-03-24 03:55:33 +0300 443) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 444)
bfc1508d (kx 2023-03-24 03:55:33 +0300 445)
bfc1508d (kx 2023-03-24 03:55:33 +0300 446) static void show_date_normal( struct strbuf *sb,
bfc1508d (kx 2023-03-24 03:55:33 +0300 447) time_t time, struct tm *tm, int tz,
bfc1508d (kx 2023-03-24 03:55:33 +0300 448) struct tm *human_tm, int human_tz, int local )
bfc1508d (kx 2023-03-24 03:55:33 +0300 449) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 450) struct
bfc1508d (kx 2023-03-24 03:55:33 +0300 451) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 452) unsigned int year:1,
bfc1508d (kx 2023-03-24 03:55:33 +0300 453) date:1,
bfc1508d (kx 2023-03-24 03:55:33 +0300 454) wday:1,
bfc1508d (kx 2023-03-24 03:55:33 +0300 455) time:1,
bfc1508d (kx 2023-03-24 03:55:33 +0300 456) seconds:1,
bfc1508d (kx 2023-03-24 03:55:33 +0300 457) tz:1;
bfc1508d (kx 2023-03-24 03:55:33 +0300 458) } hide = { 0 };
bfc1508d (kx 2023-03-24 03:55:33 +0300 459)
bfc1508d (kx 2023-03-24 03:55:33 +0300 460) hide.tz = local || tz == human_tz;
bfc1508d (kx 2023-03-24 03:55:33 +0300 461) hide.year = tm->tm_year == human_tm->tm_year;
bfc1508d (kx 2023-03-24 03:55:33 +0300 462) if( hide.year )
bfc1508d (kx 2023-03-24 03:55:33 +0300 463) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 464) if( tm->tm_mon == human_tm->tm_mon )
bfc1508d (kx 2023-03-24 03:55:33 +0300 465) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 466) if( tm->tm_mday > human_tm->tm_mday )
bfc1508d (kx 2023-03-24 03:55:33 +0300 467) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 468) /* Future date: think timezones */
bfc1508d (kx 2023-03-24 03:55:33 +0300 469) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 470) else if( tm->tm_mday == human_tm->tm_mday )
bfc1508d (kx 2023-03-24 03:55:33 +0300 471) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 472) hide.date = hide.wday = 1;
bfc1508d (kx 2023-03-24 03:55:33 +0300 473) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 474) else if( tm->tm_mday + 5 > human_tm->tm_mday )
bfc1508d (kx 2023-03-24 03:55:33 +0300 475) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 476) /* Leave just weekday if it was a few days ago */
bfc1508d (kx 2023-03-24 03:55:33 +0300 477) hide.date = 1;
bfc1508d (kx 2023-03-24 03:55:33 +0300 478) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 479) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 480) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 481)
bfc1508d (kx 2023-03-24 03:55:33 +0300 482) /* Show "today" times as just relative times */
bfc1508d (kx 2023-03-24 03:55:33 +0300 483) if( hide.wday )
bfc1508d (kx 2023-03-24 03:55:33 +0300 484) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 485) show_date_relative( sb, time );
bfc1508d (kx 2023-03-24 03:55:33 +0300 486) return;
bfc1508d (kx 2023-03-24 03:55:33 +0300 487) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 488)
bfc1508d (kx 2023-03-24 03:55:33 +0300 489) /******************************************************
bfc1508d (kx 2023-03-24 03:55:33 +0300 490) Always hide seconds for human-readable.
bfc1508d (kx 2023-03-24 03:55:33 +0300 491) Hide timezone if showing date.
bfc1508d (kx 2023-03-24 03:55:33 +0300 492) Hide weekday and time if showing year.
bfc1508d (kx 2023-03-24 03:55:33 +0300 493)
bfc1508d (kx 2023-03-24 03:55:33 +0300 494) The logic here is two-fold:
bfc1508d (kx 2023-03-24 03:55:33 +0300 495) (a) only show details when recent enough to matter
bfc1508d (kx 2023-03-24 03:55:33 +0300 496) (b) keep the maximum length "similar", and in check
bfc1508d (kx 2023-03-24 03:55:33 +0300 497) ******************************************************/
bfc1508d (kx 2023-03-24 03:55:33 +0300 498) if( human_tm->tm_year )
bfc1508d (kx 2023-03-24 03:55:33 +0300 499) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 500) hide.seconds = 1;
bfc1508d (kx 2023-03-24 03:55:33 +0300 501) hide.tz |= !hide.date;
bfc1508d (kx 2023-03-24 03:55:33 +0300 502) hide.wday = hide.time = !hide.year;
bfc1508d (kx 2023-03-24 03:55:33 +0300 503) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 504)
bfc1508d (kx 2023-03-24 03:55:33 +0300 505) if( !hide.wday )
bfc1508d (kx 2023-03-24 03:55:33 +0300 506) strbuf_addf( sb, "%.3s ", weekday_names[tm->tm_wday] );
bfc1508d (kx 2023-03-24 03:55:33 +0300 507) if( !hide.date )
bfc1508d (kx 2023-03-24 03:55:33 +0300 508) strbuf_addf( sb, "%.3s %d ", month_names[tm->tm_mon], tm->tm_mday );
bfc1508d (kx 2023-03-24 03:55:33 +0300 509)
bfc1508d (kx 2023-03-24 03:55:33 +0300 510) /* Do we want AM/PM depending on locale? */
bfc1508d (kx 2023-03-24 03:55:33 +0300 511) if( !hide.time )
bfc1508d (kx 2023-03-24 03:55:33 +0300 512) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 513) strbuf_addf( sb, "%02d:%02d", tm->tm_hour, tm->tm_min );
bfc1508d (kx 2023-03-24 03:55:33 +0300 514) if( !hide.seconds )
bfc1508d (kx 2023-03-24 03:55:33 +0300 515) strbuf_addf( sb, ":%02d", tm->tm_sec );
bfc1508d (kx 2023-03-24 03:55:33 +0300 516) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 517) else
bfc1508d (kx 2023-03-24 03:55:33 +0300 518) strbuf_rtrim( sb );
bfc1508d (kx 2023-03-24 03:55:33 +0300 519)
bfc1508d (kx 2023-03-24 03:55:33 +0300 520) if( !hide.year )
bfc1508d (kx 2023-03-24 03:55:33 +0300 521) strbuf_addf( sb, " %d", tm->tm_year + 1900 );
bfc1508d (kx 2023-03-24 03:55:33 +0300 522)
bfc1508d (kx 2023-03-24 03:55:33 +0300 523) if( !hide.tz )
bfc1508d (kx 2023-03-24 03:55:33 +0300 524) strbuf_addf( sb, " %+05d", tz );
bfc1508d (kx 2023-03-24 03:55:33 +0300 525) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 526)
bfc1508d (kx 2023-03-24 03:55:33 +0300 527) void show_date( struct strbuf *sb, time_t t, int tz, const struct date_mode *mode )
bfc1508d (kx 2023-03-24 03:55:33 +0300 528) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 529) struct tm *tm;
bfc1508d (kx 2023-03-24 03:55:33 +0300 530) struct tm tmbuf = { 0 };
bfc1508d (kx 2023-03-24 03:55:33 +0300 531) struct tm human_tm = { 0 };
bfc1508d (kx 2023-03-24 03:55:33 +0300 532) int human_tz = -1;
bfc1508d (kx 2023-03-24 03:55:33 +0300 533)
bfc1508d (kx 2023-03-24 03:55:33 +0300 534) if( mode->type == DATE_UNIX )
bfc1508d (kx 2023-03-24 03:55:33 +0300 535) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 536) strbuf_addf( sb, "%"PRIdMAX, t );
bfc1508d (kx 2023-03-24 03:55:33 +0300 537) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 538)
bfc1508d (kx 2023-03-24 03:55:33 +0300 539) if( mode->type == DATE_HUMAN )
bfc1508d (kx 2023-03-24 03:55:33 +0300 540) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 541) time_t now = time( NULL );
bfc1508d (kx 2023-03-24 03:55:33 +0300 542)
bfc1508d (kx 2023-03-24 03:55:33 +0300 543) /* Fill in the data for "current time" in human_tz and human_tm */
bfc1508d (kx 2023-03-24 03:55:33 +0300 544) human_tz = local_time_tzoffset( now, &human_tm );
bfc1508d (kx 2023-03-24 03:55:33 +0300 545) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 546)
bfc1508d (kx 2023-03-24 03:55:33 +0300 547) if( mode->local )
bfc1508d (kx 2023-03-24 03:55:33 +0300 548) tz = local_tzoffset( t );
bfc1508d (kx 2023-03-24 03:55:33 +0300 549)
bfc1508d (kx 2023-03-24 03:55:33 +0300 550) if( mode->type == DATE_RAW )
bfc1508d (kx 2023-03-24 03:55:33 +0300 551) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 552) strbuf_addf( sb, "%"PRIdMAX" %+05d", t, tz );
bfc1508d (kx 2023-03-24 03:55:33 +0300 553) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 554)
bfc1508d (kx 2023-03-24 03:55:33 +0300 555) if( mode->type == DATE_RELATIVE )
bfc1508d (kx 2023-03-24 03:55:33 +0300 556) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 557) show_date_relative( sb, t );
bfc1508d (kx 2023-03-24 03:55:33 +0300 558) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 559)
bfc1508d (kx 2023-03-24 03:55:33 +0300 560) if( mode->local )
bfc1508d (kx 2023-03-24 03:55:33 +0300 561) tm = time_to_tm_local( t, &tmbuf );
bfc1508d (kx 2023-03-24 03:55:33 +0300 562) else
bfc1508d (kx 2023-03-24 03:55:33 +0300 563) tm = time_to_tm( t, tz, &tmbuf );
bfc1508d (kx 2023-03-24 03:55:33 +0300 564) if (!tm) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 565) tm = time_to_tm( 0, 0, &tmbuf );
bfc1508d (kx 2023-03-24 03:55:33 +0300 566) tz = 0;
bfc1508d (kx 2023-03-24 03:55:33 +0300 567) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 568)
bfc1508d (kx 2023-03-24 03:55:33 +0300 569) if( mode->type == DATE_SHORT )
bfc1508d (kx 2023-03-24 03:55:33 +0300 570) strbuf_addf( sb, "%04d-%02d-%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday );
bfc1508d (kx 2023-03-24 03:55:33 +0300 571) else if( mode->type == DATE_ISO8601 )
bfc1508d (kx 2023-03-24 03:55:33 +0300 572) strbuf_addf( sb, "%04d-%02d-%02d %02d:%02d:%02d %+05d",
bfc1508d (kx 2023-03-24 03:55:33 +0300 573) tm->tm_year + 1900,
bfc1508d (kx 2023-03-24 03:55:33 +0300 574) tm->tm_mon + 1,
bfc1508d (kx 2023-03-24 03:55:33 +0300 575) tm->tm_mday,
bfc1508d (kx 2023-03-24 03:55:33 +0300 576) tm->tm_hour, tm->tm_min, tm->tm_sec,
bfc1508d (kx 2023-03-24 03:55:33 +0300 577) tz );
bfc1508d (kx 2023-03-24 03:55:33 +0300 578) else if( mode->type == DATE_ISO8601_STRICT )
bfc1508d (kx 2023-03-24 03:55:33 +0300 579) {
bfc1508d (kx 2023-03-24 03:55:33 +0300 580) char sign = (tz >= 0) ? '+' : '-';
bfc1508d (kx 2023-03-24 03:55:33 +0300 581) tz = abs( tz );
bfc1508d (kx 2023-03-24 03:55:33 +0300 582) strbuf_addf( sb, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
bfc1508d (kx 2023-03-24 03:55:33 +0300 583) tm->tm_year + 1900,
bfc1508d (kx 2023-03-24 03:55:33 +0300 584) tm->tm_mon + 1,
bfc1508d (kx 2023-03-24 03:55:33 +0300 585) tm->tm_mday,
bfc1508d (kx 2023-03-24 03:55:33 +0300 586) tm->tm_hour, tm->tm_min, tm->tm_sec,
bfc1508d (kx 2023-03-24 03:55:33 +0300 587) sign, tz / 100, tz % 100 );
bfc1508d (kx 2023-03-24 03:55:33 +0300 588) }
bfc1508d (kx 2023-03-24 03:55:33 +0300 589) else if( mode->type == DATE_RFC2822 )
bfc1508d (kx 2023-03-24 03:55:33 +0300 590) strbuf_addf( sb, "%.3s, %d %.3s %d %02d:%02d:%02d %+05d",
bfc1508d (kx 2023-03-24 03:55:33 +0300 591) weekday_names[tm->tm_wday], tm->tm_mday,
bfc1508d (kx 2023-03-24 03:55:33 +0300 592) month_names[tm->tm_mon], tm->tm_year + 1900,
bfc1508d (kx 2023-03-24 03:55:33 +0300 593) tm->tm_hour, tm->tm_min, tm->tm_sec, tz );
bfc1508d (kx 2023-03-24 03:55:33 +0300 594) else
bfc1508d (kx 2023-03-24 03:55:33 +0300 595) show_date_normal( sb, t, tm, tz, &human_tm, human_tz, mode->local );
bfc1508d (kx 2023-03-24 03:55:33 +0300 596) }