NeoMutt  2024-12-12-14-g7b49f7
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 <locale.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.
 
void mutt_time_now (struct timespec *tp)
 Set the provided time field to the current time.
 
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 (struct Buffer *buf, 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
  • Richard Russon
  • Pietro Cerutti
  • Victor Fernandes
  • Reto Brunner
  • Dennis Schön
  • Rayford Shireman
  • Steinar H Gunderson
  • наб

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 140 of file date.c.

141{
142 struct tm lt = mutt_date_localtime(g);
143
144 int tz = (((lt.tm_hour - utc->tm_hour) * 60) + (lt.tm_min - utc->tm_min)) * 60;
145
146 int yday = (lt.tm_yday - utc->tm_yday);
147 if (yday != 0)
148 {
149 /* This code is optimized to negative timezones (West of Greenwich) */
150 if ((yday == -1) || /* UTC passed midnight before localtime */
151 (yday > 1)) /* UTC passed new year before localtime */
152 {
153 tz -= (24 * 60 * 60);
154 }
155 else
156 {
157 tz += (24 * 60 * 60);
158 }
159 }
160
161 return tz;
162}
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition: date.c:906
+ 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 172 of file date.c.

173{
174 if ((t != TIME_T_MAX) && (t != TIME_T_MIN))
175 return t + (w ? 1 : -1) * (((time_t) h * 3600) + ((time_t) m * 60));
176 else
177 return t;
178}
#define TIME_T_MAX
Definition: date.h:40
#define TIME_T_MIN
Definition: date.h:41
+ 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 187 of file date.c.

188{
189 for (size_t i = 0; i < mutt_array_size(TimeZones); i++)
190 {
191 if (mutt_istrn_equal(TimeZones[i].tzname, s, len))
192 return &TimeZones[i];
193 }
194 return NULL;
195}
#define mutt_array_size(x)
Definition: memory.h:38
static const struct Tz TimeZones[]
Lookup table of Time Zones.
Definition: date.c:77
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:453
+ 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 202 of file date.c.

203{
204 if (tm->tm_mon != 1)
205 return 0;
206
207 int y = tm->tm_year + 1900;
208 return ((y & 3) == 0) && (((y % 100) != 0) || ((y % 400) == 0));
209}
+ 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 219 of file date.c.

220{
221 /* Check we haven't overflowed the time (on 32-bit arches) */
222 if ((t == TIME_T_MAX) || (t == TIME_T_MIN))
223 return 0;
224
225 if (t == 0)
226 t = mutt_date_now();
227
228 struct tm tm = mutt_date_gmtime(t);
229 return compute_tz(t, &tm);
230}
static int compute_tz(time_t g, struct tm *utc)
Calculate the number of seconds east of UTC.
Definition: date.c:140
struct tm mutt_date_gmtime(time_t t)
Converts calendar time to a broken-down time structure expressed in UTC timezone.
Definition: date.c:927
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:456
+ 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 242 of file date.c.

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

311{
312 if (!tm)
313 return;
314
315 static const char DaysPerMonth[mutt_array_size(Months)] = {
316 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
317 };
318 int leap;
319
320 while (tm->tm_sec < 0)
321 {
322 tm->tm_sec += 60;
323 tm->tm_min--;
324 }
325 while (tm->tm_sec >= 60)
326 {
327 tm->tm_sec -= 60;
328 tm->tm_min++;
329 }
330 while (tm->tm_min < 0)
331 {
332 tm->tm_min += 60;
333 tm->tm_hour--;
334 }
335 while (tm->tm_min >= 60)
336 {
337 tm->tm_min -= 60;
338 tm->tm_hour++;
339 }
340 while (tm->tm_hour < 0)
341 {
342 tm->tm_hour += 24;
343 tm->tm_mday--;
344 }
345 while (tm->tm_hour >= 24)
346 {
347 tm->tm_hour -= 24;
348 tm->tm_mday++;
349 }
350 /* use loops on NNNdwmy user input values? */
351 while (tm->tm_mon < 0)
352 {
353 tm->tm_mon += 12;
354 tm->tm_year--;
355 }
356 while (tm->tm_mon >= 12)
357 {
358 tm->tm_mon -= 12;
359 tm->tm_year++;
360 }
361 while (tm->tm_mday <= 0)
362 {
363 if (tm->tm_mon)
364 {
365 tm->tm_mon--;
366 }
367 else
368 {
369 tm->tm_mon = 11;
370 tm->tm_year--;
371 }
372 tm->tm_mday += DaysPerMonth[tm->tm_mon] + is_leap_year_feb(tm);
373 }
374 while (tm->tm_mday > (DaysPerMonth[tm->tm_mon] + (leap = is_leap_year_feb(tm))))
375 {
376 tm->tm_mday -= DaysPerMonth[tm->tm_mon] + leap;
377 if (tm->tm_mon < 11)
378 {
379 tm->tm_mon++;
380 }
381 else
382 {
383 tm->tm_mon = 0;
384 tm->tm_year++;
385 }
386 }
387}
static int is_leap_year_feb(struct tm *tm)
Is a given February in a leap year.
Definition: date.c:202
+ 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 397 of file date.c.

398{
399 if (!buf)
400 return;
401
402 struct tm tm = { 0 };
403 int tz = 0;
404
405 time_t t = mutt_date_now();
406 if (local)
407 {
408 tm = mutt_date_localtime(t);
409 tz = mutt_date_local_tz(t);
410 }
411 else
412 {
413 tm = mutt_date_gmtime(t);
414 }
415
416 tz /= 60;
417
418 buf_add_printf(buf, "%s, %d %s %d %02d:%02d:%02d %+03d%02d", Weekdays[tm.tm_wday],
419 tm.tm_mday, Months[tm.tm_mon], tm.tm_year + 1900, tm.tm_hour,
420 tm.tm_min, tm.tm_sec, tz / 60, abs(tz) % 60);
421}
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:204
static const char *const Weekdays[]
Day of the week (abbreviated)
Definition: date.c:60
int mutt_date_local_tz(time_t t)
Calculate the local timezone in seconds east of UTC.
Definition: date.c:219
+ 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 432 of file date.c.

433{
434 if (!s)
435 return -1;
436
437 char buf[4] = { 0 };
438 memcpy(buf, s, 3);
439 uint32_t sv;
440 memcpy(&sv, buf, sizeof(sv));
441 for (int i = 0; i < mutt_array_size(Months); i++)
442 {
443 uint32_t mv;
444 memcpy(&mv, Months[i], sizeof(mv));
445 if (sv == mv)
446 return i;
447 }
448
449 return -1; /* error */
450}
+ 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 456 of file date.c.

457{
458 return mutt_date_now_ms() / 1000;
459}
uint64_t mutt_date_now_ms(void)
Return the number of milliseconds since the Unix epoch.
Definition: date.c:465
+ 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 465 of file date.c.

466{
467 struct timeval tv = { 0, 0 };
468 gettimeofday(&tv, NULL);
469 /* We assume that gettimeofday doesn't modify its first argument on failure.
470 * We also kind of assume that gettimeofday does not fail. */
471 return ((uint64_t) tv.tv_sec * 1000) + (tv.tv_usec / 1000);
472}
+ Here is the caller graph for this function:

◆ mutt_time_now()

void mutt_time_now ( struct timespec *  tp)

Set the provided time field to the current time.

Parameters
[out]tpField to set

Uses nanosecond precision if available, if not we fallback to microseconds.

Definition at line 480 of file date.c.

481{
482#ifdef HAVE_CLOCK_GETTIME
483 if (clock_gettime(CLOCK_REALTIME, tp) != 0)
484 mutt_perror("clock_gettime");
485#else
486 struct timeval tv = { 0, 0 };
487 if (gettimeofday(&tv, NULL) != 0)
488 mutt_perror("gettimeofday");
489 tp->tv_sec = tv.tv_sec;
490 tp->tv_nsec = tv.tv_usec * 1000;
491#endif
492}
#define mutt_perror(...)
Definition: logging2.h:93
+ 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 507 of file date.c.

508{
509 const char *ptr = str;
510 int v = 0;
511 while ((ptr < end) && (ptr < (str + 5)) && (*ptr >= '0') && (*ptr <= '9'))
512 {
513 v = (v * 10) + (*ptr - '0');
514 ptr++;
515 }
516 *val = v;
517 return ptr - str;
518}
+ 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 537 of file date.c.

538{
539 size_t len = strlen(s);
540
541 /* Skip over the weekday, if any. */
542 if ((len >= 5) && (s[4] == ' ') &&
543 (eqi4(s, "Mon,") || eqi4(s, "Tue,") || eqi4(s, "Wed,") ||
544 eqi4(s, "Thu,") || eqi4(s, "Fri,") || eqi4(s, "Sat,") || eqi4(s, "Sun,")))
545 {
546 s += 5;
547 len -= 5;
548 }
549
550 while ((len > 0) && (*s == ' '))
551 {
552 s++;
553 len--;
554 }
555
556 if ((len == 0) || (*s < '0') || (*s > '9'))
557 return -1;
558
559 struct tm tm = { 0 };
560
561 /* Day */
562 int mday_len = parse_small_uint(s, s + len, &tm.tm_mday);
563 if ((mday_len == 0) || (mday_len > 2) || (tm.tm_mday > 31))
564 return -1;
565 s += mday_len;
566 len -= mday_len;
567
568 if ((len == 0) || (*s != ' '))
569 return -1;
570 s++;
571 len--;
572
573 /* Month */
574 if (len < 3)
575 return -1;
576 tm.tm_mon = mutt_date_check_month(s);
577 if (tm.tm_mon == -1)
578 return -1;
579 s += 3;
580 len -= 3;
581
582 if ((len == 0) || (*s != ' '))
583 return -1;
584 s++;
585 len--;
586
587 /* Year */
588 int year_len = parse_small_uint(s, s + len, &tm.tm_year);
589 if ((year_len != 2) && (year_len != 4))
590 return -1;
591 if (tm.tm_year < 50)
592 tm.tm_year += 100;
593 else if (tm.tm_year >= 1900)
594 tm.tm_year -= 1900;
595 s += year_len;
596 len -= year_len;
597
598 if ((len == 0) || (*s != ' '))
599 return -1;
600 s++;
601 len--;
602
603 /* Hour */
604 if ((len < 3) || (s[0] < '0') || (s[0] > '2') || (s[1] < '0') ||
605 (s[1] > '9') || (s[2] != ':'))
606 {
607 return -1;
608 }
609 tm.tm_hour = ((s[0] - '0') * 10) + (s[1] - '0');
610 if (tm.tm_hour > 23)
611 return -1;
612 s += 3;
613 len -= 3;
614
615 /* Minute */
616 if ((len < 2) || (s[0] < '0') || (s[0] > '5') || (s[1] < '0') || (s[1] > '9'))
617 return -1;
618 tm.tm_min = ((s[0] - '0') * 10) + (s[1] - '0');
619 if (tm.tm_min > 59)
620 return -1;
621 s += 2;
622 len -= 2;
623
624 /* Second (optional) */
625 if ((len > 0) && (s[0] == ':'))
626 {
627 s++;
628 len--;
629 if ((len < 2) || (s[0] < '0') || (s[0] > '5') || (s[1] < '0') || (s[1] > '9'))
630 return -1;
631 tm.tm_sec = ((s[0] - '0') * 10) + (s[1] - '0');
632 if (tm.tm_sec > 60)
633 return -1;
634 s += 2;
635 len -= 2;
636 }
637
638 while ((len > 0) && (*s == ' '))
639 {
640 s++;
641 len--;
642 }
643
644 /* Strip optional time zone comment and white space from the end
645 * (this is the only one that is very common) */
646 while ((len > 0) && (s[len - 1] == ' '))
647 len--;
648 if ((len >= 2) && (s[len - 1] == ')'))
649 {
650 for (int i = len - 1; i-- > 0;)
651 {
652 if (s[i] == '(')
653 {
654 len = i;
655 break;
656 }
657 if (!isalpha(s[i]) && (s[i] != ' '))
658 return -1; /* give up more complex comment parsing */
659 }
660 }
661 while ((len > 0) && (s[len - 1] == ' '))
662 len--;
663
664 /* Time zone (optional) */
665 int zhours = 0;
666 int zminutes = 0;
667 bool zoccident = false;
668 if (len > 0)
669 {
670 if ((len == 5) && ((s[0] == '+') || (s[0] == '-')) && (s[1] >= '0') &&
671 (s[1] <= '9') && (s[2] >= '0') && (s[2] <= '9') && (s[3] >= '0') &&
672 (s[3] <= '9') && (s[4] >= '0') && (s[4] <= '9'))
673 {
674 zoccident = (s[0] == '-');
675 zhours = ((s[1] - '0') * 10) + (s[2] - '0');
676 zminutes = ((s[3] - '0') * 10) + (s[4] - '0');
677 }
678 else
679 {
680 for (int i = 0; i < len; ++i)
681 {
682 if (!isalpha(s[i]))
683 return -1;
684 }
685 const struct Tz *tz = find_tz(s, len);
686 if (tz)
687 {
688 zhours = tz->zhours;
689 zminutes = tz->zminutes;
690 zoccident = tz->zoccident;
691 }
692 }
693 }
694
695 if (tz_out)
696 {
697 tz_out->zhours = zhours;
698 tz_out->zminutes = zminutes;
699 tz_out->zoccident = zoccident;
700 }
701
703}
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:242
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:507
int mutt_date_check_month(const char *s)
Is the string a valid month name.
Definition: date.c:432
static const struct Tz * find_tz(const char *s, size_t len)
Look up a timezone.
Definition: date.c:187
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:172
List of recognised Timezones.
Definition: date.h:50
unsigned char zminutes
Minutes away from UTC.
Definition: date.h:53
bool zoccident
True if west of UTC, False if East.
Definition: date.h:54
unsigned char zhours
Hours away from UTC.
Definition: date.h:52
+ 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, or -1 on failure

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 716 of file date.c.

717{
718 if (!s)
719 return -1;
720
721 const time_t strict_t = mutt_date_parse_rfc5322_strict(s, tz_out);
722 if (strict_t != -1)
723 return strict_t;
724
725 const regmatch_t *match = mutt_prex_capture(PREX_RFC5322_DATE_LAX, s);
726 if (!match)
727 {
728 mutt_debug(LL_DEBUG1, "Could not parse date: <%s>\n", s);
729 return -1;
730 }
731 mutt_debug(LL_DEBUG2, "Fallback regex for date: <%s>\n", s);
732
733 struct tm tm = { 0 };
734
735 // clang-format off
736 const regmatch_t *mday = &match[PREX_RFC5322_DATE_LAX_MATCH_DAY];
737 const regmatch_t *mmonth = &match[PREX_RFC5322_DATE_LAX_MATCH_MONTH];
738 const regmatch_t *myear = &match[PREX_RFC5322_DATE_LAX_MATCH_YEAR];
739 const regmatch_t *mhour = &match[PREX_RFC5322_DATE_LAX_MATCH_HOUR];
740 const regmatch_t *mminute = &match[PREX_RFC5322_DATE_LAX_MATCH_MINUTE];
741 const regmatch_t *msecond = &match[PREX_RFC5322_DATE_LAX_MATCH_SECOND];
742 const regmatch_t *mtz = &match[PREX_RFC5322_DATE_LAX_MATCH_TZ];
743 const regmatch_t *mtzobs = &match[PREX_RFC5322_DATE_LAX_MATCH_TZ_OBS];
744 // clang-format on
745
746 /* Day */
747 sscanf(s + mutt_regmatch_start(mday), "%d", &tm.tm_mday);
748 if (tm.tm_mday > 31)
749 return -1;
750
751 /* Month */
752 tm.tm_mon = mutt_date_check_month(s + mutt_regmatch_start(mmonth));
753
754 /* Year */
755 sscanf(s + mutt_regmatch_start(myear), "%d", &tm.tm_year);
756 if (tm.tm_year < 50)
757 tm.tm_year += 100;
758 else if (tm.tm_year >= 1900)
759 tm.tm_year -= 1900;
760
761 /* Time */
762 int hour = 0, min = 0, sec = 0;
763 sscanf(s + mutt_regmatch_start(mhour), "%d", &hour);
764 sscanf(s + mutt_regmatch_start(mminute), "%d", &min);
765 if (mutt_regmatch_start(msecond) != -1)
766 sscanf(s + mutt_regmatch_start(msecond), "%d", &sec);
767 if ((hour > 23) || (min > 59) || (sec > 60))
768 return -1;
769 tm.tm_hour = hour;
770 tm.tm_min = min;
771 tm.tm_sec = sec;
772
773 /* Time zone */
774 int zhours = 0;
775 int zminutes = 0;
776 bool zoccident = false;
777 if (mutt_regmatch_start(mtz) != -1)
778 {
779 char direction = '\0';
780 sscanf(s + mutt_regmatch_start(mtz), "%c%02d%02d", &direction, &zhours, &zminutes);
781 zoccident = (direction == '-');
782 }
783 else if (mutt_regmatch_start(mtzobs) != -1)
784 {
785 const struct Tz *tz = find_tz(s + mutt_regmatch_start(mtzobs),
786 mutt_regmatch_len(mtzobs));
787 if (tz)
788 {
789 zhours = tz->zhours;
790 zminutes = tz->zminutes;
791 zoccident = tz->zoccident;
792 }
793 }
794
795 if (tz_out)
796 {
797 tz_out->zhours = zhours;
798 tz_out->zminutes = zminutes;
799 tz_out->zoccident = zoccident;
800 }
801
803}
#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:537
regmatch_t * mutt_prex_capture(enum Prex which, const char *str)
Match a precompiled regex against a string.
Definition: prex.c:298
@ 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:147
@ PREX_RFC5322_DATE_LAX_MATCH_TZ
Tue, 3 Mar 2020 14:32:55 [+0200]
Definition: prex.h:150
@ PREX_RFC5322_DATE_LAX_MATCH_YEAR
Tue, 3 Mar [2020] 14:32:55 +0200
Definition: prex.h:139
@ PREX_RFC5322_DATE_LAX_MATCH_HOUR
Tue, 3 Mar 2020 [14]:32:55 +0200
Definition: prex.h:141
@ PREX_RFC5322_DATE_LAX_MATCH_MINUTE
Tue, 3 Mar 2020 14:[32]:55 +0200
Definition: prex.h:143
@ PREX_RFC5322_DATE_LAX_MATCH_TZ_OBS
Tue, 3 Mar 2020 14:32:55[UT]
Definition: prex.h:151
@ PREX_RFC5322_DATE_LAX_MATCH_MONTH
Tue, 3 [Jan] 2020 14:32:55 +0200
Definition: prex.h:137
@ PREX_RFC5322_DATE_LAX_MATCH_DAY
Tue, [3] Mar 2020 14:32:55 +0200
Definition: prex.h:135
static size_t mutt_regmatch_len(const regmatch_t *match)
Return the length of a match.
Definition: regex3.h:77
static regoff_t mutt_regmatch_start(const regmatch_t *match)
Return the start of a match.
Definition: regex3.h:57
+ 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 ( struct Buffer buf,
time_t  timestamp 
)

Format date in IMAP style: DD-MMM-YYYY HH:MM:SS +ZZzz.

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

Definition at line 811 of file date.c.

812{
813 if (!buf)
814 return -1;
815
816 struct tm tm = mutt_date_localtime(timestamp);
818
819 tz /= 60;
820
821 return buf_printf(buf, "%02d-%s-%d %02d:%02d:%02d %+03d%02d", tm.tm_mday,
822 Months[tm.tm_mon], tm.tm_year + 1900, tm.tm_hour, tm.tm_min,
823 tm.tm_sec, tz / 60, abs(tz) % 60);
824}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:161
static const char * timestamp(time_t stamp)
Create a YYYY-MM-DD HH:MM:SS timestamp.
Definition: logging.c:78
+ 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 837 of file date.c.

838{
839 if (!buf)
840 return -1;
841
842 struct tm tm = mutt_date_gmtime(timestamp);
843 return snprintf(buf, buflen, "%s, %d %s %d %02d:%02d:%02d UTC",
844 Weekdays[tm.tm_wday], tm.tm_mday, Months[tm.tm_mon],
845 tm.tm_year + 1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
846}
+ 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 854 of file date.c.

855{
856 const regmatch_t *match = mutt_prex_capture(PREX_IMAP_DATE, s);
857 if (!match)
858 return 0;
859
860 const regmatch_t *mday = &match[PREX_IMAP_DATE_MATCH_DAY];
861 const regmatch_t *mmonth = &match[PREX_IMAP_DATE_MATCH_MONTH];
862 const regmatch_t *myear = &match[PREX_IMAP_DATE_MATCH_YEAR];
863 const regmatch_t *mtime = &match[PREX_IMAP_DATE_MATCH_TIME];
864 const regmatch_t *mtz = &match[PREX_IMAP_DATE_MATCH_TZ];
865
866 struct tm tm = { 0 };
867
868 sscanf(s + mutt_regmatch_start(mday), " %d", &tm.tm_mday);
869 tm.tm_mon = mutt_date_check_month(s + mutt_regmatch_start(mmonth));
870 sscanf(s + mutt_regmatch_start(myear), "%d", &tm.tm_year);
871 tm.tm_year -= 1900;
872 sscanf(s + mutt_regmatch_start(mtime), "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
873
874 char direction = '\0';
875 int zhours = 0, zminutes = 0;
876 sscanf(s + mutt_regmatch_start(mtz), "%c%02d%02d", &direction, &zhours, &zminutes);
877 bool zoccident = (direction == '-');
878
879 return add_tz_offset(mutt_date_make_time(&tm, false), zoccident, zhours, zminutes);
880}
@ PREX_IMAP_DATE_MATCH_TIME
15-MAR-2020 [15:09:35] -0700
Definition: prex.h:168
@ PREX_IMAP_DATE_MATCH_YEAR
15-MAR-[2020] 15:09:35 -0700
Definition: prex.h:167
@ PREX_IMAP_DATE_MATCH_DAY
[ 4]-MAR-2020 15:09:35 -0700
Definition: prex.h:163
@ PREX_IMAP_DATE_MATCH_TZ
15-MAR-2020 15:09:35 [-0700]
Definition: prex.h:169
@ PREX_IMAP_DATE_MATCH_MONTH
15-[MAR]-2020 15:09:35 -0700
Definition: prex.h:166
@ PREX_IMAP_DATE
[16-MAR-2020 15:09:35 -0700]
Definition: prex.h:39
+ 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 890 of file date.c.

891{
892 if (timeout < 0)
893 return now;
894
895 if ((TIME_T_MAX - now) < timeout)
896 return TIME_T_MAX;
897
898 return now + timeout;
899}
+ 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 906 of file date.c.

907{
908 struct tm tm = { 0 };
909
910 struct tm *ret = localtime_r(&t, &tm);
911 if (!ret)
912 {
913 mutt_debug(LL_DEBUG1, "Could not convert time_t via localtime_r() to struct tm: time_t = %jd\n",
914 (intmax_t) t);
915 struct tm default_tm = { 0 }; // 1970-01-01 00:00:00
916 mktime(&default_tm); // update derived fields making tm into a valid tm.
917 tm = default_tm;
918 }
919 return tm;
920}
+ 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 927 of file date.c.

928{
929 struct tm tm = { 0 };
930
931 struct tm *ret = gmtime_r(&t, &tm);
932 if (!ret)
933 {
934 mutt_debug(LL_DEBUG1, "Could not convert time_t via gmtime_r() to struct tm: time_t = %jd\n",
935 (intmax_t) t);
936 struct tm default_tm = { 0 }; // 1970-01-01 00:00:00
937 mktime(&default_tm); // update derived fields making tm into a valid tm.
938 tm = default_tm;
939 }
940 return tm;
941}
+ 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 951 of file date.c.

952{
953 if (!buf || !format)
954 return 0;
955
956 struct tm tm = mutt_date_localtime(t);
957 return strftime(buf, buflen, format, &tm);
958}
+ 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 969 of file date.c.

971{
972 if (!buf || !format)
973 return 0;
974
975 struct tm tm = mutt_date_localtime(t);
976 return strftime_l(buf, buflen, format, &tm, loc);
977}
+ 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 983 of file date.c.

984{
985 const struct timespec sleep = {
986 .tv_sec = ms / 1000,
987 .tv_nsec = (ms % 1000) * 1000000UL,
988 };
989 nanosleep(&sleep, NULL);
990}
+ 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 60 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 67 of file date.c.

◆ TimeZones

const struct Tz TimeZones[]
static

Lookup table of Time Zones.

Note
Keep in alphabetical order

Definition at line 77 of file date.c.