NeoMutt
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
date.c File Reference

Time and date handling routines. More...

#include "config.h"
#include <ctype.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include "date.h"
#include "buffer.h"
#include "eqi.h"
#include "logging2.h"
#include "memory.h"
#include "prex.h"
#include "regex3.h"
#include "string2.h"
+ Include dependency graph for date.c:

Go to the source code of this file.

Functions

static int compute_tz (time_t g, struct tm *utc)
 Calculate the number of seconds east of UTC.
 
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.
 
static const struct Tzfind_tz (const char *s, size_t len)
 Look up a timezone.
 
static int is_leap_year_feb (struct tm *tm)
 Is a given February in a leap year.
 
int mutt_date_local_tz (time_t t)
 Calculate the local timezone in seconds east of UTC.
 
time_t mutt_date_make_time (struct tm *t, bool local)
 Convert struct tm to time_t
 
void mutt_date_normalize_time (struct tm *tm)
 Fix the contents of a struct tm.
 
void mutt_date_make_date (struct Buffer *buf, bool local)
 Write a date in RFC822 format to a buffer.
 
int mutt_date_check_month (const char *s)
 Is the string a valid month name.
 
time_t mutt_date_now (void)
 Return the number of seconds since the Unix epoch.
 
uint64_t mutt_date_now_ms (void)
 Return the number of milliseconds since the Unix epoch.
 
static int parse_small_uint (const char *str, const char *end, int *val)
 Parse a positive integer of at most 5 digits.
 
static time_t mutt_date_parse_rfc5322_strict (const char *s, struct Tz *tz_out)
 Parse a date string in RFC822 format.
 
time_t mutt_date_parse_date (const char *s, struct Tz *tz_out)
 Parse a date string in RFC822 format.
 
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.
 
int mutt_date_make_tls (char *buf, size_t buflen, time_t timestamp)
 Format date in TLS certificate verification style.
 
time_t mutt_date_parse_imap (const char *s)
 Parse date of the form: DD-MMM-YYYY HH:MM:SS +ZZzz.
 
time_t mutt_date_add_timeout (time_t now, time_t timeout)
 Safely add a timeout to a given time_t value.
 
struct tm mutt_date_localtime (time_t t)
 Converts calendar time to a broken-down time structure expressed in user timezone.
 
struct tm mutt_date_gmtime (time_t t)
 Converts calendar time to a broken-down time structure expressed in UTC timezone.
 
size_t mutt_date_localtime_format (char *buf, size_t buflen, const char *format, time_t t)
 Format localtime.
 
size_t mutt_date_localtime_format_locale (char *buf, size_t buflen, const char *format, time_t t, locale_t loc)
 Format localtime using a given locale.
 
void mutt_date_sleep_ms (size_t ms)
 Sleep for milliseconds.
 

Variables

static const char *const Weekdays []
 Day of the week (abbreviated)
 
static const char *const Months []
 Months of the year (abbreviated)
 
static const struct Tz TimeZones []
 Lookup table of Time Zones.
 

Detailed Description

Time and date handling routines.

Authors
  • Michael R. Elkins

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file date.c.

Function Documentation

◆ compute_tz()

static int compute_tz ( time_t  g,
struct tm *  utc 
)
static

Calculate the number of seconds east of UTC.

Parameters
gLocal time
utcUTC time
Return values
numSeconds east of UTC

returns the seconds east of UTC given 'g' and its corresponding gmtime() representation

Definition at line 130 of file date.c.

131{
132 struct tm lt = mutt_date_localtime(g);
133
134 int tz = (((lt.tm_hour - utc->tm_hour) * 60) + (lt.tm_min - utc->tm_min)) * 60;
135
136 int yday = (lt.tm_yday - utc->tm_yday);
137 if (yday != 0)
138 {
139 /* This code is optimized to negative timezones (West of Greenwich) */
140 if ((yday == -1) || /* UTC passed midnight before localtime */
141 (yday > 1)) /* UTC passed new year before localtime */
142 {
143 tz -= (24 * 60 * 60);
144 }
145 else
146 {
147 tz += (24 * 60 * 60);
148 }
149 }
150
151 return tz;
152}
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition: date.c:879
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ add_tz_offset()

static time_t add_tz_offset ( time_t  t,
bool  w,
time_t  h,
time_t  m 
)
static

Compute and add a timezone offset to an UTC time.

Parameters
tUTC time
wTrue if west of UTC, false if east
hNumber of hours in the timezone
mNumber of minutes in the timezone
Return values
numTimezone offset in seconds

Definition at line 162 of file date.c.

