NetSurf
time.c
Go to the documentation of this file.
1/*
2 * Copyright 2007 Rob Kendrick <rjek@netsurf-browser.org>
3 * Copyright 2004-2007 James Bursa <bursa@users.sourceforge.net>
4 * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
5 * Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
6 * Copyright 2004 John Tytgat <joty@netsurf-browser.org>
7 *
8 * This file is part of NetSurf, http://www.netsurf-browser.org/
9 *
10 * NetSurf is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2 of the License.
13 *
14 * NetSurf is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23/**
24 * \file utils/time.c
25 * \brief Implementation of time operations.
26 */
27
28#include <stdio.h>
29#include <stdint.h>
30#include <stdbool.h>
31
32#ifdef WITH_CURL
33#include <curl/curl.h>
34#endif
35
36#include "utils/ascii.h"
37#include "utils/errors.h"
38#include "utils/time.h"
39
40
41/**
42 * Weekdays
43 *
44 * Must be calender order.
45 */
55};
56/**
57 * Months
58 *
59 * Must be calender order.
60 */
75};
76
77
78/**
79 * Array of short weekday names.
80 */
81static const char * const weekdays_short[NSC_TIME_WEEKDAY__COUNT] = {
82 [NSC_TIME_WEEKDAY_SUN] = "Sun",
83 [NSC_TIME_WEEKDAY_MON] = "Mon",
84 [NSC_TIME_WEEKDAY_TUE] = "Tue",
85 [NSC_TIME_WEEKDAY_WED] = "Wed",
86 [NSC_TIME_WEEKDAY_THU] = "Thu",
87 [NSC_TIME_WEEKDAY_FRI] = "Fri",
88 [NSC_TIME_WEEKDAY_SAT] = "Sat"
89};
90/**
91 * Array of month names.
92 */
93static const char * const months[NSC_TIME_MONTH__COUNT] = {
94 [NSC_TIME_MONTH_JAN] = "Jan",
95 [NSC_TIME_MONTH_FEB] = "Feb",
96 [NSC_TIME_MONTH_MAR] = "Mar",
97 [NSC_TIME_MONTH_APR] = "Apr",
98 [NSC_TIME_MONTH_MAY] = "May",
99 [NSC_TIME_MONTH_JUN] = "Jun",
100 [NSC_TIME_MONTH_JUL] = "Jul",
101 [NSC_TIME_MONTH_AUG] = "Aug",
102 [NSC_TIME_MONTH_SEP] = "Sep",
103 [NSC_TIME_MONTH_OCT] = "Oct",
104 [NSC_TIME_MONTH_NOV] = "Nov",
105 [NSC_TIME_MONTH_DEC] = "Dec"
106};
107
108
109/* exported interface documented in utils/time.h */
110const char *rfc1123_date(time_t t)
111{
112 static char ret[31];
113
114 struct tm *tm = gmtime(&t);
115
116 snprintf(ret, sizeof ret, "%s, %02d %s %d %02d:%02d:%02d GMT",
117 weekdays_short[tm->tm_wday], tm->tm_mday,
118 months[tm->tm_mon], tm->tm_year + 1900,
119 tm->tm_hour, tm->tm_min, tm->tm_sec);
120
121 return ret;
122}
123
124
125/* exported function documented in utils/time.h */
126int nsc_sntimet(char *str, size_t size, time_t *timep)
127{
128#ifndef HAVE_STRFTIME
129 long long val;
130 val = (long long)*timep;
131
132 return snprintf(str, size, "%lld", val);
133#else
134 struct tm *ltm;
135
136 ltm = localtime(timep);
137 if (ltm == NULL) {
138 return -1;
139 }
140
141 return strftime(str, size, "%s", ltm);
142#endif
143}
144
145
146/* exported function documented in utils/time.h */
147nserror nsc_snptimet(const char *str, size_t size, time_t *timep)
148{
149 time_t time_out;
150
151#ifndef HAVE_STRPTIME
152 char *rstr;
153
154 if (size < 1) {
156 }
157
158 errno = 0;
159 time_out = (time_t)strtoll(str, &rstr, 10);
160
161 /* The conversion may have a range faliure or no digits were found */
162 if ((errno != 0) || (rstr == str)) {
164 }
165
166#else
167 struct tm ltm;
168
169 if (size < 1) {
171 }
172
173 if (strptime(str, "%s", &ltm) == NULL) {
175 }
176
177 time_out = mktime(&ltm);
178
179#endif
180 *timep = time_out;
181
182 return NSERROR_OK;
183}
184
185
186#ifndef WITH_CURL
187
188
189/**
190 * Array of long weekday names.
191 */
192static const char * const weekdays_long[NSC_TIME_WEEKDAY__COUNT] = {
193 [NSC_TIME_WEEKDAY_SUN] = "Sunday",
194 [NSC_TIME_WEEKDAY_MON] = "Monday",
195 [NSC_TIME_WEEKDAY_TUE] = "Tuesday",
196 [NSC_TIME_WEEKDAY_WED] = "Wednesday",
197 [NSC_TIME_WEEKDAY_THU] = "Thursday",
198 [NSC_TIME_WEEKDAY_FRI] = "Friday",
199 [NSC_TIME_WEEKDAY_SAT] = "Saturday"
200};
201
202/**
203 * Timezone offsets in mins
204 *
205 * Order doesn't matter.
206 */
208 /* Timezones */
236
237 /* Daylight saving modified timezones */
253
254 /* Military timezones */
280};
281
282/**
283 * List of timezones.
284 *
285 * The order here is the order they appear in the `timezone_mins` and
286 * `timezones` arrays. So there is value in putting the most common
287 * timezones first.
288 */
290 /** "GMT" first since its the only one I've seen in the wild. -- tlsa */
360
361/**
362 * Array of minute offsets for timezones.
363 */
364static const int16_t timezone_mins[NSC_TIME_ZONE__COUNT] = {
432};
433
434/**
435 * Array of timezone names. Order does not matter.
436 */
437static const char * const timezones[NSC_TIME_ZONE__COUNT] = {
438 [NSC_TIME_ZONE_IDLE] = "IDLE",
439 [NSC_TIME_ZONE_NZST] = "NZST",
440 [NSC_TIME_ZONE_NZT] = "NZT",
441 [NSC_TIME_ZONE_EAST] = "EAST",
442 [NSC_TIME_ZONE_GST] = "GST",
443 [NSC_TIME_ZONE_JST] = "JST",
444 [NSC_TIME_ZONE_CCT] = "CCT",
445 [NSC_TIME_ZONE_WAST] = "WAST",
446 [NSC_TIME_ZONE_EET] = "EET",
447 [NSC_TIME_ZONE_CET] = "CET",
448 [NSC_TIME_ZONE_FWT] = "FWT",
449 [NSC_TIME_ZONE_MET] = "MET",
450 [NSC_TIME_ZONE_MEWT] = "MEWT",
451 [NSC_TIME_ZONE_GMT] = "GMT",
452 [NSC_TIME_ZONE_UTC] = "UTC",
453 [NSC_TIME_ZONE_WET] = "WET",
454 [NSC_TIME_ZONE_WAT] = "WAT",
455 [NSC_TIME_ZONE_AST] = "AST",
456 [NSC_TIME_ZONE_EST] = "EST",
457 [NSC_TIME_ZONE_CST] = "CST",
458 [NSC_TIME_ZONE_MST] = "MST",
459 [NSC_TIME_ZONE_PST] = "PST",
460 [NSC_TIME_ZONE_YST] = "YST",
461 [NSC_TIME_ZONE_AHST] = "AHST",
462 [NSC_TIME_ZONE_CAT] = "CAT",
463 [NSC_TIME_ZONE_HST] = "HST",
464 [NSC_TIME_ZONE_IDLW] = "IDLW",
465 [NSC_TIME_ZONE_NZDT] = "NZDT",
466 [NSC_TIME_ZONE_EADT] = "EADT",
467 [NSC_TIME_ZONE_WADT] = "WADT",
468 [NSC_TIME_ZONE_CEST] = "CEST",
469 [NSC_TIME_ZONE_FST] = "FST",
470 [NSC_TIME_ZONE_MEST] = "MEST",
471 [NSC_TIME_ZONE_MESZ] = "MESZ",
472 [NSC_TIME_ZONE_BST] = "BST",
473 [NSC_TIME_ZONE_ADT] = "ADT",
474 [NSC_TIME_ZONE_EDT] = "EDT",
475 [NSC_TIME_ZONE_CDT] = "CDT",
476 [NSC_TIME_ZONE_MDT] = "MDT",
477 [NSC_TIME_ZONE_PDT] = "PDT",
478 [NSC_TIME_ZONE_YDT] = "YDT",
479 [NSC_TIME_ZONE_HDT] = "HDT",
480 [NSC_TIME_ZONE_Y] = "Y",
481 [NSC_TIME_ZONE_X] = "X",
482 [NSC_TIME_ZONE_W] = "W",
483 [NSC_TIME_ZONE_V] = "V",
484 [NSC_TIME_ZONE_U] = "U",
485 [NSC_TIME_ZONE_T] = "T",
486 [NSC_TIME_ZONE_S] = "S",
487 [NSC_TIME_ZONE_R] = "R",
488 [NSC_TIME_ZONE_Q] = "Q",
489 [NSC_TIME_ZONE_P] = "P",
490 [NSC_TIME_ZONE_O] = "O",
491 [NSC_TIME_ZONE_N] = "N",
492 [NSC_TIME_ZONE_Z] = "Z",
493 [NSC_TIME_ZONE_A] = "A",
494 [NSC_TIME_ZONE_B] = "B",
495 [NSC_TIME_ZONE_C] = "C",
496 [NSC_TIME_ZONE_D] = "D",
497 [NSC_TIME_ZONE_E] = "E",
498 [NSC_TIME_ZONE_F] = "F",
499 [NSC_TIME_ZONE_G] = "G",
500 [NSC_TIME_ZONE_H] = "H",
501 [NSC_TIME_ZONE_I] = "I",
502 [NSC_TIME_ZONE_K] = "K",
503 [NSC_TIME_ZONE_L] = "L",
504 [NSC_TIME_ZONE_M] = "M"
505};
506
507/**
508 * Flags for tracking the components of a date that have been parsed.
509 */
537
538/**
539 * Context for date parsing.
540 */
542 char prev; /**< Used for handling neumenrical timezone */
543 uint8_t secs;
544 uint8_t mins;
545 uint8_t hours;
546 uint8_t day;
547 uint8_t month;
548 uint16_t years;
550};
551
552
553/**
554 * Helper for testing whether any of the flags in mask are set.
555 *
556 * \param[in] flags Flags to to check.
557 * \param[in] mask The set of flags to check for in `flags`.
558 * \return true iff any flags in `mask` are set in `flags`, else false.
559 */
560static bool flags_chk(
561 enum nsc_date_component_flags flags,
562 enum nsc_date_component_flags mask)
563{
564 return flags & mask;
565}
566
567/**
568 * Helper for testing whether all of the flags in mask are set.
569 *
570 * \param[in] flags Flags to to check.
571 * \param[in] mask The set of flags to check for in `flags`.
572 * \return true iff all flags in `mask` are set in `flags`, else false.
573 */
574static bool flags_chk_all(
575 enum nsc_date_component_flags flags,
576 enum nsc_date_component_flags mask)
577{
578 return (flags & mask) == mask;
579}
580
581
582/**
583 * Test for a weekday name in a string (case insensitive).
584 *
585 * \param[in] str String to parse a weekday name in.
586 * \param[in] len Number of consecutive alphabetical characters.
587 * \param[in,out] flags Flags indicating which date components have been
588 * found in `str` already. If a weekday component
589 * is found, the weekday flag is set.
590 * \return true iff weekday component is found, else false.
591 */
592static inline bool time__parse_weekday(
593 const char *str,
594 size_t len,
595 enum nsc_date_component_flags *flags)
596{
597 const char * const *names = (len == 3) ?
599
601 return false;
602 }
603
604 for (uint32_t i = 0; i < NSC_TIME_WEEKDAY__COUNT; i++) {
605 if (ascii_strings_count_equal_caseless(names[i], str) == len) {
607 return true;
608 }
609 }
610
611 return false;
612}
613
614
615/**
616 * Attempt to parse a month name in a string (case insensitive).
617 *
618 * \param[in] str String to parse a month name in.
619 * \param[in] len Number of consecutive alphabetical characters.
620 * \param[in,out] flags Flags indicating which date components have been
621 * found in `str` already. If a month component
622 * is found, the month flag is set.
623 * \param[in,out] ctx Current date parsing context. If month component
624 * is found, the context's month value is set.
625 * \return true iff month name component is found, else false.
626 */
627static inline bool time__parse_month(
628 const char *str,
629 size_t len,
630 enum nsc_date_component_flags *flags,
631 struct nsc_date_parse_ctx *ctx)
632{
634 return false;
635 }
636
637 for (uint32_t i = 0; i < NSC_TIME_MONTH__COUNT; i++) {
638 if (ascii_strings_count_equal_caseless(months[i], str) == len) {
640 ctx->month = i;
641 return true;
642 }
643 }
644
645 return false;
646}
647
648
649/**
650 * Attempt to parse a timezone name in a string (case insensitive).
651 *
652 * \param[in] str String to parse a timezone name in.
653 * \param[in] len Number of consecutive alphabetical characters.
654 * \param[in,out] flags Flags indicating which date components have been
655 * found in `str` already. If a timezone component
656 * is found, the timezone flag is set.
657 * \param[in,out] ctx Current date parsing context. If timezone component
658 * is found, the context's timezone value is set.
659 * \return true iff timezone name component is found, else false.
660 */
661static inline bool time__parse_timezone(
662 const char *str,
663 size_t len,
664 enum nsc_date_component_flags *flags,
665 struct nsc_date_parse_ctx *ctx)
666{
668 return false;
669 }
670
671 for (uint32_t i = 0; i < NSC_TIME_ZONE__COUNT; i++) {
673 timezones[i], str) == len) {
676 return true;
677 }
678 }
679
680 return false;
681}
682
683
684/**
685 * Attempt to parse an "hh:mm:ss" time from a string.
686 *
687 * \param[in] str String to parse a time in.
688 * \param[in,out] len The number of characters until the first non-digit.
689 * Iff a time component is found, updated to the number
690 * of comsumend characters.
691 * \param[in,out] flags Flags indicating which date components have been
692 * found in `str` already. If a time component
693 * is found, the hours, mins and secs flags are set.
694 * \param[in,out] ctx Current date parsing context. If time component
695 * is found, the context's time values are set.
696 * \return true iff time component is found, else false.
697 */
698static inline bool time__parse_hh_mm_ss(
699 const char *str,
700 size_t *len,
701 enum nsc_date_component_flags *flags,
702 struct nsc_date_parse_ctx *ctx)
703{
704 size_t l;
705
706 if (*len != 2 || flags_chk(*flags, NSC_COMPONENT_FLAGS__HAVE_HHMMSS)) {
707 return false;
708 }
709
710 l = *len + ascii_count_digit_or_colon(str + *len);
711 if (l == 8) {
712 int h, m, s, count;
713 count = sscanf(str, "%02d:%02d:%02d", &h, &m, &s);
714 if (count == 3) {
715 ctx->hours = h;
716 ctx->mins = m;
717 ctx->secs = s;
719 *len = l;
720 return true;
721 }
722 } else if (l == 5) {
723 int h, m, count;
724 count = sscanf(str, "%02d:%02d", &h, &m);
725 if (count == 2) {
726 ctx->hours = h;
727 ctx->mins = m;
728 ctx->secs = 0;
730 *len = l;
731 return true;
732 }
733 }
734
735 return false;
736}
737
738
739/**
740 * Attempt to parse a number from a date string.
741 *
742 * How the number is treated depends on various things:
743 *
744 * - its character length,
745 * - its value,
746 * - which date components have already been parsed
747 *
748 * \param[in] str String to parse a time in.
749 * \param[in] len The number of characters until the first non-digit.
750 * \param[in,out] flags Flags indicating which date components have been
751 * found in `str` already. If any component is found,
752 * their flags are set.
753 * \param[in,out] ctx Current date parsing context. If any component
754 * is found, the appropriate context values are set.
755 * \return true iff a component is found, else false.
756 */
757static inline bool time__parse_number(
758 const char *str,
759 size_t len,
760 enum nsc_date_component_flags *flags,
761 struct nsc_date_parse_ctx *ctx)
762{
763 int value;
764
765 if (len != ascii_string_to_int(str, &value)) {
766 return false;
767 }
768
769 switch (len) {
770 case 8:
772 ctx->years = value / 10000;
773 ctx->month = (value % 10000) / 100 - 1;
774 ctx->day = value % 100 - 1;
776 return true;
777 }
778 break;
779
780 case 4:
782 if (ascii_is_sign(ctx->prev) && value <= 1400) {
784 value / 100 * 60 +
785 value % 100;
786 if (ctx->prev == '+') {
787 ctx->timezone_offset_mins *= -1;
788 }
790 return true;
791 }
792 }
794 ctx->years = value;
796 return true;
797 }
798 break;
799
800 case 2:
801 case 1:
803 value > 0 && value <= 31) {
804 ctx->day = value - 1;
806 return true;
807 }
809 ctx->years = (value > 70) ?
810 value + 1900 :
811 value + 2000;
813 return true;
814 }
815 break;
816
817 default:
818 break;
819 }
820
821 return false;
822}
823
824/**
825 * Get number of leap days up until end of given year.
826 *
827 * \param[in] year Year to count leap years up to.
828 * \return Number of leap days up to end of `year`.
829 */
830static inline int time__get_leap_days(int year)
831{
832 return (year / 4) - (year / 100) + (year / 400);
833}
834
835
836/**
837 * Helper to convert a date string context to a time_t.
838 *
839 * \param[in] ctx Current date parsing context.
840 * \param[in] flags Flags indicating which date components have been set.
841 * \param[out] time Returns the number of seconds since 1 Jan 1970 00:00 UTC.
842 * \return NSERROR_OK on success, appropriate error otherwise.
843 */
845 const struct nsc_date_parse_ctx *ctx,
846 enum nsc_date_component_flags flags,
847 time_t *time)
848{
849 enum {
850 NSC_MONTH_DAYS_JAN = 31,
851 NSC_MONTH_DAYS_FEB = 28, /**< Leap years handled separatly */
852 NSC_MONTH_DAYS_MAR = 31,
853 NSC_MONTH_DAYS_APR = 30,
854 NSC_MONTH_DAYS_MAY = 31,
855 NSC_MONTH_DAYS_JUN = 30,
856 NSC_MONTH_DAYS_JUL = 31,
857 NSC_MONTH_DAYS_AUG = 31,
858 NSC_MONTH_DAYS_SEP = 30,
859 NSC_MONTH_DAYS_OCT = 31,
860 NSC_MONTH_DAYS_NOV = 30,
861 NSC_MONTH_DAYS_DEC = 31
862 };
863 enum {
864 NSC_MONTH_OFF_JAN = 0,
865 NSC_MONTH_OFF_FEB = NSC_MONTH_OFF_JAN + NSC_MONTH_DAYS_JAN,
866 NSC_MONTH_OFF_MAR = NSC_MONTH_OFF_FEB + NSC_MONTH_DAYS_FEB,
867 NSC_MONTH_OFF_APR = NSC_MONTH_OFF_MAR + NSC_MONTH_DAYS_MAR,
868 NSC_MONTH_OFF_MAY = NSC_MONTH_OFF_APR + NSC_MONTH_DAYS_APR,
869 NSC_MONTH_OFF_JUN = NSC_MONTH_OFF_MAY + NSC_MONTH_DAYS_MAY,
870 NSC_MONTH_OFF_JUL = NSC_MONTH_OFF_JUN + NSC_MONTH_DAYS_JUN,
871 NSC_MONTH_OFF_AUG = NSC_MONTH_OFF_JUL + NSC_MONTH_DAYS_JUL,
872 NSC_MONTH_OFF_SEP = NSC_MONTH_OFF_AUG + NSC_MONTH_DAYS_AUG,
873 NSC_MONTH_OFF_OCT = NSC_MONTH_OFF_SEP + NSC_MONTH_DAYS_SEP,
874 NSC_MONTH_OFF_NOV = NSC_MONTH_OFF_OCT + NSC_MONTH_DAYS_OCT,
875 NSC_MONTH_OFF_DEC = NSC_MONTH_OFF_NOV + NSC_MONTH_DAYS_NOV
876 };
877 static const uint16_t month_offsets[NSC_TIME_MONTH__COUNT] = {
878 [NSC_TIME_MONTH_JAN] = NSC_MONTH_OFF_JAN,
879 [NSC_TIME_MONTH_FEB] = NSC_MONTH_OFF_FEB,
880 [NSC_TIME_MONTH_MAR] = NSC_MONTH_OFF_MAR,
881 [NSC_TIME_MONTH_APR] = NSC_MONTH_OFF_APR,
882 [NSC_TIME_MONTH_MAY] = NSC_MONTH_OFF_MAY,
883 [NSC_TIME_MONTH_JUN] = NSC_MONTH_OFF_JUN,
884 [NSC_TIME_MONTH_JUL] = NSC_MONTH_OFF_JUL,
885 [NSC_TIME_MONTH_AUG] = NSC_MONTH_OFF_AUG,
886 [NSC_TIME_MONTH_SEP] = NSC_MONTH_OFF_SEP,
887 [NSC_TIME_MONTH_OCT] = NSC_MONTH_OFF_OCT,
888 [NSC_TIME_MONTH_NOV] = NSC_MONTH_OFF_NOV,
889 [NSC_TIME_MONTH_DEC] = NSC_MONTH_OFF_DEC
890 };
891 int year_days = (ctx->years - 1970) * 365;
892 int month_days = month_offsets[ctx->month];
893 int year = (ctx->month < NSC_TIME_MONTH_FEB) ?
894 ctx->years - 1 : ctx->years;
895 int leap_days = time__get_leap_days(year) - time__get_leap_days(1969);
896 int total_days = year_days + month_days + ctx->day + leap_days;
897
898 int mins = (int)ctx->mins + (int)ctx->timezone_offset_mins;
899
900 *time = (((((time_t)(total_days)) * 24) +
901 ctx->hours) * 60 +
902 mins) * 60 +
903 ctx->secs;
904 return NSERROR_OK;
905}
906
907
908/**
909 * Parse a date string to a `time_t`.
910 *
911 * \param[in] str String to parse.
912 * \param[out] time Returns the number of seconds since 1 Jan 1970 00:00 UTC.
913 * \return `NSERROR_OK` on success, else
914 * `NSERROR_INVALID` if the string parsing failed,
915 * appropriate error otherwise.
916 */
917static nserror time__get_date(const char *str, time_t *time)
918{
920 struct nsc_date_parse_ctx ctx = {
921 .prev = '\0',
922 .secs = 0,
923 .mins = 0,
924 .hours = 0,
925 .day = 0,
926 .month = 0,
927 .years = 0,
928 .timezone_offset_mins = 0
929 };
930
931 if (str == NULL || time == NULL) {
933 }
934
935 /* Parse */
936 while (*str != '\0' &&
938 size_t len = 1;
939
940 if (ascii_is_alpha(*str)) {
941 len += ascii_count_alpha(str + 1);
942
943 if (!time__parse_weekday(str, len, &flags) &&
944 !time__parse_month(str, len, &flags, &ctx) &&
945 !time__parse_timezone(str, len, &flags, &ctx)) {
946 return NSERROR_INVALID;
947 }
948
949 } else if (ascii_is_digit(*str)) {
950 len += ascii_count_digit(str + 1);
951
952 if (!time__parse_hh_mm_ss(str, &len, &flags, &ctx) &&
953 !time__parse_number(str, len, &flags, &ctx)) {
954 return NSERROR_INVALID;
955 }
956 }
957 ctx.prev = *str;
958 str += len;
959 }
960
961 /* The initial values of 0 are used if hours, mins, secs, and timezone
962 * are not found */
965
966 /* Validate */
968 return NSERROR_INVALID;
969 }
970 if (ctx.secs > 60 || ctx.mins > 59 || ctx.hours > 23 ||
971 ctx.day > 31 || ctx.month > 11) {
972 return NSERROR_INVALID;
973 }
974
975 /* Convert */
976 return time__ctx_to_time_t(&ctx, flags, time);
977}
978
979/* exported function documented in utils/time.h */
980nserror nsc_strntimet(const char *str, size_t size, time_t *timep)
981{
982 return time__get_date(str, timep);
983}
984
985# else
986
987/* exported function documented in utils/time.h */
988nserror nsc_strntimet(const char *str, size_t size, time_t *timep)
989{
990 time_t result;
991
992 if (str == NULL || timep == NULL) {
994 }
995
996 result = curl_getdate(str, NULL);
997
998 if (result == -1) {
999 return NSERROR_INVALID;
1000 }
1001
1002 *timep = result;
1003
1004 return NSERROR_OK;
1005}
1006
1007#endif
STATIC char result[100]
Definition: arexx.c:77
Helpers for ASCII string handling.
static size_t ascii_count_alpha(const char *str)
Count consecutive alphabetical characters in string (upper or lower case).
Definition: ascii.h:267
static size_t ascii_string_to_int(const char *str, int *res)
Parse an int out of a string.
Definition: ascii.h:397
static size_t ascii_count_digit_or_colon(const char *str)
Count consecutive characters either decimal digit or colon in string.
Definition: ascii.h:297
static bool ascii_is_sign(char c)
Test whether a character is a positive/negative numerical sign.
Definition: ascii.h:97
static size_t ascii_count_digit(const char *str)
Count consecutive decial digit characters in string.
Definition: ascii.h:282
static bool ascii_is_alpha(char c)
Test whether a character is alphabetical (upper or lower case).
Definition: ascii.h:75
static bool ascii_is_digit(char c)
Test whether a character is a decimal digit.
Definition: ascii.h:86
static size_t ascii_strings_count_equal_caseless(const char *s1, const char *s2)
Count consecutive equal ascii characters (case insensitive).
Definition: ascii.h:354
static uint32_t count(const http_directive *list, lwc_string *key)
Error codes.
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_BAD_PARAMETER
Bad Parameter.
Definition: errors.h:48
@ NSERROR_INVALID
Invalid data.
Definition: errors.h:49
@ NSERROR_OK
No error.
Definition: errors.h:30
long long int strtoll(const char *nptr, char **endptr, int base)
Definition: os3support.c:198
Context for date parsing.
Definition: time.c:541
uint8_t secs
Definition: time.c:543
uint8_t day
Definition: time.c:546
uint8_t month
Definition: time.c:547
char prev
Used for handling neumenrical timezone.
Definition: time.c:542
uint8_t hours
Definition: time.c:545
int16_t timezone_offset_mins
Definition: time.c:549
uint16_t years
Definition: time.c:548
uint8_t mins
Definition: time.c:544
static bool time__parse_hh_mm_ss(const char *str, size_t *len, enum nsc_date_component_flags *flags, struct nsc_date_parse_ctx *ctx)
Attempt to parse an "hh:mm:ss" time from a string.
Definition: time.c:698
static bool time__parse_timezone(const char *str, size_t len, enum nsc_date_component_flags *flags, struct nsc_date_parse_ctx *ctx)
Attempt to parse a timezone name in a string (case insensitive).
Definition: time.c:661
nsc_date_component_flags
Flags for tracking the components of a date that have been parsed.
Definition: time.c:510
@ NSC_COMPONENT_FLAGS_HAVE_HOURS
Definition: time.c:515
@ NSC_COMPONENT_FLAGS_HAVE_SECS
Definition: time.c:517
@ NSC_COMPONENT_FLAGS_HAVE_MONTHS
Definition: time.c:513
@ NSC_COMPONENT_FLAGS__HAVE_HHMMSS
Definition: time.c:524
@ NSC_COMPONENT_FLAGS_HAVE_TIMEZONE
Definition: time.c:518
@ NSC_COMPONENT_FLAGS_HAVE_DAYS
Definition: time.c:514
@ NSC_COMPONENT_FLAGS_HAVE_WEEKDAY
Definition: time.c:519
@ NSC_COMPONENT_FLAGS_HAVE_MINS
Definition: time.c:516
@ NSC_COMPONENT_FLAGS__HAVE_YYYYMMDD
Definition: time.c:520
@ NSC_COMPONENT_FLAGS__HAVE_ALL
Definition: time.c:528
@ NSC_COMPONENT_FLAGS_NONE
Definition: time.c:511
@ NSC_COMPONENT_FLAGS_HAVE_YEARS
Definition: time.c:512
static int time__get_leap_days(int year)
Get number of leap days up until end of given year.
Definition: time.c:830
static bool time__parse_weekday(const char *str, size_t len, enum nsc_date_component_flags *flags)
Test for a weekday name in a string (case insensitive).
Definition: time.c:592
nsc_time_weekdays
Weekdays.
Definition: time.c:46
@ NSC_TIME_WEEKDAY_MON
Definition: time.c:48
@ NSC_TIME_WEEKDAY_FRI
Definition: time.c:52
@ NSC_TIME_WEEKDAY_THU
Definition: time.c:51
@ NSC_TIME_WEEKDAY_SAT
Definition: time.c:53
@ NSC_TIME_WEEKDAY__COUNT
Definition: time.c:54
@ NSC_TIME_WEEKDAY_TUE
Definition: time.c:49
@ NSC_TIME_WEEKDAY_SUN
Definition: time.c:47
@ NSC_TIME_WEEKDAY_WED
Definition: time.c:50
static bool time__parse_number(const char *str, size_t len, enum nsc_date_component_flags *flags, struct nsc_date_parse_ctx *ctx)
Attempt to parse a number from a date string.
Definition: time.c:757
int nsc_sntimet(char *str, size_t size, time_t *timep)
Write the time in seconds since epoch to a buffer.
Definition: time.c:126
nserror nsc_strntimet(const char *str, size_t size, time_t *timep)
Converts a date string to a number of seconds since epoch.
Definition: time.c:980
nsc_time_months
Months.
Definition: time.c:61
@ NSC_TIME_MONTH_AUG
Definition: time.c:69
@ NSC_TIME_MONTH_MAR
Definition: time.c:64
@ NSC_TIME_MONTH__COUNT
Definition: time.c:74
@ NSC_TIME_MONTH_JUL
Definition: time.c:68
@ NSC_TIME_MONTH_DEC
Definition: time.c:73
@ NSC_TIME_MONTH_MAY
Definition: time.c:66
@ NSC_TIME_MONTH_JUN
Definition: time.c:67
@ NSC_TIME_MONTH_OCT
Definition: time.c:71
@ NSC_TIME_MONTH_FEB
Definition: time.c:63
@ NSC_TIME_MONTH_JAN
Definition: time.c:62
@ NSC_TIME_MONTH_SEP
Definition: time.c:70
@ NSC_TIME_MONTH_APR
Definition: time.c:65
@ NSC_TIME_MONTH_NOV
Definition: time.c:72
nserror nsc_snptimet(const char *str, size_t size, time_t *timep)
Parse time in seconds since epoc.
Definition: time.c:147
const char * rfc1123_date(time_t t)
Create an RFC 1123 compliant date string from a Unix timestamp.
Definition: time.c:110
static bool time__parse_month(const char *str, size_t len, enum nsc_date_component_flags *flags, struct nsc_date_parse_ctx *ctx)
Attempt to parse a month name in a string (case insensitive).
Definition: time.c:627
static const char *const weekdays_long[NSC_TIME_WEEKDAY__COUNT]
Array of long weekday names.
Definition: time.c:192
static const char *const timezones[NSC_TIME_ZONE__COUNT]
Array of timezone names.
Definition: time.c:437
static bool flags_chk_all(enum nsc_date_component_flags flags, enum nsc_date_component_flags mask)
Helper for testing whether all of the flags in mask are set.
Definition: time.c:574
static const char *const weekdays_short[NSC_TIME_WEEKDAY__COUNT]
Array of short weekday names.
Definition: time.c:81
static bool flags_chk(enum nsc_date_component_flags flags, enum nsc_date_component_flags mask)
Helper for testing whether any of the flags in mask are set.
Definition: time.c:560
static nserror time__get_date(const char *str, time_t *time)
Parse a date string to a time_t.
Definition: time.c:917
nsc_time_zones
List of timezones.
Definition: time.c:289
@ NSC_TIME_ZONE_IDLE
Definition: time.c:292
@ NSC_TIME_ZONE_AHST
Definition: time.c:314
@ NSC_TIME_ZONE_HST
Definition: time.c:316
@ NSC_TIME_ZONE_UTC
Definition: time.c:305
@ NSC_TIME_ZONE_FST
Definition: time.c:322
@ NSC_TIME_ZONE_K
Definition: time.c:355
@ NSC_TIME_ZONE_X
Definition: time.c:334
@ NSC_TIME_ZONE_P
Definition: time.c:342
@ NSC_TIME_ZONE_C
Definition: time.c:348
@ NSC_TIME_ZONE_Y
Definition: time.c:333
@ NSC_TIME_ZONE_MEST
Definition: time.c:323
@ NSC_TIME_ZONE_CST
Definition: time.c:310
@ NSC_TIME_ZONE_GST
Definition: time.c:296
@ NSC_TIME_ZONE_G
Definition: time.c:352
@ NSC_TIME_ZONE_WADT
Definition: time.c:320
@ NSC_TIME_ZONE_D
Definition: time.c:349
@ NSC_TIME_ZONE_I
Definition: time.c:354
@ NSC_TIME_ZONE_U
Definition: time.c:337
@ NSC_TIME_ZONE_MST
Definition: time.c:311
@ NSC_TIME_ZONE_N
Definition: time.c:344
@ NSC_TIME_ZONE_IDLW
Definition: time.c:317
@ NSC_TIME_ZONE_NZT
Definition: time.c:294
@ NSC_TIME_ZONE_M
Definition: time.c:357
@ NSC_TIME_ZONE_ADT
Definition: time.c:326
@ NSC_TIME_ZONE_F
Definition: time.c:351
@ NSC_TIME_ZONE_PDT
Definition: time.c:330
@ NSC_TIME_ZONE_H
Definition: time.c:353
@ NSC_TIME_ZONE_MESZ
Definition: time.c:324
@ NSC_TIME_ZONE_WET
Definition: time.c:306
@ NSC_TIME_ZONE_W
Definition: time.c:335
@ NSC_TIME_ZONE_A
Definition: time.c:346
@ NSC_TIME_ZONE_YDT
Definition: time.c:331
@ NSC_TIME_ZONE_YST
Definition: time.c:313
@ NSC_TIME_ZONE_CDT
Definition: time.c:328
@ NSC_TIME_ZONE_L
Definition: time.c:356
@ NSC_TIME_ZONE_R
Definition: time.c:340
@ NSC_TIME_ZONE_Z
Definition: time.c:345
@ NSC_TIME_ZONE_EDT
Definition: time.c:327
@ NSC_TIME_ZONE_Q
Definition: time.c:341
@ NSC_TIME_ZONE_EAST
Definition: time.c:295
@ NSC_TIME_ZONE_V
Definition: time.c:336
@ NSC_TIME_ZONE__COUNT
Definition: time.c:358
@ NSC_TIME_ZONE_NZST
Definition: time.c:293
@ NSC_TIME_ZONE_S
Definition: time.c:339
@ NSC_TIME_ZONE_MET
Definition: time.c:303
@ NSC_TIME_ZONE_BST
Definition: time.c:325
@ NSC_TIME_ZONE_MEWT
Definition: time.c:304
@ NSC_TIME_ZONE_EST
Definition: time.c:309
@ NSC_TIME_ZONE_O
Definition: time.c:343
@ NSC_TIME_ZONE_EADT
Definition: time.c:319
@ NSC_TIME_ZONE_CEST
Definition: time.c:321
@ NSC_TIME_ZONE_FWT
Definition: time.c:302
@ NSC_TIME_ZONE_MDT
Definition: time.c:329
@ NSC_TIME_ZONE_T
Definition: time.c:338
@ NSC_TIME_ZONE_EET
Definition: time.c:300
@ NSC_TIME_ZONE_B
Definition: time.c:347
@ NSC_TIME_ZONE_CET
Definition: time.c:301
@ NSC_TIME_ZONE_NZDT
Definition: time.c:318
@ NSC_TIME_ZONE_E
Definition: time.c:350
@ NSC_TIME_ZONE_CAT
Definition: time.c:315
@ NSC_TIME_ZONE_WAST
Definition: time.c:299
@ NSC_TIME_ZONE_PST
Definition: time.c:312
@ NSC_TIME_ZONE_HDT
Definition: time.c:332
@ NSC_TIME_ZONE_AST
Definition: time.c:308
@ NSC_TIME_ZONE_GMT
"GMT" first since its the only one I've seen in the wild.
Definition: time.c:291
@ NSC_TIME_ZONE_CCT
Definition: time.c:298
@ NSC_TIME_ZONE_WAT
Definition: time.c:307
@ NSC_TIME_ZONE_JST
Definition: time.c:297
static const char *const months[NSC_TIME_MONTH__COUNT]
Array of month names.
Definition: time.c:93
nsc_time_zone_offsets
Timezone offsets in mins.
Definition: time.c:207
@ NSC_TIME_ZONE_OFFSET_M
Definition: time.c:279
@ NSC_TIME_ZONE_OFFSET_HDT
Definition: time.c:252
@ NSC_TIME_ZONE_OFFSET_ADT
Definition: time.c:246
@ NSC_TIME_ZONE_OFFSET_MEST
Definition: time.c:243
@ NSC_TIME_ZONE_OFFSET_EADT
Definition: time.c:239
@ NSC_TIME_ZONE_OFFSET_AST
Definition: time.c:226
@ NSC_TIME_ZONE_OFFSET_L
Definition: time.c:278
@ NSC_TIME_ZONE_OFFSET_AHST
Definition: time.c:232
@ NSC_TIME_ZONE_OFFSET_WAT
Definition: time.c:225
@ NSC_TIME_ZONE_OFFSET_PST
Definition: time.c:230
@ NSC_TIME_ZONE_OFFSET_Z
Definition: time.c:267
@ NSC_TIME_ZONE_OFFSET_I
Definition: time.c:276
@ NSC_TIME_ZONE_OFFSET_GMT
Definition: time.c:222
@ NSC_TIME_ZONE_OFFSET_YST
Definition: time.c:231
@ NSC_TIME_ZONE_OFFSET_MEWT
Definition: time.c:221
@ NSC_TIME_ZONE_OFFSET_X
Definition: time.c:256
@ NSC_TIME_ZONE_OFFSET_EST
Definition: time.c:227
@ NSC_TIME_ZONE_OFFSET_PDT
Definition: time.c:250
@ NSC_TIME_ZONE_OFFSET_WET
Definition: time.c:224
@ NSC_TIME_ZONE_OFFSET_R
Definition: time.c:262
@ NSC_TIME_ZONE_OFFSET_W
Definition: time.c:257
@ NSC_TIME_ZONE_OFFSET_Y
Definition: time.c:255
@ NSC_TIME_ZONE_OFFSET_V
Definition: time.c:258
@ NSC_TIME_ZONE_OFFSET_P
Definition: time.c:264
@ NSC_TIME_ZONE_OFFSET_E
Definition: time.c:272
@ NSC_TIME_ZONE_OFFSET_D
Definition: time.c:271
@ NSC_TIME_ZONE_OFFSET_WADT
Definition: time.c:240
@ NSC_TIME_ZONE_OFFSET_NZT
Definition: time.c:211
@ NSC_TIME_ZONE_OFFSET_A
Definition: time.c:268
@ NSC_TIME_ZONE_OFFSET_EDT
Definition: time.c:247
@ NSC_TIME_ZONE_OFFSET_H
Definition: time.c:275
@ NSC_TIME_ZONE_OFFSET_GST
Definition: time.c:213
@ NSC_TIME_ZONE_OFFSET_U
Definition: time.c:259
@ NSC_TIME_ZONE_OFFSET_MET
Definition: time.c:220
@ NSC_TIME_ZONE_OFFSET_B
Definition: time.c:269
@ NSC_TIME_ZONE_OFFSET_CET
Definition: time.c:218
@ NSC_TIME_ZONE_OFFSET_O
Definition: time.c:265
@ NSC_TIME_ZONE_OFFSET_C
Definition: time.c:270
@ NSC_TIME_ZONE_OFFSET_MESZ
Definition: time.c:244
@ NSC_TIME_ZONE_OFFSET_WAST
Definition: time.c:216
@ NSC_TIME_ZONE_OFFSET_N
Definition: time.c:266
@ NSC_TIME_ZONE_OFFSET_F
Definition: time.c:273
@ NSC_TIME_ZONE_OFFSET_YDT
Definition: time.c:251
@ NSC_TIME_ZONE_OFFSET_EAST
Definition: time.c:212
@ NSC_TIME_ZONE_OFFSET_IDLE
Definition: time.c:209
@ NSC_TIME_ZONE_OFFSET_MST
Definition: time.c:229
@ NSC_TIME_ZONE_OFFSET_NZST
Definition: time.c:210
@ NSC_TIME_ZONE_OFFSET_CCT
Definition: time.c:215
@ NSC_TIME_ZONE_OFFSET_G
Definition: time.c:274
@ NSC_TIME_ZONE_OFFSET_UTC
Definition: time.c:223
@ NSC_TIME_ZONE_OFFSET_IDLW
Definition: time.c:235
@ NSC_TIME_ZONE_OFFSET_K
Definition: time.c:277
@ NSC_TIME_ZONE_OFFSET_JST
Definition: time.c:214
@ NSC_TIME_ZONE_OFFSET_NZDT
Definition: time.c:238
@ NSC_TIME_ZONE_OFFSET_EET
Definition: time.c:217
@ NSC_TIME_ZONE_OFFSET_HST
Definition: time.c:234
@ NSC_TIME_ZONE_OFFSET_MDT
Definition: time.c:249
@ NSC_TIME_ZONE_OFFSET_CAT
Definition: time.c:233
@ NSC_TIME_ZONE_OFFSET_CST
Definition: time.c:228
@ NSC_TIME_ZONE_OFFSET_CEST
Definition: time.c:241
@ NSC_TIME_ZONE_OFFSET_T
Definition: time.c:260
@ NSC_TIME_ZONE_OFFSET_BST
Definition: time.c:245
@ NSC_TIME_ZONE_OFFSET_FWT
Definition: time.c:219
@ NSC_TIME_ZONE_OFFSET_Q
Definition: time.c:263
@ NSC_TIME_ZONE_OFFSET_FST
Definition: time.c:242
@ NSC_TIME_ZONE_OFFSET_CDT
Definition: time.c:248
@ NSC_TIME_ZONE_OFFSET_S
Definition: time.c:261
static const int16_t timezone_mins[NSC_TIME_ZONE__COUNT]
Array of minute offsets for timezones.
Definition: time.c:364
static nserror time__ctx_to_time_t(const struct nsc_date_parse_ctx *ctx, enum nsc_date_component_flags flags, time_t *time)
Helper to convert a date string context to a time_t.
Definition: time.c:844
Interface to time operations.