NeoMutt  2020-09-25
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 
44 // clang-format off
48 static const char *const Weekdays[] = {
49  "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
50 };
51 
55 static const char *const Months[] = {
56  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
57  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
58 };
59 
65 static const struct Tz TimeZones[] = {
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 };
116 // clang-format on
117 
127 static time_t compute_tz(time_t g, struct tm *utc)
128 {
129  struct tm lt = mutt_date_localtime(g);
130 
131  time_t t = (((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  t -= (24 * 60 * 60);
141  }
142  else
143  {
144  t += (24 * 60 * 60);
145  }
146  }
147 
148  return t;
149 }
150 
159 static 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 
174 static 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 
189 static 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 
206 time_t mutt_date_local_tz(time_t t)
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_epoch();
214 
215  struct tm tm = mutt_date_gmtime(t);
216  return compute_tz(t, &tm);
217 }
218 
229 time_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  time_t g = 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  g += t->tm_mday;
260  if ((t->tm_year % 4) || (t->tm_mon < 2))
261  g--;
262  t->tm_yday = g;
263 
264  /* Compute the number of days since January 1, 1970 */
265  g += (t->tm_year - 70) * (time_t) 365;
266  g += (t->tm_year - 69) / 4;
267 
268  /* Compute the number of hours */
269  g *= 24;
270  g += t->tm_hour;
271 
272  /* Compute the number of minutes */
273  g *= 60;
274  g += t->tm_min;
275 
276  /* Compute the number of seconds */
277  g *= 60;
278  g += t->tm_sec;
279 
280  if (local)
281  g -= compute_tz(g, t);
282 
283  return g;
284 }
285 
295 void mutt_date_normalize_time(struct tm *tm)
296 {
297  if (!tm)
298  return;
299 
300  static const char DaysPerMonth[mutt_array_size(Months)] = {
301  31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
302  };
303  int leap;
304 
305  while (tm->tm_sec < 0)
306  {
307  tm->tm_sec += 60;
308  tm->tm_min--;
309  }
310  while (tm->tm_sec >= 60)
311  {
312  tm->tm_sec -= 60;
313  tm->tm_min++;
314  }
315  while (tm->tm_min < 0)
316  {
317  tm->tm_min += 60;
318  tm->tm_hour--;
319  }
320  while (tm->tm_min >= 60)
321  {
322  tm->tm_min -= 60;
323  tm->tm_hour++;
324  }
325  while (tm->tm_hour < 0)
326  {
327  tm->tm_hour += 24;
328  tm->tm_mday--;
329  }
330  while (tm->tm_hour >= 24)
331  {
332  tm->tm_hour -= 24;
333  tm->tm_mday++;
334  }
335  /* use loops on NNNdwmy user input values? */
336  while (tm->tm_mon < 0)
337  {
338  tm->tm_mon += 12;
339  tm->tm_year--;
340  }
341  while (tm->tm_mon >= 12)
342  {
343  tm->tm_mon -= 12;
344  tm->tm_year++;
345  }
346  while (tm->tm_mday <= 0)
347  {
348  if (tm->tm_mon)
349  tm->tm_mon--;
350  else
351  {
352  tm->tm_mon = 11;
353  tm->tm_year--;
354  }
355  tm->tm_mday += DaysPerMonth[tm->tm_mon] + is_leap_year_feb(tm);
356  }
357  while (tm->tm_mday > (DaysPerMonth[tm->tm_mon] + (leap = is_leap_year_feb(tm))))
358  {
359  tm->tm_mday -= DaysPerMonth[tm->tm_mon] + leap;
360  if (tm->tm_mon < 11)
361  tm->tm_mon++;
362  else
363  {
364  tm->tm_mon = 0;
365  tm->tm_year++;
366  }
367  }
368 }
369 
377 void mutt_date_make_date(struct Buffer *buf)
378 {
379  if (!buf)
380  return;
381 
382  time_t t = mutt_date_epoch();
383  struct tm tm = mutt_date_localtime(t);
384  time_t tz = mutt_date_local_tz(t);
385 
386  tz /= 60;
387 
388  mutt_buffer_add_printf(buf, "%s, %d %s %d %02d:%02d:%02d %+03d%02d",
389  Weekdays[tm.tm_wday], tm.tm_mday, Months[tm.tm_mon],
390  tm.tm_year + 1900, tm.tm_hour, tm.tm_min, tm.tm_sec,
391  (int) tz / 60, (int) abs((int) tz) % 60);
392 }
393 
403 int mutt_date_check_month(const char *s)
404 {
405  for (int i = 0; i < mutt_array_size(Months); i++)
406  if (mutt_istr_startswith(s, Months[i]))
407  return i;
408 
409  return -1; /* error */
410 }
411 
416 time_t mutt_date_epoch(void)
417 {
418  return mutt_date_epoch_ms() / 1000;
419 }
420 
425 uint64_t mutt_date_epoch_ms(void)
426 {
427  struct timeval tv = { 0, 0 };
428  gettimeofday(&tv, NULL);
429  /* We assume that gettimeofday doesn't modify its first argument on failure.
430  * We also kind of assume that gettimeofday does not fail. */
431  return (uint64_t) tv.tv_sec * 1000 + tv.tv_usec / 1000;
432 }
433 
445 time_t mutt_date_parse_date(const char *s, struct Tz *tz_out)
446 {
447  if (!s)
448  return -1;
449 
450  bool lax = false;
451 
452  const regmatch_t *match = mutt_prex_capture(PREX_RFC5322_DATE, s);
453  if (!match)
454  {
456  if (!match)
457  {
458  mutt_debug(LL_DEBUG1, "Could not parse date: <%s>\n", s);
459  return -1;
460  }
461  lax = true;
462  mutt_debug(LL_DEBUG2, "Fallback regex for date: <%s>\n", s);
463  }
464 
465  struct tm tm = { 0 };
466 
467  // clang-format off
468  const regmatch_t *mday = &match[lax ? PREX_RFC5322_DATE_LAX_MATCH_DAY : PREX_RFC5322_DATE_MATCH_DAY];
469  const regmatch_t *mmonth = &match[lax ? PREX_RFC5322_DATE_LAX_MATCH_MONTH : PREX_RFC5322_DATE_MATCH_MONTH];
470  const regmatch_t *myear = &match[lax ? PREX_RFC5322_DATE_LAX_MATCH_YEAR : PREX_RFC5322_DATE_MATCH_YEAR];
471  const regmatch_t *mhour = &match[lax ? PREX_RFC5322_DATE_LAX_MATCH_HOUR : PREX_RFC5322_DATE_MATCH_HOUR];
472  const regmatch_t *mminute = &match[lax ? PREX_RFC5322_DATE_LAX_MATCH_MINUTE : PREX_RFC5322_DATE_MATCH_MINUTE];
473  const regmatch_t *msecond = &match[lax ? PREX_RFC5322_DATE_LAX_MATCH_SECOND : PREX_RFC5322_DATE_MATCH_SECOND];
474  const regmatch_t *mtz = &match[lax ? PREX_RFC5322_DATE_LAX_MATCH_TZ : PREX_RFC5322_DATE_MATCH_TZ];
475  const regmatch_t *mtzobs = &match[lax ? PREX_RFC5322_DATE_LAX_MATCH_TZ_OBS : PREX_RFC5322_DATE_MATCH_TZ_OBS];
476  // clang-format on
477 
478  /* Day */
479  sscanf(s + mutt_regmatch_start(mday), "%d", &tm.tm_mday);
480  if (tm.tm_mday > 31)
481  return -1;
482 
483  /* Month */
484  tm.tm_mon = mutt_date_check_month(s + mutt_regmatch_start(mmonth));
485 
486  /* Year */
487  sscanf(s + mutt_regmatch_start(myear), "%d", &tm.tm_year);
488  if (tm.tm_year < 50)
489  tm.tm_year += 100;
490  else if (tm.tm_year >= 1900)
491  tm.tm_year -= 1900;
492 
493  /* Time */
494  int hour, min, sec = 0;
495  sscanf(s + mutt_regmatch_start(mhour), "%d", &hour);
496  sscanf(s + mutt_regmatch_start(mminute), "%d", &min);
497  if (mutt_regmatch_start(msecond) != -1)
498  sscanf(s + mutt_regmatch_start(msecond), "%d", &sec);
499  if ((hour > 23) || (min > 59) || (sec > 60))
500  return -1;
501  tm.tm_hour = hour;
502  tm.tm_min = min;
503  tm.tm_sec = sec;
504 
505  /* Time zone */
506  int zhours = 0;
507  int zminutes = 0;
508  bool zoccident = false;
509  if (mutt_regmatch_start(mtz) != -1)
510  {
511  char direction;
512  sscanf(s + mutt_regmatch_start(mtz), "%c%02d%02d", &direction, &zhours, &zminutes);
513  zoccident = (direction == '-');
514  }
515  else if (mutt_regmatch_start(mtzobs) != -1)
516  {
517  const struct Tz *tz =
518  find_tz(s + mutt_regmatch_start(mtzobs), mutt_regmatch_len(mtzobs));
519  if (tz)
520  {
521  zhours = tz->zhours;
522  zminutes = tz->zminutes;
523  zoccident = tz->zoccident;
524  }
525  }
526 
527  if (tz_out)
528  {
529  tz_out->zhours = zhours;
530  tz_out->zminutes = zminutes;
531  tz_out->zoccident = zoccident;
532  }
533 
534  return add_tz_offset(mutt_date_make_time(&tm, false), zoccident, zhours, zminutes);
535 }
536 
546 int mutt_date_make_imap(char *buf, size_t buflen, time_t timestamp)
547 {
548  if (!buf)
549  return -1;
550 
551  struct tm tm = mutt_date_localtime(timestamp);
552  time_t tz = mutt_date_local_tz(timestamp);
553 
554  tz /= 60;
555 
556  return snprintf(buf, buflen, "%02d-%s-%d %02d:%02d:%02d %+03d%02d",
557  tm.tm_mday, Months[tm.tm_mon], tm.tm_year + 1900, tm.tm_hour,
558  tm.tm_min, tm.tm_sec, (int) tz / 60, (int) abs((int) tz) % 60);
559 }
560 
572 int mutt_date_make_tls(char *buf, size_t buflen, time_t timestamp)
573 {
574  if (!buf)
575  return -1;
576 
577  struct tm tm = mutt_date_gmtime(timestamp);
578  return snprintf(buf, buflen, "%s, %d %s %d %02d:%02d:%02d UTC",
579  Weekdays[tm.tm_wday], tm.tm_mday, Months[tm.tm_mon],
580  tm.tm_year + 1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
581 }
582 
589 time_t mutt_date_parse_imap(const char *s)
590 {
591  const regmatch_t *match = mutt_prex_capture(PREX_IMAP_DATE, s);
592  if (!match)
593  return 0;
594 
595  const regmatch_t *mday = &match[PREX_IMAP_DATE_MATCH_DAY];
596  const regmatch_t *mmonth = &match[PREX_IMAP_DATE_MATCH_MONTH];
597  const regmatch_t *myear = &match[PREX_IMAP_DATE_MATCH_YEAR];
598  const regmatch_t *mtime = &match[PREX_IMAP_DATE_MATCH_TIME];
599  const regmatch_t *mtz = &match[PREX_IMAP_DATE_MATCH_TZ];
600 
601  struct tm tm;
602 
603  sscanf(s + mutt_regmatch_start(mday), " %d", &tm.tm_mday);
604  tm.tm_mon = mutt_date_check_month(s + mutt_regmatch_start(mmonth));
605  sscanf(s + mutt_regmatch_start(myear), "%d", &tm.tm_year);
606  tm.tm_year -= 1900;
607  sscanf(s + mutt_regmatch_start(mtime), "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
608 
609  char direction;
610  int zhours, zminutes;
611  sscanf(s + mutt_regmatch_start(mtz), "%c%02d%02d", &direction, &zhours, &zminutes);
612  bool zoccident = (direction == '-');
613 
614  return add_tz_offset(mutt_date_make_time(&tm, false), zoccident, zhours, zminutes);
615 }
616 
625 time_t mutt_date_add_timeout(time_t now, time_t timeout)
626 {
627  if (timeout < 0)
628  return now;
629 
630  if ((TIME_T_MAX - now) < timeout)
631  return TIME_T_MAX;
632 
633  return now + timeout;
634 }
635 
643 struct tm mutt_date_localtime(time_t t)
644 {
645  struct tm tm = { 0 };
646 
647  if (t == MUTT_DATE_NOW)
648  t = mutt_date_epoch();
649 
650  localtime_r(&t, &tm);
651  return tm;
652 }
653 
661 struct tm mutt_date_gmtime(time_t t)
662 {
663  struct tm tm = { 0 };
664 
665  if (t == MUTT_DATE_NOW)
666  t = mutt_date_epoch();
667 
668  gmtime_r(&t, &tm);
669  return tm;
670 }
671 
680 size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
681 {
682  if (!buf || !format)
683  return 0;
684 
685  struct tm tm = mutt_date_localtime(t);
686  return strftime(buf, buflen, format, &tm);
687 }
688 
693 void mutt_date_sleep_ms(size_t ms)
694 {
695  const struct timespec sleep = {
696  .tv_sec = ms / 1000,
697  .tv_nsec = (ms % 1000) * 1000000UL,
698  };
699  nanosleep(&sleep, NULL);
700 }
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:416
Tue, 3 Mar [2020] 14:32:55 +0200
Definition: prex.h:127
#define TIME_T_MIN
Definition: date.h:34
uint64_t mutt_date_epoch_ms(void)
Return the number of milliseconds since the Unix epoch.
Definition: date.c:425
Manage precompiled / predefined regular expressions.
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition: date.c:680
void mutt_date_make_date(struct Buffer *buf)
Write a date in RFC822 format to a buffer.
Definition: date.c:377
Tue, [3] Mar 2020 14:32:55 +0200
Definition: prex.h:125
Memory management wrappers.
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition: date.c:643
#define TIME_T_MAX
Definition: date.h:33
Tue, 3 Mar 2020 14:32:55[UT]
Definition: prex.h:172
[16-MAR-2020 15:09:35 -0700]
Definition: prex.h:39
Tue, 3 Mar 2020 14:32:[55] +0200
Definition: prex.h:168
static const char *const Months[]
Months of the year (abbreviated)
Definition: date.c:55
static size_t mutt_regmatch_len(const regmatch_t *match)
Return the length of a match.
Definition: regex3.h:80
String manipulation buffer.
Definition: buffer.h:33
void mutt_date_normalize_time(struct tm *tm)
Fix the contents of a struct tm.
Definition: date.c:295
static const char * timestamp(time_t stamp)
Create a YYYY-MM-DD HH:MM:SS timestamp.
Definition: logging.c:77
Tue, [3] Mar 2020 14:32:55 +0200
Definition: prex.h:156
#define MUTT_DATE_NOW
Constant representing the &#39;current time&#39;, see: mutt_date_gmtime(), mutt_date_localtime() ...
Definition: date.h:39
15-MAR-2020 15:09:35 [-0700]
Definition: prex.h:190
struct tm mutt_date_gmtime(time_t t)
Converts calendar time to a broken-down time structure expressed in UTC timezone. ...
Definition: date.c:661
time_t mutt_date_local_tz(time_t t)
Calculate the local timezone in seconds east of UTC.
Definition: date.c:206
15-MAR-2020 [15:09:35] -0700
Definition: prex.h:189
time_t mutt_date_parse_date(const char *s, struct Tz *tz_out)
Parse a date string in RFC822 format.
Definition: date.c:445
static int is_leap_year_feb(struct tm *tm)
Is a given February in a leap year.
Definition: date.c:189
Tue, 3 Mar 2020 14:[32]:55 +0200
Definition: prex.h:129
Tue, 3 Mar [2020] 14:32:55 +0200
Definition: prex.h:160
unsigned char zhours
Hours away from UTC.
Definition: date.h:47
char tzname[8]
Name, e.g. UTC.
Definition: date.h:46
Tue, 3 Mar 2020 14:32:55 [+0200]
Definition: prex.h:133
Logging Dispatcher.
15-MAR-[2020] 15:09:35 -0700
Definition: prex.h:188
time_t tv_sec
Definition: file.h:48
String manipulation functions.
bool mutt_istrn_equal(const char *a, const char *b, size_t l)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition: string.c:621
#define mutt_array_size(x)
Definition: memory.h:33
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:625
Tue, 3 [Jan] 2020 14:32:55 +0200
Definition: prex.h:126
int mutt_date_make_tls(char *buf, size_t buflen, time_t timestamp)
Format date in TLS certificate verification style.
Definition: date.c:572
Log at debug level 2.
Definition: logging.h:41
Tue, 3 Mar 2020 14:[32]:55 +0200
Definition: prex.h:164
[Mon, (Comment) 16 Mar 2020 15:09:35 -0700]
Definition: prex.h:38
bool zoccident
True if west of UTC, False if East.
Definition: date.h:49
Tue, 3 Mar 2020 14:32:55 [+0200]
Definition: prex.h:171
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:203
Tue, 3 Mar 2020 [14]:32:55 +0200
Definition: prex.h:128
[ 4]-MAR-2020 15:09:35 -0700
Definition: prex.h:184
regmatch_t * mutt_prex_capture(enum Prex which, const char *str)
match a precompiled regex against a string
Definition: prex.c:306
static const struct Tz * find_tz(const char *s, size_t len)
Look up a timezone.
Definition: date.c:174
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
Tue, 3 [Jan] 2020 14:32:55 +0200
Definition: prex.h:158
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
static regoff_t mutt_regmatch_start(const regmatch_t *match)
Return the start of a match.
Definition: regex3.h:60
[Mon, 16 Mar 2020 15:09:35 -0700]
Definition: prex.h:37
static time_t compute_tz(time_t g, struct tm *utc)
Calculate the number of seconds east of UTC.
Definition: date.c:127
15-[MAR]-2020 15:09:35 -0700
Definition: prex.h:187
unsigned char zminutes
Minutes away from UTC.
Definition: date.h:48
General purpose object for storing and parsing strings.
List of recognised Timezones.
Definition: date.h:44
Log at debug level 1.
Definition: logging.h:40
Tue, 3 Mar 2020 14:32:[55] +0200
Definition: prex.h:131
int mutt_date_check_month(const char *s)
Is the string a valid month name.
Definition: date.c:403
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:546
Time value with nanosecond precision.
Definition: file.h:46
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
time_t mutt_date_parse_imap(const char *s)
Parse date of the form: DD-MMM-YYYY HH:MM:SS +ZZzz.
Definition: date.c:589
static const char *const Weekdays[]
Day of the week (abbreviated)
Definition: date.c:48
Time and date handling routines.
time_t mutt_date_make_time(struct tm *t, bool local)
Convert struct tm to time_t
Definition: date.c:229
Tue, 3 Mar 2020 [14]:32:55 +0200
Definition: prex.h:162
void mutt_date_sleep_ms(size_t ms)
Sleep for milliseconds.
Definition: date.c:693
Tue, 3 Mar 2020 14:32:55[UT]
Definition: prex.h:134
Manage regular expressions.