163{
164 if ((t != TIME_T_MAX) && (t != TIME_T_MIN))
165 return t + (w ? 1 : -1) * (((time_t) h * 3600) + ((time_t) m * 60));
166 else
167 return t;
168}
#define TIME_T_MAX
Definition: date.h:37
#define TIME_T_MIN
Definition: date.h:38
+ Here is the caller graph for this function:

◆ find_tz()

static const struct Tz * find_tz ( const char *  s,
size_t  len 
)
static

Look up a timezone.

Parameters
sTimezone to lookup
lenLength of the s string
Return values
ptrPointer to the Tz struct
NULLNot found

Definition at line 177 of file date.c.

178{
179 for (size_t i = 0; i < mutt_array_size(TimeZones); i++)
180 {
181 if (mutt_istrn_equal(TimeZones[i].tzname, s, len))
182 return &TimeZones[i];
183 }
184 return NULL;
185}
#define mutt_array_size(x)
Definition: memory.h:38
static const struct Tz TimeZones[]
Lookup table of Time Zones.
Definition: date.c:67
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:525
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ is_leap_year_feb()

static int is_leap_year_feb ( struct tm *  tm)
static

Is a given February in a leap year.

Parameters
tmDate to be tested
Return values
trueIt's a leap year

Definition at line 192 of file date.c.

193{
194 if (tm->tm_mon != 1)
195 return 0;
196
197 int y = tm->tm_year + 1900;
198 return ((y & 3) == 0) && (((y % 100) != 0) || ((y % 400) == 0));
199}
+ Here is the caller graph for this function:

◆ mutt_date_local_tz()

int mutt_date_local_tz ( time_t  t)

Calculate the local timezone in seconds east of UTC.

Parameters
tTime to examine
Return values
numSeconds east of UTC

Returns the local timezone in seconds east of UTC for the time t, or for the current time if t is zero.

Definition at line 209 of file date.c.

210{
211 /* Check we haven't overflowed the time (on 32-bit arches) */
212 if ((t == TIME_T_MAX) || (t == TIME_T_MIN))
213 return 0;
214
215 if (t == 0)
216 t = mutt_date_now();
217
218 struct tm tm = mutt_date_gmtime(t);
219 return compute_tz(t, &tm);
220}
static int compute_tz(time_t g, struct tm *utc)
Calculate the number of seconds east of UTC.
Definition: date.c:130
struct tm mutt_date_gmtime(time_t t)
Converts calendar time to a broken-down time structure expressed in UTC timezone.
Definition: date.c:900
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:446
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_date_make_time()

time_t mutt_date_make_time ( struct tm *  t,
bool  local 
)

Convert struct tm to time_t

Parameters
tTime to convert
localShould the local timezone be considered
Return values
numTime in Unix format
TIME_T_MINError

Convert a struct tm to time_t, but don't take the local timezone into account unless "local" is nonzero

Definition at line 232 of file date.c.

233{
234 if (!t)
235 return TIME_T_MIN;
236
237 static const int AccumDaysPerMonth[mutt_array_size(Months)] = {
238 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
239 };
240
241 /* Prevent an integer overflow, with some arbitrary limits. */
242 if (t->tm_year > 10000)
243 return TIME_T_MAX;
244 if (t->tm_year < -10000)
245 return TIME_T_MIN;
246
247 if ((t->tm_mday < 1) || (t->tm_mday > 31))
248 return TIME_T_MIN;
249 if ((t->tm_hour < 0) || (t->tm_hour > 23) || (t->tm_min < 0) ||
250 (t->tm_min > 59) || (t->tm_sec < 0) || (t->tm_sec > 60))
251 {
252 return TIME_T_MIN;
253 }
254 if (t->tm_year > 9999)
255 return TIME_T_MAX;
256
257 /* Compute the number of days since January 1 in the same year */
258 int yday = AccumDaysPerMonth[t->tm_mon % mutt_array_size(Months)];
259
260 /* The leap years are 1972 and every 4. year until 2096,
261 * but this algorithm will fail after year 2099 */
262 yday += t->tm_mday;
263 if ((t->tm_year % 4) || (t->tm_mon < 2))
264 yday--;
265 t->tm_yday = yday;
266
267 time_t g = yday;
268
269 /* Compute the number of days since January 1, 1970 */
270 g += (t->tm_year - 70) * (time_t) 365;
271 g += (t->tm_year - 69) / 4;
272
273 /* Compute the number of hours */
274 g *= 24;
275 g += t->tm_hour;
276
277 /* Compute the number of minutes */
278 g *= 60;
279 g += t->tm_min;
280
281 /* Compute the number of seconds */
282 g *= 60;
283 g += t->tm_sec;
284
285 if (local)
286 g -= compute_tz(g, t);
287
288 return g;
289}
static const char *const Months[]
Months of the year (abbreviated)
Definition: date.c:57
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_date_normalize_time()

