iso8601-date.c revision 5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "lib.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "utc-offset.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "utc-mktime.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "iso8601-date.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include <ctype.h>
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen/* RFC3339/ISO8601 date-time syntax
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
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 ; month/year
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 ; rules
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time-secfrac = "." 1*DIGIT
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time-numoffset = ("+" / "-") time-hour ":" time-minute
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time-offset = "Z" / time-numoffset
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
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
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen date-time = full-date "T" full-time
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstruct iso8601_date_parser {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen const unsigned char *cur, *end;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen struct tm tm;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen int timezone_offset;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen};
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic inline int
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Siraineniso8601_date_parse_number(struct iso8601_date_parser *parser,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen int digits, int *number_r)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen int i;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->cur >= parser->end || !i_isdigit(parser->cur[0]))
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return 0;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen *number_r = parser->cur[0] - '0';
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen parser->cur++;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen for (i=0; i < digits-1; i++) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->cur >= parser->end || !i_isdigit(parser->cur[0]))
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen *number_r = ((*number_r) * 10) + parser->cur[0] - '0';
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen parser->cur++;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return 1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic int
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Siraineniso8601_date_parse_secfrac(struct iso8601_date_parser *parser)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* time-secfrac = "." 1*DIGIT
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen NOTE: Currently not applied anywhere, so fraction is just skipped.
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* "." */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->cur >= parser->end || parser->cur[0] != '.')
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return 0;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen parser->cur++;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* 1DIGIT */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->cur >= parser->end || !i_isdigit(parser->cur[0]))
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen parser->cur++;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* *DIGIT */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen while (parser->cur < parser->end && i_isdigit(parser->cur[0]))
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen parser->cur++;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return 1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic int is08601_date_parse_time_offset(struct iso8601_date_parser *parser)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen int tz_sign = 1, tz_hour = 0, tz_min = 0;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
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 */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->cur >= parser->end)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return 0;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* time-offset = "Z" / time-numoffset */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen switch (parser->cur[0]) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen case '-':
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen tz_sign = -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen case '+':
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen parser->cur++;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* time-hour = 2DIGIT */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (iso8601_date_parse_number(parser, 2, &tz_hour) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (tz_hour > 23)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* ":" */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->cur >= parser->end || parser->cur[0] != ':')
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen parser->cur++;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen /* time-minute = 2DIGIT */
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen if (iso8601_date_parse_number(parser, 2, &tz_min) <= 0)
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen return -1;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen if (tz_min > 59)
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen return -1;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen break;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen case 'Z':
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen case 'z':
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen parser->cur++;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen break;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen default:
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen return -1;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen }
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen parser->timezone_offset = tz_sign*(tz_hour*60 + tz_min);
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen return 1;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen}
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic int is08601_date_parse_full_time(struct iso8601_date_parser *parser)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
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 ; rules
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* time-hour = 2DIGIT */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (iso8601_date_parse_number(parser, 2, &parser->tm.tm_hour) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen /* ":" */
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen if (parser->cur >= parser->end || parser->cur[0] != ':')
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen parser->cur++;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* time-minute = 2DIGIT */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (iso8601_date_parse_number(parser, 2, &parser->tm.tm_min) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* ":" */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->cur >= parser->end || parser->cur[0] != ':')
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen parser->cur++;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* time-second = 2DIGIT */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (iso8601_date_parse_number(parser, 2, &parser->tm.tm_sec) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* [time-secfrac] */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (iso8601_date_parse_secfrac(parser) < 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* time-offset */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (is08601_date_parse_time_offset(parser) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return 1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic int is08601_date_parse_full_date(struct iso8601_date_parser *parser)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
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 ; month/year
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* date-fullyear = 4DIGIT */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (iso8601_date_parse_number(parser, 4, &parser->tm.tm_year) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->tm.tm_year < 1900)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen parser->tm.tm_year -= 1900;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* "-" */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->cur >= parser->end || parser->cur[0] != '-')
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen parser->cur++;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* date-month = 2DIGIT */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (iso8601_date_parse_number(parser, 2, &parser->tm.tm_mon) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen parser->tm.tm_mon -= 1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* "-" */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->cur >= parser->end || parser->cur[0] != '-')
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen parser->cur++;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* time-second = 2DIGIT */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (iso8601_date_parse_number(parser, 2, &parser->tm.tm_mday) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return 1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic int iso8601_date_parse_date_time(struct iso8601_date_parser *parser)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* date-time = full-date "T" full-time */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* full-date */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (is08601_date_parse_full_date(parser) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* "T" */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->cur >= parser->end ||
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen (parser->cur[0] != 'T' && parser->cur[0] != 't'))
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen parser->cur++;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* full-time */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (is08601_date_parse_full_time(parser) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (parser->cur != parser->end)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return 1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic bool
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Siraineniso8601_date_do_parse(const unsigned char *data, size_t size, struct tm *tm_r,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time_t *timestamp_r, int *timezone_offset_r)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen struct iso8601_date_parser parser;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time_t timestamp;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen memset(&parser, 0, sizeof(parser));
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen parser.cur = data;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen parser.end = data + size;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (iso8601_date_parse_date_time(&parser) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return FALSE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen parser.tm.tm_isdst = -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen timestamp = utc_mktime(&parser.tm);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (timestamp == (time_t)-1)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return FALSE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen *timezone_offset_r = parser.timezone_offset;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen *tm_r = parser.tm;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen *timestamp_r = timestamp - parser.timezone_offset * 60;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return TRUE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenbool iso8601_date_parse(const unsigned char *data, size_t size,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time_t *timestamp_r, int *timezone_offset_r)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen struct tm tm;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return iso8601_date_do_parse(data, size, &tm,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen timestamp_r, timezone_offset_r);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenbool iso8601_date_parse_tm(const unsigned char *data, size_t size,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen struct tm *tm_r, int *timezone_offset_r)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen time_t timestamp;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return iso8601_date_do_parse(data, size, tm_r,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen &timestamp, timezone_offset_r);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenconst char *iso8601_date_create_tm(struct tm *tm, int timezone_offset)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
const char *time_offset;
if (timezone_offset == INT_MAX)
time_offset = "Z";
else {
char sign = '+';
if (timezone_offset < 0) {
timezone_offset = -timezone_offset;
sign = '-';
}
time_offset = t_strdup_printf("%c%02d:%02d", sign,
timezone_offset / 60,
timezone_offset % 60);
}
return t_strdup_printf("%04d-%02d-%02dT%02d:%02d:%02d%s",
tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec, time_offset);
}
const char *iso8601_date_create(time_t timestamp)
{
struct tm *tm;
int timezone_offset;
tm = localtime(&timestamp);
timezone_offset = utc_offset(tm, timestamp);
return iso8601_date_create_tm(tm, timezone_offset);
}