iso8601-date.c revision 5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen/* RFC3339/ISO8601 date-time syntax
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen date-fullyear = 4DIGIT
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen date-month = 2DIGIT ; 01-12
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time-hour = 2DIGIT ; 00-23
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time-minute = 2DIGIT ; 00-59
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time-secfrac = "." 1*DIGIT
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time-numoffset = ("+" / "-") time-hour ":" time-minute
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time-offset = "Z" / time-numoffset
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen partial-time = time-hour ":" time-minute ":" time-second [time-secfrac]
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen full-date = date-fullyear "-" date-month "-" date-mday
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen full-time = partial-time time-offset
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen date-time = full-date "T" full-time
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic inline int
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Siraineniso8601_date_parse_number(struct iso8601_date_parser *parser,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->cur >= parser->end || !i_isdigit(parser->cur[0]))
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->cur >= parser->end || !i_isdigit(parser->cur[0]))
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen *number_r = ((*number_r) * 10) + parser->cur[0] - '0';
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Siraineniso8601_date_parse_secfrac(struct iso8601_date_parser *parser)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* time-secfrac = "." 1*DIGIT
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen NOTE: Currently not applied anywhere, so fraction is just skipped.
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->cur >= parser->end || parser->cur[0] != '.')
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->cur >= parser->end || !i_isdigit(parser->cur[0]))
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen while (parser->cur < parser->end && i_isdigit(parser->cur[0]))
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic int is08601_date_parse_time_offset(struct iso8601_date_parser *parser)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* time-offset = "Z" / time-numoffset
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time-numoffset = ("+" / "-") time-hour ":" time-minute
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time-hour = 2DIGIT ; 00-23
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time-minute = 2DIGIT ; 00-59
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* time-offset = "Z" / time-numoffset */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* time-hour = 2DIGIT */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (iso8601_date_parse_number(parser, 2, &tz_hour) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->cur >= parser->end || parser->cur[0] != ':')
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen /* time-minute = 2DIGIT */
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen if (iso8601_date_parse_number(parser, 2, &tz_min) <= 0)
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen parser->timezone_offset = tz_sign*(tz_hour*60 + tz_min);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic int is08601_date_parse_full_time(struct iso8601_date_parser *parser)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* full-time = partial-time time-offset
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen partial-time = time-hour ":" time-minute ":" time-second [time-secfrac]
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time-hour = 2DIGIT ; 00-23
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time-minute = 2DIGIT ; 00-59
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* time-hour = 2DIGIT */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (iso8601_date_parse_number(parser, 2, &parser->tm.tm_hour) <= 0)
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen if (parser->cur >= parser->end || parser->cur[0] != ':')
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* time-minute = 2DIGIT */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (iso8601_date_parse_number(parser, 2, &parser->tm.tm_min) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->cur >= parser->end || parser->cur[0] != ':')
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* time-second = 2DIGIT */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (iso8601_date_parse_number(parser, 2, &parser->tm.tm_sec) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* [time-secfrac] */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* time-offset */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (is08601_date_parse_time_offset(parser) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic int is08601_date_parse_full_date(struct iso8601_date_parser *parser)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* full-date = date-fullyear "-" date-month "-" date-mday
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen date-fullyear = 4DIGIT
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen date-month = 2DIGIT ; 01-12
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* date-fullyear = 4DIGIT */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (iso8601_date_parse_number(parser, 4, &parser->tm.tm_year) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->cur >= parser->end || parser->cur[0] != '-')
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* date-month = 2DIGIT */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (iso8601_date_parse_number(parser, 2, &parser->tm.tm_mon) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->cur >= parser->end || parser->cur[0] != '-')
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* time-second = 2DIGIT */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (iso8601_date_parse_number(parser, 2, &parser->tm.tm_mday) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic int iso8601_date_parse_date_time(struct iso8601_date_parser *parser)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* date-time = full-date "T" full-time */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* full-date */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (is08601_date_parse_full_date(parser) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen (parser->cur[0] != 'T' && parser->cur[0] != 't'))
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* full-time */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (is08601_date_parse_full_time(parser) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Siraineniso8601_date_do_parse(const unsigned char *data, size_t size, struct tm *tm_r,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (iso8601_date_parse_date_time(&parser) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen *timestamp_r = timestamp - parser.timezone_offset * 60;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenbool iso8601_date_parse(const unsigned char *data, size_t size,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenbool iso8601_date_parse_tm(const unsigned char *data, size_t size,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return iso8601_date_do_parse(data, size, tm_r,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenconst char *iso8601_date_create_tm(struct tm *tm, int timezone_offset)
const char *time_offset;
if (timezone_offset < 0) {
int timezone_offset;