void mutt_date_normalize_time ( struct tm *  tm)

Fix the contents of a struct tm.

Parameters
tmTime to correct

If values have been added/subtracted from a struct tm, it can lead to invalid dates, e.g. Adding 10 days to the 25th of a month.

This function will correct any over/under-flow.

Definition at line 300 of file date.c.

301{
302 if (!tm)
303 return;
304
305 static const char DaysPerMonth[mutt_array_size(Months)] = {
306 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
307 };
308 int leap;
309
310 while (tm->tm_sec < 0)
311 {
312 tm->tm_sec += 60;
313 tm->tm_min--;
314 }
315 while (tm->tm_sec >= 60)
316 {
317 tm->tm_sec -= 60;
318 tm->tm_min++;
319 }
320 while (tm->tm_min < 0)
321 {
322 tm->tm_min += 60;
323 tm->tm_hour--;
324 }
325 while (tm->tm_min >= 60)
326 {
327 tm->tm_min -= 60;
328 tm->tm_hour++;
329 }
330 while (tm->tm_hour < 0)
331 {
332 tm->tm_hour += 24;
333 tm->tm_mday--;
334 }
335 while (tm->tm_hour >= 24)
336 {
337 tm->tm_hour -= 24;
338 tm->tm_mday++;
339 }
340 /* use loops on NNNdwmy user input values? */
341 while (tm->tm_mon < 0)
342 {
343 tm->tm_mon += 12;
344 tm->tm_year--;
345 }
346 while (tm->tm_mon >= 12)
347 {
348 tm->tm_mon -= 12;
349 tm->tm_year++;
350 }
351 while (tm->tm_mday <= 0)
352 {
353 if (tm->tm_mon)
354 {
355 tm->tm_mon--;
356 }
357 else
358 {
359 tm->tm_mon = 11;
360 tm->tm_year--;
361 }
362 tm->tm_mday += DaysPerMonth[tm->tm_mon] + is_leap_year_feb(tm);
363 }
364 while (tm->tm_mday > (DaysPerMonth[tm->tm_mon] + (leap = is_leap_year_feb(tm))))
365 {
366 tm->tm_mday -= DaysPerMonth[tm->tm_mon] + leap;
367 if (tm->tm_mon < 11)
368 {
369 tm->tm_mon++;
370 }
371 else
372 {
373 tm->tm_mon = 0;
374 tm->tm_year++;
375 }
376 }
377}
static int is_leap_year_feb(struct tm *tm)
Is a given February in a leap year.
Definition: date.c:192
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_date_make_date()

void mutt_date_make_date ( struct Buffer buf,
bool  local 
)

Write a date in RFC822 format to a buffer.

Parameters
bufBuffer for result
localIf true, use the local timezone. Otherwise use UTC.

Appends the date to the passed in buffer. The buffer is not cleared because some callers prepend quotes.

Definition at line 387 of file date.c.

388{
389 if (!buf)
390 return;
391
392 struct tm tm = { 0 };
393 int tz = 0;
394
395 time_t t = mutt_date_now();
396 if (local)
397 {
398 tm = mutt_date_localtime(t);
399 tz = mutt_date_local_tz(t);
400 }
401 else
402 {
403 tm = mutt_date_gmtime(t);
404 }
405
406 tz /= 60;
407
408 buf_add_printf(buf, "%s, %d %s %d %02d:%02d:%02d %+03d%02d", Weekdays[tm.tm_wday],
409 tm.tm_mday, Months[tm.tm_mon], tm.tm_year + 1900, tm.tm_hour,
410 tm.tm_min, tm.tm_sec, tz / 60, abs(tz) % 60);
411}
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:216
static const char *const Weekdays[]
Day of the week (abbreviated)
Definition: date.c:50
int mutt_date_local_tz(time_t t)
Calculate the local timezone in seconds east of UTC.
Definition: date.c:209
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_date_check_month()

int mutt_date_check_month ( const char *  s)

Is the string a valid month name.

Parameters
sString to check (must be at least 3 bytes long)
Return values
numIndex into Months array (0-based)
-1Error
Note
Only the first three characters are checked
The comparison is case insensitive

Definition at line 422 of file date.c.

423{
424 if (!s)
425 return -1;
426
427 char buf[4] = { 0 };
428 memcpy(buf, s, 3);
429 uint32_t sv;
430 memcpy(&sv, buf, sizeof(sv));
431 for (int i = 0; i < mutt_array_size(Months); i++)
432 {
433 uint32_t mv;
434 memcpy(&mv, Months[i], sizeof(mv));
435 if (sv == mv)
436 return i;
437 }
438
439 return -1; /* error */
440}
+ Here is the caller graph for this function:

