NeoMutt  2023-03-22-27-g3cb248
Teaching an old dog new tricks
DOXYGEN
date.c
Go to the documentation of this file.
1
29#include "config.h"
30#include <stdbool.h>
31#include <stdint.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <sys/time.h>
35#include <time.h>
36#include "date.h"
37#include "buffer.h"
38#include "logging.h"
39#include "memory.h"
40#include "prex.h"
41#include "regex3.h"
42#include "string2.h"
43
47static const char *const Weekdays[] = {
48 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
49};
50
54static const char *const Months[] = {
55 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
56 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
57};
58
64static const struct Tz TimeZones[] = {
65 // clang-format off
66 { "aat", 1, 0, true }, /* Atlantic Africa Time */
67 { "adt", 4, 0, false }, /* Arabia DST */
68 { "ast", 3, 0, false }, /* Arabia */
69//{ "ast", 4, 0, true }, /* Atlantic */
70 { "bst", 1, 0, false }, /* British DST */
71 { "cat", 1, 0, false }, /* Central Africa */
72 { "cdt", 5, 0, true },
73 { "cest", 2, 0, false }, /* Central Europe DST */
74 { "cet", 1, 0, false }, /* Central Europe */
75 { "cst", 6, 0, true },
76//{ "cst", 8, 0, false }, /* China */
77//{ "cst", 9, 30, false }, /* Australian Central Standard Time */
78 { "eat", 3, 0, false }, /* East Africa */
79 { "edt", 4, 0, true },
80 { "eest", 3, 0, false }, /* Eastern Europe DST */
81 { "eet", 2, 0, false }, /* Eastern Europe */
82 { "egst", 0, 0, false }, /* Eastern Greenland DST */
83 { "egt", 1, 0, true }, /* Eastern Greenland */
84 { "est", 5, 0, true },
85 { "gmt", 0, 0, false },
86 { "gst", 4, 0, false }, /* Presian Gulf */
87 { "hkt", 8, 0, false }, /* Hong Kong */
88 { "ict", 7, 0, false }, /* Indochina */
89 { "idt", 3, 0, false }, /* Israel DST */
90 { "ist", 2, 0, false }, /* Israel */
91//{ "ist", 5, 30, false }, /* India */
92 { "jst", 9, 0, false }, /* Japan */
93 { "kst", 9, 0, false }, /* Korea */
94 { "mdt", 6, 0, true },
95 { "met", 1, 0, false }, /* This is now officially CET */
96 { "met dst", 2, 0, false }, /* MET in Daylight Saving Time */
97 { "msd", 4, 0, false }, /* Moscow DST */
98 { "msk", 3, 0, false }, /* Moscow */
99 { "mst", 7, 0, true },
100 { "nzdt", 13, 0, false }, /* New Zealand DST */
101 { "nzst", 12, 0, false }, /* New Zealand */
102 { "pdt", 7, 0, true },
103 { "pst", 8, 0, true },
104 { "sat", 2, 0, false }, /* South Africa */
105 { "smt", 4, 0, false }, /* Seychelles */
106 { "sst", 11, 0, true }, /* Samoa */
107//{ "sst", 8, 0, false }, /* Singapore */
108 { "utc", 0, 0, false },
109 { "wat", 0, 0, false }, /* West Africa */
110 { "west", 1, 0, false }, /* Western Europe DST */
111 { "wet", 0, 0, false }, /* Western Europe */
112 { "wgst", 2, 0, true }, /* Western Greenland DST */
113 { "wgt", 3, 0, true }, /* Western Greenland */
114 { "wst", 8, 0, false }, /* Western Australia */
115 // clang-format on
116};
117
127static int compute_tz(time_t g, struct tm *utc)
128{
129 struct tm lt = mutt_date_localtime(g);
130
131 int tz = (((lt.tm_hour - utc->tm_hour) * 60) + (lt.tm_min - utc->tm_min)) * 60;
132
133 int yday = (lt.tm_yday - utc->tm_yday);
134 if (yday != 0)
135 {
136 /* This code is optimized to negative timezones (West of Greenwich) */
137 if ((yday == -1) || /* UTC passed midnight before localtime */
138 (yday > 1)) /* UTC passed new year before localtime */
139 {
140 tz -= (24 * 60 * 60);
141 }
142 else
143 {
144 tz += (24 * 60 * 60);
145 }
146 }
147
148 return tz;
149}
150
159static time_t add_tz_offset(time_t t, bool w, time_t h, time_t m)
160{
161 if ((t != TIME_T_MAX) && (t != TIME_T_MIN))
162 return t + (w ? 1 : -1) * (((time_t) h * 3600) + ((time_t) m * 60));
163 else
164 return t;
165}
166
174static const struct Tz *find_tz(const char *s, size_t len)
175{
176 for (size_t i = 0; i < mutt_array_size(TimeZones); i++)
177 {
178 if (mutt_istrn_equal(TimeZones[i].tzname, s, len))
179 return &TimeZones[i];
180 }
181 return NULL;
182}
183
189static int is_leap_year_feb(struct tm *tm)
190{
191 if (tm->tm_mon != 1)
192 return 0;
193
194 int y = tm->tm_year + 1900;
195 return ((y & 3) == 0) && (((y % 100) != 0) || ((y % 400) == 0));
196}
197
207{
208 /* Check we haven't overflowed the time (on 32-bit arches) */
209 if ((t == TIME_T_MAX) || (t == TIME_T_MIN))
210 return 0;
211
212 if (t == 0)
213 t = mutt_date_now();
214
215 struct tm tm = mutt_date_gmtime(t);
216 return compute_tz(t, &tm);
217}
218
229time_t mutt_date_make_time(struct tm *t, bool local)
230{
231 if (!t)
232 return TIME_T_MIN;
233
234 static const int AccumDaysPerMonth[mutt_array_size(Months)] = {
235 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
236 };
237
238 /* Prevent an integer overflow, with some arbitrary limits. */
239 if (t->tm_year > 10000)
240 return TIME_T_MAX;
241 if (t->tm_year < -10000)
242 return TIME_T_MIN;
243
244 if ((t->tm_mday < 1) || (t->tm_mday > 31))
245 return TIME_T_MIN;
246 if ((t->tm_hour < 0) || (t->tm_hour > 23) || (t->tm_min < 0) ||
247 (t->tm_min > 59) || (t->tm_sec < 0) || (t->tm_sec > 60))
248 {
249 return TIME_T_MIN;
250 }
251 if (t->tm_year > 9999)
252 return TIME_T_MAX;
253
254 /* Compute the number of days since January 1 in the same year */
255 int yday = AccumDaysPerMonth[t->tm_mon % mutt_array_size(Months)];
256
257 /* The leap years are 1972 and every 4. year until 2096,
258 * but this algorithm will fail after year 2099 */
259 yday += t->tm_mday;
260 if ((t->tm_year % 4) || (t->tm_mon < 2))
261 yday--;
262 t->tm_yday = yday;
263
264 time_t g = yday;
265
266 /* Compute the number of days since January 1, 1970 */
267 g += (t->tm_year - 70) * (time_t) 365;
268 g += (t->tm_year - 69) / 4;
269
270 /* Compute the number of hours */
271 g *= 24;
272 g += t->tm_hour;
273
274 /* Compute the number of minutes */
275 g *= 60;
276 g += t->tm_min;
277
278 /* Compute the number of seconds */
279 g *= 60;
280 g += t->tm_sec;
281
282 if (local)
283 g -= compute_tz(g, t);
284
285 return g;
286}
287
297void mutt_date_normalize_time(struct tm *tm)
298{
299 if (!tm)
300 return;
301
302 static const char DaysPerMonth[mutt_array_size(Months)] = {
303 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
304 };
305 int leap;
306
307 while (tm->tm_sec < 0)
308 {
309 tm->tm_sec += 60;
310 tm->tm_min--;
311 }
312 while (tm->tm_sec >= 60)
313 {
314 tm->tm_sec -= 60;
315 tm->tm_min++;
316 }
317 while (tm->tm_min < 0)
318 {
319 tm->tm_min += 60;
320 tm->tm_hour--;
321 }
322 while (tm->tm_min >= 60)
323 {
324 tm->tm_min -= 60;
325 tm->tm_hour++;
326 }
327 while (tm->tm_hour < 0)
328 {
329 tm->tm_hour += 24;
330 tm->tm_mday--;
331 }
332 while (tm->tm_hour >= 24)
333 {
334 tm->tm_hour -= 24;
335 tm->tm_mday++;
336 }
337 /* use loops on NNNdwmy user input values? */
338 while (tm->tm_mon < 0)
339 {
340 tm->tm_mon += 12;
341 tm->tm_year--;
342 }
343 while (tm->tm_mon >= 12)
344 {
345 tm->tm_mon -= 12;
346 tm->tm_year++;
347 }
348 while (tm->tm_mday <= 0)
349 {
350 if (tm->tm_mon)
351 {
352 tm->tm_mon--;
353 }
354 else
355 {
356 tm->tm_mon = 11;
357 tm->tm_year--;
358 }
359 tm->tm_mday += DaysPerMonth[tm->tm_mon] + is_leap_year_feb(tm);
360 }
361 while (tm->tm_mday > (DaysPerMonth[tm->tm_mon] + (leap = is_leap_year_feb(tm))))
362 {
363 tm->tm_mday -= DaysPerMonth[tm->tm_mon] + leap;
364 if (tm->tm_mon < 11)
365 {
366 tm->tm_mon++;
367 }
368 else
369 {
370 tm->tm_mon = 0;
371 tm->tm_year++;
372 }
373 }
374}
375
384void mutt_date_make_date(struct Buffer *buf, bool local)
385{
386 if (!buf)
387 return;
388
389 struct tm tm;
390 int tz = 0;
391
392 time_t t = mutt_date_now();
393 if (local)
394 {
395 tm = mutt_date_localtime(t);
396 tz = mutt_date_local_tz(t);
397 }
398 else
399 {
400 tm = mutt_date_gmtime(t);
401 }
402
403 tz /= 60;
404
405 mutt_buffer_add_printf(buf, "%s, %d %s %d %02d:%02d:%02d %+03d%02d", Weekdays[tm.tm_wday],
406 tm.tm_mday, Months[tm.tm_mon], tm.tm_year + 1900,
407 tm.tm_hour, tm.tm_min, tm.tm_sec, tz / 60, abs(tz) % 60);
408}
409
419int mutt_date_check_month(const char *s)
420{
421 for (int i = 0; i < mutt_array_size(Months); i++)
422 if (mutt_istr_startswith(s, Months[i]))
423 return i;
424
425 return -1; /* error */
426}
427
432time_t mutt_date_now(void)
433{
434 return mutt_date_now_ms() / 1000;
435}
436
441uint64_t mutt_date_now_ms(void)
442{
443 struct timeval tv = { 0, 0 };
444 gettimeofday(&tv, NULL);
445 /* We assume that gettimeofday doesn't modify its first argument on failure.
446 * We also kind of assume that gettimeofday does not fail. */
447 return (uint64_t) tv.tv_sec * 1000 + tv.tv_usec / 1000;
448}
449
461time_t mutt_date_parse_date(const char *s, struct Tz *tz_out)
462{
463 if (!s)
464 return -1;
465
466 bool lax = false;
467
468 const regmatch_t *match = mutt_prex_capture(PREX_RFC5322_DATE, s);
469 if (!match)
470 {
472 if (!match)
473 {
474 mutt_debug(LL_DEBUG1, "Could not parse date: <%s>\n", s);
475 return -1;
476 }
477 lax = true;
478 mutt_debug(LL_DEBUG2, "Fallback regex for date: <%s>\n", s);
479 }
480
481 struct tm tm = { 0 };
482
483 // clang-format off
484 const regmatch_t *mday = &match[lax ? PREX_RFC5322_DATE_LAX_MATCH_DAY : PREX_RFC5322_DATE_MATCH_DAY];
485 const regmatch_t *mmonth = &match[lax ? PREX_RFC5322_DATE_LAX_MATCH_MONTH : PREX_RFC5322_DATE_MATCH_MONTH];
486 const regmatch_t *myear = &match[lax ? PREX_RFC5322_DATE_LAX_MATCH_YEAR : PREX_RFC5322_DATE_MATCH_YEAR];
487 const regmatch_t *mhour = &match[lax ? PREX_RFC5322_DATE_LAX_MATCH_HOUR : PREX_RFC5322_DATE_MATCH_HOUR];
488 const regmatch_t *mminute = &match[lax ? PREX_RFC5322_DATE_LAX_MATCH_MINUTE : PREX_RFC5322_DATE_MATCH_MINUTE];
489 const regmatch_t *msecond = &match[lax ? PREX_RFC5322_DATE_LAX_MATCH_SECOND : PREX_RFC5322_DATE_MATCH_SECOND];
490 const regmatch_t *mtz = &match[lax ? PREX_RFC5322_DATE_LAX_MATCH_TZ : PREX_RFC5322_DATE_MATCH_TZ];
491 const regmatch_t *mtzobs = &match[lax ? PREX_RFC5322_DATE_LAX_MATCH_TZ_OBS : PREX_RFC5322_DATE_MATCH_TZ_OBS];
492 // clang-format on
493
494 /* Day */
495 sscanf(s + mutt_regmatch_start(mday), "%d", &tm.tm_mday);
496 if (tm.tm_mday > 31)
497 return -1;
498
499 /* Month */
500 tm.tm_mon = mutt_date_check_month(s + mutt_regmatch_start(mmonth));
501
502 /* Year */
503 sscanf(s + mutt_regmatch_start(myear), "%d", &tm.tm_year);
504 if (tm.tm_year < 50)
505 tm.tm_year += 100;
506 else if (tm.tm_year >= 1900)
507 tm.tm_year -= 1900;
508
509 /* Time */
510 int hour, min, sec = 0;
511 sscanf(s + mutt_regmatch_start(mhour), "%d", &hour);
512 sscanf(s + mutt_regmatch_start(mminute), "%d", &min);
513 if (mutt_regmatch_start(msecond) != -1)
514 sscanf(s + mutt_regmatch_start(msecond), "%d", &sec);
515 if ((hour > 23) || (min > 59) || (sec > 60))
516 return -1;
517 tm.tm_hour = hour;
518 tm.tm_min = min;
519 tm.tm_sec = sec;
520
521 /* Time zone */
522 int zhours = 0;
523 int zminutes = 0;
524 bool zoccident = false;
525 if (mutt_regmatch_start(mtz) != -1)
526 {
527 char direction;
528 sscanf(s + mutt_regmatch_start(mtz), "%c%02d%02d", &direction, &zhours, &zminutes);
529 zoccident = (direction == '-');
530 }
531 else if (mutt_regmatch_start(mtzobs) != -1)
532 {
533 const struct Tz *tz = find_tz(s + mutt_regmatch_start(mtzobs),
534 mutt_regmatch_len(mtzobs));
535 if (tz)
536 {
537 zhours = tz->zhours;
538 zminutes = tz->zminutes;
539 zoccident = tz->zoccident;
540 }
541 }
542
543 if (tz_out)
544 {
545 tz_out->zhours = zhours;
546 tz_out->zminutes = zminutes;
547 tz_out->zoccident = zoccident;
548 }
549
551}
552
562int mutt_date_make_imap(char *buf, size_t buflen, time_t timestamp)
563{
564 if (!buf)
565 return -1;
566
567 struct tm tm = mutt_date_localtime(timestamp);
569
570 tz /= 60;
571
572 return snprintf(buf, buflen, "%02d-%s-%d %02d:%02d:%02d %+03d%02d",
573 tm.tm_mday, Months[tm.tm_mon], tm.tm_year + 1900, tm.tm_hour,
574 tm.tm_min, tm.tm_sec, tz / 60, abs(tz) % 60);
575}
576
588int mutt_date_make_tls(char *buf, size_t buflen, time_t timestamp)
589{
590 if (!buf)
591 return -1;
592
593 struct tm tm = mutt_date_gmtime(timestamp);
594 return snprintf(buf, buflen, "%s, %d %s %d %02d:%02d:%02d UTC",
595 Weekdays[tm.tm_wday], tm.tm_mday, Months[tm.tm_mon],
596 tm.tm_year + 1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
597}
598
605time_t mutt_date_parse_imap(const char *s)
606{
607 const regmatch_t *match = mutt_prex_capture(PREX_IMAP_DATE, s);
608 if (!match)
609 return 0;
610
611 const regmatch_t *mday = &match[PREX_IMAP_DATE_MATCH_DAY];
612 const regmatch_t *mmonth = &match[PREX_IMAP_DATE_MATCH_MONTH];
613 const regmatch_t *myear = &match[PREX_IMAP_DATE_MATCH_YEAR];
614 const regmatch_t *mtime = &match[PREX_IMAP_DATE_MATCH_TIME];
615 const regmatch_t *mtz = &match[PREX_IMAP_DATE_MATCH_TZ];
616
617 struct tm tm;
618
619 sscanf(s + mutt_regmatch_start(mday), " %d", &tm.tm_mday);
620 tm.tm_mon = mutt_date_check_month(s + mutt_regmatch_start(mmonth));
621 sscanf(s + mutt_regmatch_start(myear), "%d", &tm.tm_year);
622 tm.tm_year -= 1900;
623 sscanf(s + mutt_regmatch_start(mtime), "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
624
625 char direction;
626 int zhours, zminutes;
627 sscanf(s + mutt_regmatch_start(mtz), "%c%02d%02d", &direction, &zhours, &zminutes);
628 bool zoccident = (direction == '-');
629
630 return add_tz_offset(mutt_date_make_time(&tm, false), zoccident, zhours, zminutes);
631}
632
641time_t mutt_date_add_timeout(time_t now, time_t timeout)
642{
643 if (timeout < 0)
644 return now;
645
646 if ((TIME_T_MAX - now) < timeout)
647 return TIME_T_MAX;
648
649 return now + timeout;
650}
651
657struct tm mutt_date_localtime(time_t t)
658{
659 struct tm tm = { 0 };
660
661 struct tm *ret = localtime_r(&t, &tm);
662 if (!ret)
663 {
664 mutt_debug(LL_DEBUG1, "Could not convert time_t via localtime_r() to struct tm: time_t = %jd\n",
665 (intmax_t) t);
666 struct tm default_tm = { 0 }; // 1970-01-01 00:00:00
667 mktime(&default_tm); // update derived fields making tm into a valid tm.
668 tm = default_tm;
669 }
670 return tm;
671}
672
678struct tm mutt_date_gmtime(time_t t)
679{
680 struct tm tm = { 0 };
681
682 struct tm *ret = gmtime_r(&t, &tm);
683 if (!ret)
684 {
685 mutt_debug(LL_DEBUG1, "Could not convert time_t via gmtime_r() to struct tm: time_t = %jd\n",
686 (intmax_t) t);
687 struct tm default_tm = { 0 }; // 1970-01-01 00:00:00
688 mktime(&default_tm); // update derived fields making tm into a valid tm.
689 tm = default_tm;
690 }
691 return tm;
692}
693
702size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
703{
704 if (!buf || !format)
705 return 0;
706
707 struct tm tm = mutt_date_localtime(t);
708 return strftime(buf, buflen, format, &tm);
709}
710
715void mutt_date_sleep_ms(size_t ms)
716{
717 const struct timespec sleep = {
718 .tv_sec = ms / 1000,
719 .tv_nsec = (ms % 1000) * 1000000UL,
720 };
721 nanosleep(&sleep, NULL);
722}
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:211
General purpose object for storing and parsing strings.
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition: date.c:657
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition: date.c:702
uint64_t mutt_date_now_ms(void)
Return the number of milliseconds since the Unix epoch.
Definition: date.c:441
static int compute_tz(time_t g, struct tm *utc)
Calculate the number of seconds east of UTC.
Definition: date.c:127
void mutt_date_make_date(struct Buffer *buf, bool local)
Write a date in RFC822 format to a buffer.
Definition: date.c:384
time_t mutt_date_make_time(struct tm *t, bool local)
Convert struct tm to time_t
Definition: date.c:229
static const char *const Months[]
Months of the year (abbreviated)
Definition: date.c:54
void mutt_date_sleep_ms(size_t ms)
Sleep for milliseconds.
Definition: date.c:715
int mutt_date_check_month(const char *s)
Is the string a valid month name.
Definition: date.c:419
static const struct Tz * find_tz(const char *s, size_t len)
Look up a timezone.
Definition: date.c:174
struct tm mutt_date_gmtime(time_t t)
Converts calendar time to a broken-down time structure expressed in UTC timezone.
Definition: date.c:678
int mutt_date_make_tls(char *buf, size_t buflen, time_t timestamp)
Format date in TLS certificate verification style.
Definition: date.c:588
static int is_leap_year_feb(struct tm *tm)
Is a given February in a leap year.
Definition: date.c:189
static const char *const Weekdays[]
Day of the week (abbreviated)
Definition: date.c:47
int mutt_date_make_imap(char *buf, size_t buflen, time_t timestamp)
Format date in IMAP style: DD-MMM-YYYY HH:MM:SS +ZZzz.
Definition: date.c:562
int mutt_date_local_tz(time_t t)
Calculate the local timezone in seconds east of UTC.
Definition: date.c:206
time_t mutt_date_add_timeout(time_t now, time_t timeout)
Safely add a timeout to a given time_t value.
Definition: date.c:641
static const struct Tz TimeZones[]
Lookup table of Time Zones.
Definition: date.c:64
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:432
time_t mutt_date_parse_date(const char *s, struct Tz *tz_out)
Parse a date string in RFC822 format.
Definition: date.c:461
time_t mutt_date_parse_imap(const char *s)
Parse date of the form: DD-MMM-YYYY HH:MM:SS +ZZzz.
Definition: date.c:605
void mutt_date_normalize_time(struct tm *tm)
Fix the contents of a struct tm.
Definition: date.c:297
static time_t add_tz_offset(time_t t, bool w, time_t h, time_t m)
Compute and add a timezone offset to an UTC time.
Definition: date.c:159
Time and date handling routines.
#define TIME_T_MAX
Definition: date.h:33
#define TIME_T_MIN
Definition: date.h:34
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
static const char * timestamp(time_t stamp)
Create a YYYY-MM-DD HH:MM:SS timestamp.
Definition: logging.c:77
Logging Dispatcher.
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
Memory management wrappers.
#define mutt_array_size(x)
Definition: memory.h:36
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:239
bool mutt_istrn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition: string.c:524
regmatch_t * mutt_prex_capture(enum Prex which, const char *str)
Match a precompiled regex against a string.
Definition: prex.c:308
Manage precompiled / predefined regular expressions.
@ PREX_IMAP_DATE_MATCH_TIME
15-MAR-2020 [15:09:35] -0700
Definition: prex.h:190
@ PREX_IMAP_DATE_MATCH_YEAR
15-MAR-[2020] 15:09:35 -0700
Definition: prex.h:189
@ PREX_IMAP_DATE_MATCH_DAY
[ 4]-MAR-2020 15:09:35 -0700
Definition: prex.h:185
@ PREX_IMAP_DATE_MATCH_TZ
15-MAR-2020 15:09:35 [-0700]
Definition: prex.h:191
@ PREX_IMAP_DATE_MATCH_MONTH
15-[MAR]-2020 15:09:35 -0700
Definition: prex.h:188
@ PREX_RFC5322_DATE_MATCH_TZ_OBS
Tue, 3 Mar 2020 14:32:55[UT]
Definition: prex.h:135
@ PREX_RFC5322_DATE_MATCH_TZ
Tue, 3 Mar 2020 14:32:55 [+0200]
Definition: prex.h:134
@ PREX_RFC5322_DATE_MATCH_SECOND
Tue, 3 Mar 2020 14:32:[55] +0200
Definition: prex.h:132
@ PREX_RFC5322_DATE_MATCH_YEAR
Tue, 3 Mar [2020] 14:32:55 +0200
Definition: prex.h:128
@ PREX_RFC5322_DATE_MATCH_HOUR
Tue, 3 Mar 2020 [14]:32:55 +0200
Definition: prex.h:129
@ PREX_RFC5322_DATE_MATCH_DAY
Tue, [3] Mar 2020 14:32:55 +0200
Definition: prex.h:126
@ PREX_RFC5322_DATE_MATCH_MINUTE
Tue, 3 Mar 2020 14:[32]:55 +0200
Definition: prex.h:130
@ PREX_RFC5322_DATE_MATCH_MONTH
Tue, 3 [Jan] 2020 14:32:55 +0200
Definition: prex.h:127
@ PREX_IMAP_DATE
[16-MAR-2020 15:09:35 -0700]
Definition: prex.h:39
@ PREX_RFC5322_DATE
[Mon, 16 Mar 2020 15:09:35 -0700]
Definition: prex.h:37
@ PREX_RFC5322_DATE_LAX
[Mon, (Comment) 16 Mar 2020 15:09:35 -0700]
Definition: prex.h:38
@ PREX_RFC5322_DATE_LAX_MATCH_SECOND
Tue, 3 Mar 2020 14:32:[55] +0200
Definition: prex.h:169
@ PREX_RFC5322_DATE_LAX_MATCH_TZ
Tue, 3 Mar 2020 14:32:55 [+0200]
Definition: prex.h:172
@ PREX_RFC5322_DATE_LAX_MATCH_YEAR
Tue, 3 Mar [2020] 14:32:55 +0200
Definition: prex.h:161
@ PREX_RFC5322_DATE_LAX_MATCH_HOUR
Tue, 3 Mar 2020 [14]:32:55 +0200
Definition: prex.h:163
@ PREX_RFC5322_DATE_LAX_MATCH_MINUTE
Tue, 3 Mar 2020 14:[32]:55 +0200
Definition: prex.h:165
@ PREX_RFC5322_DATE_LAX_MATCH_TZ_OBS
Tue, 3 Mar 2020 14:32:55[UT]
Definition: prex.h:173
@ PREX_RFC5322_DATE_LAX_MATCH_MONTH
Tue, 3 [Jan] 2020 14:32:55 +0200
Definition: prex.h:159
@ PREX_RFC5322_DATE_LAX_MATCH_DAY
Tue, [3] Mar 2020 14:32:55 +0200
Definition: prex.h:157
Manage regular expressions.
static size_t mutt_regmatch_len(const regmatch_t *match)
Return the length of a match.
Definition: regex3.h:80
static regoff_t mutt_regmatch_start(const regmatch_t *match)
Return the start of a match.
Definition: regex3.h:60
String manipulation functions.
String manipulation buffer.
Definition: buffer.h:34
List of recognised Timezones.
Definition: date.h:43
unsigned char zminutes
Minutes away from UTC.
Definition: date.h:46
bool zoccident
True if west of UTC, False if East.
Definition: date.h:47
char tzname[8]
Name, e.g. UTC.
Definition: date.h:44
unsigned char zhours
Hours away from UTC.
Definition: date.h:45
Time value with nanosecond precision.
Definition: file.h:50
time_t tv_sec
Number of seconds since the epoch.
Definition: file.h:51