◆ mutt_date_now()

time_t mutt_date_now ( void  )

Return the number of seconds since the Unix epoch.

Return values
numNumber of seconds since the Unix epoch, or 0 on failure

Definition at line 446 of file date.c.

447{
448 return mutt_date_now_ms() / 1000;
449}
uint64_t mutt_date_now_ms(void)
Return the number of milliseconds since the Unix epoch.
Definition: date.c:455
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_date_now_ms()

uint64_t mutt_date_now_ms ( void  )

Return the number of milliseconds since the Unix epoch.

Return values
numThe number of ms since the Unix epoch, or 0 on failure

Definition at line 455 of file date.c.

456{
457 struct timeval tv = { 0, 0 };
458 gettimeofday(&tv, NULL);
459 /* We assume that gettimeofday doesn't modify its first argument on failure.
460 * We also kind of assume that gettimeofday does not fail. */
461 return (uint64_t) (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
462}
+ Here is the caller graph for this function:

◆ parse_small_uint()

static int parse_small_uint ( const char *  str,
const char *  end,
int *  val 
)
static

Parse a positive integer of at most 5 digits.

Parameters
[in]strString to parse
[in]endEnd of the string
[out]valValue
Return values
numNumber of chars parsed

Leaves val untouched if the given string does not start with an integer; ignores junk after it or any digits beyond the first five (this is so that the function can never overflow, yet check if the integer is larger than the maximum 4 digits supported in a year). and does not support negative numbers. Empty strings are parsed as zero.

Definition at line 477 of file date.c.

478{
479 const char *ptr = str;
480 int v = 0;
481 while ((ptr < end) && (ptr < (str + 5)) && (*ptr >= '0') && (*ptr <= '9'))
482 {
483 v = (v * 10) + (*ptr - '0');
484 ++ptr;
485 }
486 *val = v;
487 return ptr - str;
488}
+ Here is the caller graph for this function:

◆ mutt_date_parse_rfc5322_strict()

static time_t mutt_date_parse_rfc5322_strict ( const char *  s,
struct Tz tz_out 
)
static

Parse a date string in RFC822 format.

Parameters
[in]sString to parse
[out]tz_outTimezone info (OPTIONAL)
Return values
numUnix time in seconds

Parse a date string in RFC822 format, without any comments or extra whitespace (except a comment at the very end, since that is very common for time zones).

This is a fairly straightforward implementation in the hope of extracting the valid cases quickly, i.e., without having to resort to a regex. The hard cases are left to a regex implementation further down in mutt_date_parse_date() (which calls us).

Spec: https://tools.ietf.org/html/rfc5322#section-3.3

Definition at line 507 of file date.c.

508{
509 size_t len = strlen(s);
510
511 /* Skip over the weekday, if any. */
512 if ((len >= 5) && (s[4] == ' ') &&
513 (eqi4(s, "Mon,") || eqi4(s, "Tue,") || eqi4(s, "Wed,") ||
514 eqi4(s, "Thu,") || eqi4(s, "Fri,") || eqi4(s, "Sat,") || eqi4(s, "Sun,")))
515 {
516 s += 5;
517 len -= 5;
518 }
519
520 while ((len > 0) && (*s == ' '))
521 {
522 ++s;
523 --len;
524 }
525
526 if ((len == 0) || (*s < '0') || (*s > '9'))
527 return -1;
528
529 struct tm tm = { 0 };
530
531 /* Day */
532 int mday_len = parse_small_uint(s, s + len, &tm.tm_mday);
533 if ((mday_len == 0) || (mday_len > 2) || (tm.tm_mday > 31))
534 return -1;
535 s += mday_len;
536 len -= mday_len;
537
538 if ((len == 0) || (*s != ' '))
539 return -1;
540 ++s;
541 --len;
542
543 /* Month */
544 if (len < 3)
545 return -1;
546 tm.tm_mon = mutt_date_check_month(s);
547 if (tm.tm_mon == -1)
548 return -1;
549 s += 3;
550 len -= 3;
551
552 if ((len == 0) || (*s != ' '))
553 return -1;
554 ++s;
555 --len;
556
557 /* Year */
558 int year_len = parse_small_uint(s, s + len, &tm.tm_year);
559 if ((year_len != 2) && (year_len != 4))
560 return -1;
561 if (tm.tm_year < 50)
562 tm.tm_year += 100;
563 else if (tm.tm_year >= 1900)
564 tm.tm_year -= 1900;
565 s += year_len;
566 len -= year_len;
567
568 if ((len == 0) || (*s != ' '))
569 return -1;
570 ++s;
571 --len;
572
573 /* Hour */
574 if ((len < 3) || (s[0] < '0') || (s[0] > '2') || (s[1] < '0') ||
575 (s[1] > '9') || (s[2] != ':'))
576 {
577 return -1;
578 }
579 tm.tm_hour = ((s[0] - '0') * 10) + (s[1] - '0');
580 if (tm.tm_hour > 23)
581 return -1;
582 s += 3;
583 len -= 3;
584
585 /* Minute */
586 if ((len < 2) || (s[0] < '0') || (s[0] > '5') || (s[1] < '0') || (s[1] > '9'))
587 return -1;
588 tm.tm_min = ((s[0] - '0') * 10) + (s[1] - '0');
589 if (tm.tm_min > 59)
590 return -1;
591 s += 2;
592 len -= 2;
593
594 /* Second (optional) */
595 if ((len > 0) && (s[0] == ':'))
596 {
597 ++s;
598 --len;
599 if ((len < 2) || (s[0] < '0') || (s[0] > '5') || (s[1] < '0') || (s[1] > '9'))
600 return -1;
601 tm.tm_sec = ((s[0] - '0') * 10) + (s[1] - '0');
602 if (tm.tm_sec > 60)
603 return -1;
604 s += 2;
605 len -= 2;
606 }
607
608 while ((len > 0) && (*s == ' '))
609 {
610 ++s;
611 --len;
612 }
613
614 /* Strip optional time zone comment and white space from the end
615 * (this is the only one that is very common) */
616 while ((len > 0) && (s[len - 1] == ' '))
617 --len;
618 if ((len >= 2) && (s[len - 1] == ')'))
619 {
620 for (int i = len - 1; i-- > 0;)
621 {
622 if (s[i] == '(')
623 {
624 len = i;
625 break;
626 }
627 if (!isalpha(s[i]) && (s[i] != ' '))
628 return -1; /* give up more complex comment parsing */
629 }
630 }
631 while ((len > 0) && (s[len - 1] == ' '))
632 --len;
633
634 /* Time zone (optional) */
635 int zhours = 0;
636 int zminutes = 0;
637 bool zoccident = false;
638 if (len > 0)
639 {
640 if ((len == 5) && ((s[0] == '+') || (s[0] == '-')) && (s[1] >= '0') &&
641 (s[1] <= '9') && (s[2] >= '0') && (s[2] <= '9') && (s[3] >= '0') &&
642 (s[3] <= '9') && (s[4] >= '0') && (s[4] <= '9'))
643 {
644 zoccident = (s[0] == '-');
645 zhours = ((s[1] - '0') * 10) + (s[2] - '0');
646 zminutes = ((s[3] - '0') * 10) + (s[4] - '0');
647 }
648 else
649 {
650 for (int i = 0; i < len; ++i)
651 {
652 if (!isalpha(s[i]))
653 return -1;
654 }
655 const struct Tz *tz = find_tz(s, len);
656 if (tz)
657 {
658 zhours = tz->zhours;
659 zminutes = tz->zminutes;
660 zoccident = tz->zoccident;
661 }
662 }
663 }
664
665 if (tz_out)
666 {
667 tz_out->zhours = zhours;
668 tz_out->zminutes = zminutes;
669 tz_out->zoccident = zoccident;
670 }
671
673}
static bool eqi4(const char *a, const char b[4])
Compare two 4-byte strings, ignoring case - See: Case-insensitive fixed-chunk comparisons.
Definition: eqi.h:104
time_t mutt_date_make_time(struct tm *t, bool local)
Convert struct tm to time_t
Definition: date.c:232
static int parse_small_uint(const char *str, const char *end, int *val)
Parse a positive integer of at most 5 digits.
Definition: date.c:477
int mutt_date_check_month(const char *s)
Is the string a valid month name.
Definition: date.c:422
static const struct Tz * find_tz(const char *s, size_t len)
Look up a timezone.
Definition: date.c:177
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:162
List of recognised Timezones.
Definition: date.h:47
unsigned char zminutes
Minutes away from UTC.
Definition: date.h:50
bool zoccident
True if west of UTC, False if East.
Definition: date.h:51
unsigned char zhours
Hours away from UTC.
Definition: date.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_date_parse_date()

time_t mutt_date_parse_date ( const char *  s,
struct Tz tz_out 
)

Parse a date string in RFC822 format.

Parameters
[in]sString to parse
[out]tz_outPointer to timezone (optional)
Return values
numUnix time in seconds

Parse a date of the form: [ weekday , ] day-of-month month year hour:minute:second [ timezone ]

The 'timezone' field is optional; it defaults to +0000 if missing.

Definition at line 686 of file date.c.

687{
688 if (!s)
689 return -1;
690
691 const time_t strict_t = mutt_date_parse_rfc5322_strict(s, tz_out);
692 if (strict_t != -1)
693 return strict_t;
694
695 const regmatch_t *match = mutt_prex_capture(PREX_RFC5322_DATE_LAX, s);
696 if (!match)
697 {
698 mutt_debug(LL_DEBUG1, "Could not parse date: <%s>\n", s);
699 return -1;
700 }
701 mutt_debug(LL_DEBUG2, "Fallback regex for date: <%s>\n", s);
702
703 struct tm tm = { 0 };
704
705 // clang-format off
706 const regmatch_t *mday = &match[PREX_RFC5322_DATE_LAX_MATCH_DAY];
707 const regmatch_t *mmonth = &match[PREX_RFC5322_DATE_LAX_MATCH_MONTH];
708 const regmatch_t *myear = &match[PREX_RFC5322_DATE_LAX_MATCH_YEAR];
709 const regmatch_t *mhour = &match[PREX_RFC5322_DATE_LAX_MATCH_HOUR];
710 const regmatch_t *mminute = &match[PREX_RFC5322_DATE_LAX_MATCH_MINUTE];
711 const regmatch_t *msecond = &match[PREX_RFC5322_DATE_LAX_MATCH_SECOND];
712 const regmatch_t *mtz = &match[PREX_RFC5322_DATE_LAX_MATCH_TZ];
713 const regmatch_t *mtzobs = &match[PREX_RFC5322_DATE_LAX_MATCH_TZ_OBS];
714 // clang-format on
715
716 /* Day */
717 sscanf(s + mutt_regmatch_start(mday), "%d", &tm.tm_mday);
718 if (tm.tm_mday > 31)
719 return -1;
720
721 /* Month */
722 tm.tm_mon = mutt_date_check_month(s + mutt_regmatch_start(mmonth));
723
724 /* Year */
725 sscanf(s + mutt_regmatch_start(myear), "%d", &tm.tm_year);
726 if (tm.tm_year < 50)
727 tm.tm_year += 100;
728 else if (tm.tm_year >= 1900)
729 tm.tm_year -= 1900;
730
731 /* Time */
732 int hour, min, sec = 0;
733 sscanf(s + mutt_regmatch_start(mhour), "%d", &hour);
734 sscanf(s + mutt_regmatch_start(mminute), "%d", &min);
735 if (mutt_regmatch_start(msecond) != -1)
736 sscanf(s + mutt_regmatch_start(msecond), "%d", &sec);
737 if ((hour > 23) || (min > 59) || (sec > 60))
738 return -1;
739 tm.tm_hour = hour;
740 tm.tm_min = min;
741 tm.tm_sec = sec;
742
743 /* Time zone */
744 int zhours = 0;
745 int zminutes = 0;
746 bool zoccident = false;
747 if (mutt_regmatch_start(mtz) != -1)
748 {
749 char direction;
750 sscanf(s + mutt_regmatch_start(mtz), "%c%02d%02d", &direction, &zhours, &zminutes);
751 zoccident = (direction == '-');
752 }
753 else if (mutt_regmatch_start(mtzobs) != -1)
754 {
755 const struct Tz *tz = find_tz(s + mutt_regmatch_start(mtzobs),
756 mutt_regmatch_len(mtzobs));
757 if (tz)
758 {
759 zhours = tz->zhours;
760 zminutes = tz->zminutes;
761 zoccident = tz->zoccident;
762 }
763 }
764
765 if (tz_out)
766 {
767 tz_out->zhours = zhours;
768 tz_out->zminutes = zminutes;
769 tz_out->zoccident = zoccident;
770 }
771
773}
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
static time_t mutt_date_parse_rfc5322_strict(const char *s, struct Tz *tz_out)
Parse a date string in RFC822 format.
Definition: date.c:507
regmatch_t * mutt_prex_capture(enum Prex which, const char *str)
Match a precompiled regex against a string.
Definition: prex.c:289
@ PREX_RFC5322_DATE_LAX
[Mon, (Comment) 16 Mar 2020 15:09:35 -0700]
Definition: prex.h:37
@ PREX_RFC5322_DATE_LAX_MATCH_SECOND
Tue, 3 Mar 2020 14:32:[55] +0200
Definition: prex.h:145
@ PREX_RFC5322_DATE_LAX_MATCH_TZ
Tue, 3 Mar 2020 14:32:55 [+0200]
Definition: prex.h:148
@ PREX_RFC5322_DATE_LAX_MATCH_YEAR
Tue, 3 Mar [2020] 14:32:55 +0200
Definition: prex.h:137
@ PREX_RFC5322_DATE_LAX_MATCH_HOUR
Tue, 3 Mar 2020 [14]:32:55 +0200
Definition: prex.h:139
@ PREX_RFC5322_DATE_LAX_MATCH_MINUTE
Tue, 3 Mar 2020 14:[32]:55 +0200
Definition: prex.h:141
@ PREX_RFC5322_DATE_LAX_MATCH_TZ_OBS
Tue, 3 Mar 2020 14:32:55[UT]
Definition: prex.h:149
@ PREX_RFC5322_DATE_LAX_MATCH_MONTH
Tue, 3 [Jan] 2020 14:32:55 +0200
Definition: prex.h:135
@ PREX_RFC5322_DATE_LAX_MATCH_DAY
Tue, [3] Mar 2020 14:32:55 +0200
Definition: prex.h:133
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
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_date_make_imap()

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.

Parameters
bufBuffer to store the results
buflenLength of buffer
timestampTime to format
Return values
numCharacters written to buf

Caller should provide a buffer of at least 27 bytes.

Definition at line 784 of file date.c.

785{
786 if (!buf)
787 return -1;
788
789 struct tm tm = mutt_date_localtime(timestamp);
791
792 tz /= 60;
793
794 return snprintf(buf, buflen, "%02d-%s-%d %02d:%02d:%02d %+03d%02d",
795 tm.tm_mday, Months[tm.tm_mon], tm.tm_year + 1900, tm.tm_hour,
796 tm.tm_min, tm.tm_sec, tz / 60, abs(tz) % 60);
797}
static const char * timestamp(time_t stamp)
Create a YYYY-MM-DD HH:MM:SS timestamp.
Definition: logging.c:77
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_date_make_tls()

int mutt_date_make_tls ( char *  buf,
size_t  buflen,
time_t  timestamp 
)

Format date in TLS certificate verification style.

Parameters
bufBuffer to store the results
buflenLength of buffer
timestampTime to format
Return values
numCharacters written to buf

e.g., Mar 17 16:40:46 2016 UTC. The time is always in UTC.

Caller should provide a buffer of at least 27 bytes.

Definition at line 810 of file date.c.

811{
812 if (!buf)
813 return -1;
814
815 struct tm tm = mutt_date_gmtime(timestamp);
816 return snprintf(buf, buflen, "%s, %d %s %d %02d:%02d:%02d UTC",
817 Weekdays[tm.tm_wday], tm.tm_mday, Months[tm.tm_mon],
818 tm.tm_year + 1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
819}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_date_parse_imap()

time_t mutt_date_parse_imap ( const char *  s)

Parse date of the form: DD-MMM-YYYY HH:MM:SS +ZZzz.

Parameters
sDate in string form
Return values
numUnix time
0Error

Definition at line 827 of file date.c.

828{
829 const regmatch_t *match = mutt_prex_capture(PREX_IMAP_DATE, s);
830 if (!match)
831 return 0;
832
833 const regmatch_t *mday = &match[PREX_IMAP_DATE_MATCH_DAY];
834 const regmatch_t *mmonth = &match[PREX_IMAP_DATE_MATCH_MONTH];
835 const regmatch_t *myear = &match[PREX_IMAP_DATE_MATCH_YEAR];
836 const regmatch_t *mtime = &match[PREX_IMAP_DATE_MATCH_TIME];
837 const regmatch_t *mtz = &match[PREX_IMAP_DATE_MATCH_TZ];
838
839 struct tm tm = { 0 };
840
841 sscanf(s + mutt_regmatch_start(mday), " %d", &tm.tm_mday);
842 tm.tm_mon = mutt_date_check_month(s + mutt_regmatch_start(mmonth));
843 sscanf(s + mutt_regmatch_start(myear), "%d", &tm.tm_year);
844 tm.tm_year -= 1900;
845 sscanf(s + mutt_regmatch_start(mtime), "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
846
847 char direction;
848 int zhours, zminutes;
849 sscanf(s + mutt_regmatch_start(mtz), "%c%02d%02d", &direction, &zhours, &zminutes);
850 bool zoccident = (direction == '-');
851
852 return add_tz_offset(mutt_date_make_time(&tm, false), zoccident, zhours, zminutes);
853}
@ PREX_IMAP_DATE_MATCH_TIME
15-MAR-2020 [15:09:35] -0700
Definition: prex.h:166
@ PREX_IMAP_DATE_MATCH_YEAR
15-MAR-[2020] 15:09:35 -0700
Definition: prex.h:165
@ PREX_IMAP_DATE_MATCH_DAY
[ 4]-MAR-2020 15:09:35 -0700
Definition: prex.h:161
@ PREX_IMAP_DATE_MATCH_TZ
15-MAR-2020 15:09:35 [-0700]
Definition: prex.h:167
@ PREX_IMAP_DATE_MATCH_MONTH
15-[MAR]-2020 15:09:35 -0700
Definition: prex.h:164
@ PREX_IMAP_DATE
[16-MAR-2020 15:09:35 -0700]
Definition: prex.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_date_add_timeout()

time_t mutt_date_add_timeout ( time_t  now,
time_t  timeout 
)

Safely add a timeout to a given time_t value.

Parameters
nowTime now
timeoutTimeout in seconds
Return values
numUnix time to timeout

This will truncate instead of overflowing.

Definition at line 863 of file date.c.

864{
865 if (timeout < 0)
866 return now;
867
868 if ((TIME_T_MAX - now) < timeout)
869 return TIME_T_MAX;
870
871 return now + timeout;
872}
+ Here is the caller graph for this function:

◆ mutt_date_localtime()

struct tm mutt_date_localtime ( time_t  t)

Converts calendar time to a broken-down time structure expressed in user timezone.

Parameters
tTime
Return values
objBroken-down time representation

Definition at line 879 of file date.c.

880{
881 struct tm tm = { 0 };
882
883 struct tm *ret = localtime_r(&t, &tm);
884 if (!ret)
885 {
886 mutt_debug(LL_DEBUG1, "Could not convert time_t via localtime_r() to struct tm: time_t = %jd\n",
887 (intmax_t) t);
888 struct tm default_tm = { 0 }; // 1970-01-01 00:00:00
889 mktime(&default_tm); // update derived fields making tm into a valid tm.
890 tm = default_tm;
891 }
892 return tm;
893}
+ Here is the caller graph for this function:

◆ mutt_date_gmtime()

struct tm mutt_date_gmtime ( time_t  t)

Converts calendar time to a broken-down time structure expressed in UTC timezone.

Parameters
tTime
Return values
objBroken-down time representation

Definition at line 900 of file date.c.

901{
902 struct tm tm = { 0 };
903
904 struct tm *ret = gmtime_r(&t, &tm);
905 if (!ret)
906 {
907 mutt_debug(LL_DEBUG1, "Could not convert time_t via gmtime_r() to struct tm: time_t = %jd\n",
908 (intmax_t) t);
909 struct tm default_tm = { 0 }; // 1970-01-01 00:00:00
910 mktime(&default_tm); // update derived fields making tm into a valid tm.
911 tm = default_tm;
912 }
913 return tm;
914}
+ Here is the caller graph for this function:

◆ mutt_date_localtime_format()

size_t mutt_date_localtime_format ( char *  buf,
size_t  buflen,
const char *  format,
time_t  t 
)

Format localtime.

Parameters
bufBuffer to store formatted time
buflenBuffer size
formatFormat to apply
tTime to format
Return values
numNumber of Bytes added to buffer, excluding NUL byte

Definition at line 924 of file date.c.

925{
926 if (!buf || !format)
927 return 0;
928
929 struct tm tm = mutt_date_localtime(t);
930 return strftime(buf, buflen, format, &tm);
931}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_date_localtime_format_locale()

size_t mutt_date_localtime_format_locale ( char *  buf,
size_t  buflen,
const char *  format,
time_t  t,
locale_t  loc 
)

Format localtime using a given locale.

Parameters
bufBuffer to store formatted time
buflenBuffer size
formatFormat to apply
tTime to format
locLocale to use
Return values
numNumber of Bytes added to buffer, excluding NUL byte

Definition at line 942 of file date.c.

944{
945 if (!buf || !format)
946 return 0;
947
948 struct tm tm = mutt_date_localtime(t);
949 return strftime_l(buf, buflen, format, &tm, loc);
950}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_date_sleep_ms()

void mutt_date_sleep_ms ( size_t  ms)

Sleep for milliseconds.

Parameters
msNumber of milliseconds to sleep

Definition at line 956 of file date.c.

957{
958 const struct timespec sleep = {
959 .tv_sec = ms / 1000,
960 .tv_nsec = (ms % 1000) * 1000000UL,
961 };
962 nanosleep(&sleep, NULL);
963}
Time value with nanosecond precision.
Definition: file.h:50
time_t tv_sec
Number of seconds since the epoch.
Definition: file.h:51
+ Here is the caller graph for this function:

Variable Documentation

◆ Weekdays

const char* const Weekdays[]
static
Initial value:
= {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
}

Day of the week (abbreviated)

Definition at line 50 of file date.c.

◆ Months

const char* const Months[]
static
Initial value:
= {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
}

Months of the year (abbreviated)

Definition at line 57 of file date.c.

◆ TimeZones

const struct Tz TimeZones[]
static

Lookup table of Time Zones.

Note
Keep in alphabetical order

Definition at line 67 of file date.c.