mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-08-22 11:13:09 +02:00
ISO8601
- Merged libexpr ISO8601 code.
This commit is contained in:
parent
4cf0763845
commit
712b0bb4b5
6 changed files with 1429 additions and 1 deletions
|
@ -18,6 +18,7 @@ set (task_SRCS A3.cpp A3.h
|
|||
E9.cpp E9.h
|
||||
File.cpp File.h
|
||||
Hooks.cpp Hooks.h
|
||||
ISO8601.cpp ISO8601.h
|
||||
JSON.cpp JSON.h
|
||||
LRParser.cpp LRParser.h
|
||||
Msg.cpp Msg.h
|
||||
|
|
880
src/ISO8601.cpp
Normal file
880
src/ISO8601.cpp
Normal file
|
@ -0,0 +1,880 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2006 - 2014, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cmake.h>
|
||||
#include <ISO8601.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
ISO8601d::ISO8601d ()
|
||||
{
|
||||
clear ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
ISO8601d::~ISO8601d ()
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
ISO8601d::operator time_t () const
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// By default, ISO8601d allows ambiguous dates, such as YYYY, YYYYMMDD, HHMMSS.
|
||||
// These are also valid numbers. Setting ambiguity to false inhibites the
|
||||
// parsing of these as dates.
|
||||
void ISO8601d::ambiguity (bool value)
|
||||
{
|
||||
_ambiguity = value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Supported:
|
||||
//
|
||||
// result ::= date-ext 'T' time-ext 'Z' # UTC
|
||||
// | date-ext 'T' time-ext offset-ext # Specified TZ
|
||||
// | date-ext 'T' time-ext # Local
|
||||
// | date-ext # Local
|
||||
// | date 'T' time 'Z'
|
||||
// | date 'T' time offset-ext
|
||||
// | date 'T' time
|
||||
// | date
|
||||
// | time-ext 'Z'
|
||||
// | time-ext offset-ext
|
||||
// | time-ext
|
||||
// | time 'Z'
|
||||
// | time offset
|
||||
// | time
|
||||
// ;
|
||||
//
|
||||
// date-ext ::= ±YYYYY-MM-DD Νot needed
|
||||
// | ±YYYYY-Www-D Νot needed
|
||||
// | ±YYYYY-Www Νot needed
|
||||
// | ±YYYYY-DDD Νot needed
|
||||
// | YYYY-MM-DD
|
||||
// | YYYY-DDD
|
||||
// | YYYY-Www-D
|
||||
// | YYYY-Www
|
||||
// ;
|
||||
//
|
||||
// date ::= ±YYYYYMMDD Νot needed
|
||||
// | ±YYYYYWwwD Νot needed
|
||||
// | ±YYYYYWww Νot needed
|
||||
// | ±YYYYYDDD Νot needed
|
||||
// | ±YYYYYMM Νot needed
|
||||
// | ±YYYYY Νot needed
|
||||
// | ±YYY Νot needed
|
||||
// | YYYYMMDD Ambiguous (number)
|
||||
// | YYYYWwwD
|
||||
// | YYYYWww
|
||||
// | YYYYDDD Ambiguous (number)
|
||||
// | YYYY-MM
|
||||
// | YYYY Ambiguous (number)
|
||||
// | YY Ambiguous (number)
|
||||
// ;
|
||||
//
|
||||
// time-ext ::= hh:mm:ss[,ss]
|
||||
// | hh:mm[,mm]
|
||||
// | hh[,hh] Ambiguous (number)
|
||||
// ;
|
||||
//
|
||||
// time ::= hhmmss[,ss] Ambiguous (number)
|
||||
// | hhmm[,mm] Ambiguous (number)
|
||||
// | hh[,hh] Ambiguous (number)
|
||||
// ;
|
||||
//
|
||||
// time-utc-ext ::= hh:mm[:ss] 'Z' ;
|
||||
// time-utc ::= hh[mm[ss]] 'Z' ;
|
||||
//
|
||||
// offset-ext ::= ±hh[:mm] ;
|
||||
// offset ::= ±hh[mm] ;
|
||||
//
|
||||
// Not yet supported:
|
||||
//
|
||||
// recurrence ::=
|
||||
// | 'R' [n] '/' designated '/' datetime-ext # duration end
|
||||
// | 'R' [n] '/' designated '/' datetime # duration end
|
||||
// | 'R' [n] '/' designated # duration
|
||||
// | 'R' [n] '/' datetime-ext '/' designated # start duration
|
||||
// | 'R' [n] '/' datetime-ext '/' datetime-ext # start end
|
||||
// | 'R' [n] '/' datetime '/' designated # start duration
|
||||
// | 'R' [n] '/' datetime '/' datetime # start end
|
||||
// ;
|
||||
//
|
||||
bool ISO8601d::parse (const std::string& input, std::string::size_type& start)
|
||||
{
|
||||
std::string::size_type i = start;
|
||||
Nibbler n (input.substr (i));
|
||||
|
||||
if (parse_date_time_ext (n) || // Most complex first.
|
||||
parse_date_ext (n) ||
|
||||
parse_time_utc_ext (n) ||
|
||||
parse_time_off_ext (n) ||
|
||||
parse_date_time (n) ||
|
||||
parse_date (n, _ambiguity) ||
|
||||
parse_time_utc (n) ||
|
||||
parse_time_off (n) ||
|
||||
parse_time_ext (n) || // Time last, as it is the most permissive.
|
||||
parse_time (n, _ambiguity))
|
||||
{
|
||||
// Check the values and determine time_t.
|
||||
if (validate ())
|
||||
{
|
||||
// Record cursor position.
|
||||
start = n.cursor ();
|
||||
|
||||
resolve ();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void ISO8601d::clear ()
|
||||
{
|
||||
_ambiguity = true;
|
||||
_year = 0;
|
||||
_month = 0;
|
||||
_week = 0;
|
||||
_weekday = 0;
|
||||
_julian = 0;
|
||||
_day = 0;
|
||||
_seconds = 0;
|
||||
_offset = 0;
|
||||
_utc = false;
|
||||
_value = 0;
|
||||
_default_seconds = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void ISO8601d::set_default_time (int hours, int minutes, int seconds)
|
||||
{
|
||||
_default_seconds = (hours * 3600) + (minutes * 60) + seconds;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// date-ext 'T' time-ext 'Z'
|
||||
// date-ext 'T' time-ext offset-ext
|
||||
// date-ext 'T' time-ext
|
||||
bool ISO8601d::parse_date_time_ext (Nibbler& n)
|
||||
{
|
||||
n.save ();
|
||||
if (parse_date_ext (n))
|
||||
{
|
||||
if (n.skip ('T') &&
|
||||
parse_time_ext (n))
|
||||
{
|
||||
if (n.skip ('Z'))
|
||||
_utc = true;
|
||||
else if (parse_off_ext (n))
|
||||
;
|
||||
|
||||
if (! isdigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Restore date_ext
|
||||
_year = 0;
|
||||
_month = 0;
|
||||
_week = 0;
|
||||
_weekday = 0;
|
||||
_julian = 0;
|
||||
_day = 0;
|
||||
}
|
||||
|
||||
n.restore ();
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// date 'T' time 'Z'
|
||||
// date 'T' time offset
|
||||
// date 'T' time
|
||||
bool ISO8601d::parse_date_time (Nibbler& n)
|
||||
{
|
||||
Nibbler backup (n);
|
||||
if (parse_date (n, true))
|
||||
{
|
||||
if (n.skip ('T') &&
|
||||
parse_time (n, true))
|
||||
{
|
||||
if (n.skip ('Z'))
|
||||
{
|
||||
_utc = true;
|
||||
if (!isdigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
else if (parse_off (n))
|
||||
{
|
||||
if (!isdigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isdigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Restore date
|
||||
_year = 0;
|
||||
_month = 0;
|
||||
_week = 0;
|
||||
_weekday = 0;
|
||||
_julian = 0;
|
||||
_day = 0;
|
||||
}
|
||||
|
||||
n = backup;
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// YYYY-MM-DD
|
||||
// YYYY-DDD
|
||||
// YYYY-Www-D
|
||||
// YYYY-Www
|
||||
bool ISO8601d::parse_date_ext (Nibbler& n)
|
||||
{
|
||||
Nibbler backup (n);
|
||||
int year;
|
||||
if (n.getDigit4 (year) &&
|
||||
n.skip ('-'))
|
||||
{
|
||||
int month;
|
||||
int day;
|
||||
if (n.skip ('W') &&
|
||||
n.getDigit2 (_week))
|
||||
{
|
||||
if (n.skip ('-') &&
|
||||
n.getDigit (_weekday))
|
||||
{
|
||||
}
|
||||
|
||||
_year = year;
|
||||
if (!isdigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
else if (n.getDigit3 (_julian))
|
||||
{
|
||||
_year = year;
|
||||
if (!isdigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
else if (n.getDigit2 (month) &&
|
||||
n.skip ('-') &&
|
||||
n.getDigit2 (day))
|
||||
{
|
||||
_year = year;
|
||||
_month = month;
|
||||
_day = day;
|
||||
if (!isdigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
n = backup;
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// YYYYMMDD Ambiguous (number)
|
||||
// YYYYWwwD
|
||||
// YYYYWww
|
||||
// YYYYDDD Ambiguous (number)
|
||||
// YYYY-MM
|
||||
bool ISO8601d::parse_date (Nibbler& n, bool ambiguous)
|
||||
{
|
||||
Nibbler backup (n);
|
||||
int year;
|
||||
if (n.getDigit4 (year))
|
||||
{
|
||||
int month;
|
||||
if (n.skip ('W'))
|
||||
{
|
||||
int week;
|
||||
if (n.getDigit2 (week))
|
||||
{
|
||||
_week = week;
|
||||
|
||||
int day;
|
||||
if (n.getDigit (day))
|
||||
_weekday = day;
|
||||
|
||||
_year = year;
|
||||
if (!isdigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (n.skip ('-'))
|
||||
{
|
||||
if (n.getDigit2 (_month))
|
||||
{
|
||||
_year = year;
|
||||
if (!isdigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (n.getDigit4 (month))
|
||||
{
|
||||
_year = year;
|
||||
_month = month / 100;
|
||||
_day = month % 100;
|
||||
if (!isdigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
else if (ambiguous && n.getDigit3 (_julian))
|
||||
{
|
||||
_year = year;
|
||||
if (!isdigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
n = backup;
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// ±hh[:mm]
|
||||
bool ISO8601d::parse_off_ext (Nibbler& n)
|
||||
{
|
||||
Nibbler backup (n);
|
||||
std::string sign;
|
||||
if (n.getN (1, sign))
|
||||
{
|
||||
if (sign == "+" || sign == "-")
|
||||
{
|
||||
int offset;
|
||||
int hh;
|
||||
int mm;
|
||||
if (n.getDigit2 (hh) &&
|
||||
!n.getDigit (mm))
|
||||
{
|
||||
offset = hh * 3600;
|
||||
if (n.skip (':') &&
|
||||
n.getDigit2 (mm))
|
||||
offset += mm * 60;
|
||||
|
||||
_offset = (sign == "-") ? -offset : offset;
|
||||
if (!isdigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n = backup;
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// ±hh[mm]
|
||||
bool ISO8601d::parse_off (Nibbler& n)
|
||||
{
|
||||
Nibbler backup (n);
|
||||
std::string sign;
|
||||
if (n.getN (1, sign))
|
||||
{
|
||||
if (sign == "+" || sign == "-")
|
||||
{
|
||||
int offset;
|
||||
int hh;
|
||||
if (n.getDigit2 (hh))
|
||||
{
|
||||
offset = hh * 3600;
|
||||
int mm;
|
||||
if (n.getDigit2 (mm))
|
||||
offset += mm * 60;
|
||||
|
||||
_offset = (sign == "-") ? -offset : offset;
|
||||
if (!isdigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n = backup;
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// hh[:mm[:ss]]
|
||||
bool ISO8601d::parse_time_ext (Nibbler& n)
|
||||
{
|
||||
Nibbler backup (n);
|
||||
int seconds = 0;
|
||||
int hh;
|
||||
int mm;
|
||||
int ss;
|
||||
if (n.getDigit2 (hh) &&
|
||||
!n.getDigit (mm))
|
||||
{
|
||||
seconds = hh * 3600;
|
||||
|
||||
if (n.skip (':') &&
|
||||
n.getDigit2 (mm) &&
|
||||
!n.getDigit (ss))
|
||||
{
|
||||
seconds += mm * 60;
|
||||
|
||||
if (n.skip (':') &&
|
||||
n.getDigit2 (ss))
|
||||
seconds += ss;
|
||||
|
||||
_seconds = seconds;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_ambiguity)
|
||||
{
|
||||
_seconds = seconds;
|
||||
if (!isdigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
n = backup;
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// hh[mm[ss]]
|
||||
bool ISO8601d::parse_time (Nibbler& n, bool ambiguous)
|
||||
{
|
||||
if (!ambiguous)
|
||||
return false;
|
||||
|
||||
Nibbler backup (n);
|
||||
int seconds = 0;
|
||||
int hh;
|
||||
if (n.getDigit2 (hh))
|
||||
{
|
||||
seconds = hh * 3600;
|
||||
|
||||
int mm;
|
||||
if (n.getDigit2 (mm))
|
||||
{
|
||||
seconds += mm * 60;
|
||||
|
||||
int ss;
|
||||
if (n.getDigit2 (ss))
|
||||
seconds += ss;
|
||||
}
|
||||
|
||||
_seconds = seconds;
|
||||
if (!isdigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
|
||||
n = backup;
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// time-ext 'Z'
|
||||
bool ISO8601d::parse_time_utc_ext (Nibbler& n)
|
||||
{
|
||||
n.save ();
|
||||
if (parse_time_ext (n) &&
|
||||
n.skip ('Z'))
|
||||
{
|
||||
_utc = true;
|
||||
if (!isdigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
|
||||
n.restore ();
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// time 'Z'
|
||||
bool ISO8601d::parse_time_utc (Nibbler& n)
|
||||
{
|
||||
n.save ();
|
||||
if (parse_time (n, true) &&
|
||||
n.skip ('Z'))
|
||||
{
|
||||
_utc = true;
|
||||
if (!isdigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
|
||||
n.restore ();
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// time-ext offset-ext
|
||||
bool ISO8601d::parse_time_off_ext (Nibbler& n)
|
||||
{
|
||||
Nibbler backup (n);
|
||||
if (parse_time_ext (n) &&
|
||||
parse_off_ext (n))
|
||||
{
|
||||
if (!isdigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
|
||||
n = backup;
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// time offset
|
||||
bool ISO8601d::parse_time_off (Nibbler& n)
|
||||
{
|
||||
Nibbler backup (n);
|
||||
if (parse_time (n, true) &&
|
||||
parse_off (n))
|
||||
{
|
||||
if (!isdigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
|
||||
n = backup;
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Using Zeller's Congruence.
|
||||
int ISO8601d::dayOfWeek (int year, int month, int day)
|
||||
{
|
||||
int adj = (14 - month) / 12;
|
||||
int m = month + 12 * adj - 2;
|
||||
int y = year - adj;
|
||||
return (day + (13 * m - 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Validation via simple range checking.
|
||||
bool ISO8601d::validate ()
|
||||
{
|
||||
// _year;
|
||||
if ((_year && (_year < 1900 || _year > 2100)) ||
|
||||
(_month && (_month < 1 || _month > 12)) ||
|
||||
(_week && (_week < 1 || _week > 53)) ||
|
||||
(_weekday && (_weekday < 0 || _weekday > 6)) ||
|
||||
(_julian && (_julian < 0 || _julian > 366)) ||
|
||||
(_day && (_day < 1 || _day > 31)) ||
|
||||
(_seconds && (_seconds < 1 || _seconds > 86400)) ||
|
||||
(_offset && (_offset < -86400 || _offset > 86400)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// int tm_sec; seconds (0 - 60)
|
||||
// int tm_min; minutes (0 - 59)
|
||||
// int tm_hour; hours (0 - 23)
|
||||
// int tm_mday; day of month (1 - 31)
|
||||
// int tm_mon; month of year (0 - 11)
|
||||
// int tm_year; year - 1900
|
||||
// int tm_wday; day of week (Sunday = 0)
|
||||
// int tm_yday; day of year (0 - 365)
|
||||
// int tm_isdst; is summer time in effect?
|
||||
// char *tm_zone; abbreviation of timezone name
|
||||
// long tm_gmtoff; offset from UTC in seconds
|
||||
void ISO8601d::resolve ()
|
||||
{
|
||||
// Don't touch the original values.
|
||||
int year = _year;
|
||||
int month = _month;
|
||||
int week = _week;
|
||||
int weekday = _weekday;
|
||||
int julian = _julian;
|
||||
int day = _day;
|
||||
int seconds = _seconds;
|
||||
int offset = _offset;
|
||||
bool utc = _utc;
|
||||
|
||||
struct tm t = {0};
|
||||
|
||||
// Requests that mktime determine summer time effect.
|
||||
t.tm_isdst = -1;
|
||||
|
||||
// Determine local time.
|
||||
time_t now = time (NULL);
|
||||
struct tm* local_now = localtime (&now);
|
||||
struct tm* utc_now = gmtime (&now);
|
||||
|
||||
// What is a complete TZ?
|
||||
// utc
|
||||
// offset
|
||||
// local (get default)
|
||||
if (utc)
|
||||
offset = 0;
|
||||
else if (! offset)
|
||||
{
|
||||
#ifdef HAVE_TM_GMTOFF
|
||||
offset = local_now->tm_gmtoff;
|
||||
#else
|
||||
// TODO Umm...
|
||||
#endif
|
||||
}
|
||||
|
||||
// Subtract the offset, to project local to UTC.
|
||||
seconds -= offset;
|
||||
|
||||
// If the time is specified without a date, if it is earlier than 'now', then
|
||||
// it refers to tomorrow.
|
||||
int seconds_utc_now = utc_now->tm_hour * 3600 +
|
||||
utc_now->tm_min * 60 +
|
||||
utc_now->tm_sec;
|
||||
if (year == 0 &&
|
||||
month == 0 &&
|
||||
day == 0 &&
|
||||
week == 0 &&
|
||||
weekday == 0 &&
|
||||
seconds < seconds_utc_now)
|
||||
{
|
||||
seconds += 86400;
|
||||
}
|
||||
|
||||
// Conversion of week + weekday to julian.
|
||||
if (week)
|
||||
{
|
||||
julian = (week * 7) + weekday - dayOfWeek (year, 1, 4) - 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default values for year, month, day:
|
||||
//
|
||||
// y m d --> y m d
|
||||
// y m - --> y m 1
|
||||
// y - - --> y 1 1
|
||||
// - - - --> now now now
|
||||
//
|
||||
if (year == 0)
|
||||
{
|
||||
year = local_now->tm_year + 1900;
|
||||
month = local_now->tm_mon + 1;
|
||||
day = local_now->tm_mday;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (month == 0)
|
||||
{
|
||||
month = 1;
|
||||
day = 1;
|
||||
}
|
||||
else if (day == 0)
|
||||
day = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (julian)
|
||||
{
|
||||
month = 1;
|
||||
day = julian;
|
||||
}
|
||||
|
||||
t.tm_year = year - 1900;
|
||||
t.tm_mon = month - 1;
|
||||
t.tm_mday = day;
|
||||
|
||||
// What is a complete time spec?
|
||||
// seconds
|
||||
if (seconds)
|
||||
{
|
||||
if (seconds > 86400)
|
||||
{
|
||||
int days = seconds / 86400;
|
||||
t.tm_mday += days;
|
||||
seconds -= days * 86400;
|
||||
}
|
||||
|
||||
t.tm_hour = seconds / 3600;
|
||||
t.tm_min = (seconds % 3600) / 60;
|
||||
t.tm_sec = seconds % 60;
|
||||
}
|
||||
else
|
||||
{
|
||||
// User-provided default.
|
||||
t.tm_hour = _default_seconds / 3600;
|
||||
t.tm_min = (_default_seconds % 3600) / 60;
|
||||
t.tm_sec = _default_seconds % 60;
|
||||
}
|
||||
|
||||
_value = timegm (&t);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
ISO8601p::ISO8601p ()
|
||||
{
|
||||
clear ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
ISO8601p::~ISO8601p ()
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
ISO8601p::operator time_t () const
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Supported:
|
||||
//
|
||||
// duration ::= designated # duration
|
||||
//
|
||||
// designated ::= 'P' [nn 'Y'] [nn 'M'] [nn 'D'] ['T' [nn 'H'] [nn 'M'] [nn 'S']]
|
||||
//
|
||||
// Not supported:
|
||||
//
|
||||
// duration ::= designated '/' datetime-ext # duration end
|
||||
// | degignated '/' datetime # duration end
|
||||
// | designated # duration
|
||||
// | 'P' datetime-ext '/' datetime-ext # start end
|
||||
// | 'P' datetime '/' datetime # start end
|
||||
// | 'P' datetime-ext # start
|
||||
// | 'P' datetime # start
|
||||
// | datetime-ext '/' designated # start duration
|
||||
// | datetime-ext '/' 'P' datetime-ext # start end
|
||||
// | datetime-ext '/' datetime-ext # start end
|
||||
// | datetime '/' designated # start duration
|
||||
// | datetime '/' 'P' datetime # start end
|
||||
// | datetime '/' datetime # start end
|
||||
// ;
|
||||
//
|
||||
bool ISO8601p::parse (const std::string& input, std::string::size_type& start)
|
||||
{
|
||||
std::string::size_type i = start;
|
||||
Nibbler n (input.substr (i));
|
||||
|
||||
if (parse_designated (n))
|
||||
{
|
||||
// Check the values and determine time_t.
|
||||
if (validate ())
|
||||
{
|
||||
// Record cursor position.
|
||||
start = n.cursor ();
|
||||
|
||||
resolve ();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void ISO8601p::clear ()
|
||||
{
|
||||
_year = 0;
|
||||
_month = 0;
|
||||
_day = 0;
|
||||
_hours = 0;
|
||||
_minutes = 0;
|
||||
_seconds = 0;
|
||||
_value = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 'P' [nn 'Y'] [nn 'M'] [nn 'D'] ['T' [nn 'H'] [nn 'M'] [nn 'S']]
|
||||
bool ISO8601p::parse_designated (Nibbler& n)
|
||||
{
|
||||
Nibbler backup (n);
|
||||
|
||||
if (n.skip ('P'))
|
||||
{
|
||||
int value;
|
||||
n.save ();
|
||||
if (n.getUnsignedInt (value) && n.skip ('Y'))
|
||||
_year = value;
|
||||
else
|
||||
n.restore ();
|
||||
|
||||
n.save ();
|
||||
if (n.getUnsignedInt (value) && n.skip ('M'))
|
||||
_month = value;
|
||||
else
|
||||
n.restore ();
|
||||
|
||||
n.save ();
|
||||
if (n.getUnsignedInt (value) && n.skip ('D'))
|
||||
_day = value;
|
||||
else
|
||||
n.restore ();
|
||||
|
||||
if (n.skip ('T'))
|
||||
{
|
||||
n.save ();
|
||||
if (n.getUnsignedInt (value) && n.skip ('H'))
|
||||
_hours = value;
|
||||
else
|
||||
n.restore ();
|
||||
|
||||
n.save ();
|
||||
if (n.getUnsignedInt (value) && n.skip ('M'))
|
||||
_minutes = value;
|
||||
else
|
||||
n.restore ();
|
||||
|
||||
n.save ();
|
||||
if (n.getUnsignedInt (value) && n.skip ('S'))
|
||||
_seconds = value;
|
||||
else
|
||||
n.restore ();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
n = backup;
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool ISO8601p::validate ()
|
||||
{
|
||||
return _year ||
|
||||
_month ||
|
||||
_day ||
|
||||
_hours ||
|
||||
_minutes ||
|
||||
_seconds;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Allow un-normalized values.
|
||||
void ISO8601p::resolve ()
|
||||
{
|
||||
_value = (_year * 365 * 86400) +
|
||||
(_month * 30 * 86400) +
|
||||
(_day * 86400) +
|
||||
(_hours * 3600) +
|
||||
(_minutes * 60) +
|
||||
_seconds;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
110
src/ISO8601.h
Normal file
110
src/ISO8601.h
Normal file
|
@ -0,0 +1,110 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2006 - 2014, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef INCLUDED_ISO8601
|
||||
#define INCLUDED_ISO8601
|
||||
|
||||
#include <Nibbler.h>
|
||||
#include <time.h>
|
||||
|
||||
// Date
|
||||
class ISO8601d
|
||||
{
|
||||
public:
|
||||
ISO8601d ();
|
||||
~ISO8601d ();
|
||||
ISO8601d (const ISO8601d&); // Unimplemented
|
||||
ISO8601d& operator= (const ISO8601d&); // Unimplemented
|
||||
operator time_t () const;
|
||||
void ambiguity (bool);
|
||||
bool parse (const std::string&, std::string::size_type&);
|
||||
void clear ();
|
||||
void set_default_time (int, int, int);
|
||||
|
||||
private:
|
||||
bool parse_date_time_ext (Nibbler&);
|
||||
bool parse_date_time (Nibbler&);
|
||||
bool parse_date_ext (Nibbler&);
|
||||
bool parse_date (Nibbler&, bool);
|
||||
bool parse_off_ext (Nibbler&);
|
||||
bool parse_off (Nibbler&);
|
||||
bool parse_time_ext (Nibbler&);
|
||||
bool parse_time (Nibbler&, bool);
|
||||
bool parse_time_utc_ext (Nibbler&);
|
||||
bool parse_time_utc (Nibbler&);
|
||||
bool parse_time_off_ext (Nibbler&);
|
||||
bool parse_time_off (Nibbler&);
|
||||
int dayOfWeek (int, int, int);
|
||||
bool validate ();
|
||||
void resolve ();
|
||||
|
||||
public:
|
||||
bool _ambiguity;
|
||||
int _year;
|
||||
int _month;
|
||||
int _week;
|
||||
int _weekday;
|
||||
int _julian;
|
||||
int _day;
|
||||
int _seconds;
|
||||
int _offset;
|
||||
bool _utc;
|
||||
time_t _value;
|
||||
|
||||
int _default_seconds;
|
||||
};
|
||||
|
||||
// Period
|
||||
class ISO8601p
|
||||
{
|
||||
public:
|
||||
ISO8601p ();
|
||||
~ISO8601p ();
|
||||
ISO8601p (const ISO8601p&); // Unimplemented
|
||||
ISO8601p& operator= (const ISO8601p&); // Unimplemented
|
||||
operator time_t () const;
|
||||
bool parse (const std::string&, std::string::size_type&);
|
||||
void clear ();
|
||||
|
||||
private:
|
||||
bool parse_designated (Nibbler&);
|
||||
bool validate ();
|
||||
void resolve ();
|
||||
|
||||
public:
|
||||
int _year;
|
||||
int _month;
|
||||
int _day;
|
||||
int _hours;
|
||||
int _minutes;
|
||||
int _seconds;
|
||||
time_t _value;
|
||||
};
|
||||
|
||||
// TODO Recurrence
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
|
@ -9,7 +9,7 @@ include_directories (${CMAKE_SOURCE_DIR}
|
|||
set (test_SRCS autocomplete.t color.t config.t date.t directory.t dom.t
|
||||
duration.t file.t i18n.t json.t list.t msg.t nibbler.t path.t
|
||||
rx.t t.t t2.t taskmod.t tdb2.t text.t tree.t uri.t utf8.t util.t
|
||||
view.t width.t json_test)
|
||||
view.t width.t json_test iso8601d.t iso8601p.t)
|
||||
|
||||
message ("-- Configuring run_all")
|
||||
if (${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
|
||||
|
|
315
test/iso8601d.t.cpp
Normal file
315
test/iso8601d.t.cpp
Normal file
|
@ -0,0 +1,315 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2013 - 2014, Göteborg Bit Factory.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cmake.h>
|
||||
#include <iostream>
|
||||
#include <time.h>
|
||||
#include <test.h>
|
||||
#include <ISO8601.h>
|
||||
#include <Context.h>
|
||||
|
||||
Context context;
|
||||
|
||||
#define AMBIGUOUS // Include ambiguous forms
|
||||
#undef AMBIGUOUS // Exclude ambiguous forms
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void testParse (
|
||||
UnitTest& t,
|
||||
const std::string& input,
|
||||
int in_start,
|
||||
int in_year,
|
||||
int in_month,
|
||||
int in_week,
|
||||
int in_weekday,
|
||||
int in_julian,
|
||||
int in_day,
|
||||
int in_seconds,
|
||||
int in_offset,
|
||||
bool in_utc,
|
||||
time_t in_value)
|
||||
{
|
||||
std::string label = std::string ("parse (\"") + input + "\") --> ";
|
||||
|
||||
ISO8601d iso;
|
||||
std::string::size_type start = 0;
|
||||
|
||||
t.ok (iso.parse (input, start), label + "true");
|
||||
t.is ((int) start, in_start, label + "[]");
|
||||
t.is (iso._year, in_year, label + "_year");
|
||||
t.is (iso._month, in_month, label + "_month");
|
||||
t.is (iso._week, in_week, label + "_week");
|
||||
t.is (iso._weekday, in_weekday, label + "_weekday");
|
||||
t.is (iso._julian, in_julian, label + "_julian");
|
||||
t.is (iso._day, in_day, label + "_day");
|
||||
t.is (iso._seconds, in_seconds, label + "_seconds");
|
||||
t.is (iso._offset, in_offset, label + "_offset");
|
||||
t.is (iso._utc, in_utc, label + "_utc");
|
||||
t.is ((size_t) iso._value, (size_t) in_value, label + "_value");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
UnitTest t (1610
|
||||
#ifdef AMBIGUOUS
|
||||
+ 48
|
||||
#endif
|
||||
);
|
||||
|
||||
ISO8601d iso;
|
||||
std::string::size_type start = 0;
|
||||
t.notok (iso.parse ("foo", start), "foo --> false");
|
||||
t.is ((int)start, 0, "foo[0]");
|
||||
|
||||
// Determine local and UTC time.
|
||||
time_t now = time (NULL);
|
||||
struct tm* local_now = localtime (&now);
|
||||
int local_s = (local_now->tm_hour * 3600) +
|
||||
(local_now->tm_min * 60) +
|
||||
local_now->tm_sec;
|
||||
local_now->tm_hour = 0;
|
||||
local_now->tm_min = 0;
|
||||
local_now->tm_sec = 0;
|
||||
time_t local = timelocal (local_now);
|
||||
std::cout << "# local midnight today " << local << "\n";
|
||||
|
||||
local_now->tm_year = 2013 - 1900;
|
||||
local_now->tm_mon = 12 - 1;
|
||||
local_now->tm_mday = 6;
|
||||
time_t local6 = timelocal (local_now);
|
||||
std::cout << "# local midnight 2013-12-06 " << local6 << "\n";
|
||||
|
||||
local_now->tm_year = 2013 - 1900;
|
||||
local_now->tm_mon = 12 - 1;
|
||||
local_now->tm_mday = 1;
|
||||
time_t local1 = timelocal (local_now);
|
||||
std::cout << "# local midnight 2013-12-01 " << local1 << "\n";
|
||||
|
||||
struct tm* utc_now = gmtime (&now);
|
||||
int utc_s = (utc_now->tm_hour * 3600) +
|
||||
(utc_now->tm_min * 60) +
|
||||
utc_now->tm_sec;
|
||||
utc_now->tm_hour = 0;
|
||||
utc_now->tm_min = 0;
|
||||
utc_now->tm_sec = 0;
|
||||
time_t utc = timegm (utc_now);
|
||||
std::cout << "# utc midnight today " << utc << "\n";
|
||||
|
||||
utc_now->tm_year = 2013 - 1900;
|
||||
utc_now->tm_mon = 12 - 1;
|
||||
utc_now->tm_mday = 6;
|
||||
time_t utc6 = timegm (utc_now);
|
||||
std::cout << "# utc midnight 2013-12-06 " << utc6 << "\n";
|
||||
|
||||
utc_now->tm_year = 2013 - 1900;
|
||||
utc_now->tm_mon = 12 - 1;
|
||||
utc_now->tm_mday = 1;
|
||||
time_t utc1 = timegm (utc_now);
|
||||
std::cout << "# utc midnight 2013-12-01 " << utc1 << "\n";
|
||||
|
||||
int hms = (12 * 3600) + (34 * 60) + 56; // The time 12:34:56 in seconds.
|
||||
int hm = (12 * 3600) + (34 * 60); // The time 12:34:00 in seconds.
|
||||
int h = (12 * 3600); // The time 12:00:00 in seconds.
|
||||
int z = 3600; // TZ offset.
|
||||
|
||||
int ld = local_s > hms ? 86400 : 0; // Local extra day if now > hms.
|
||||
int ud = utc_s > hms ? 86400 : 0; // UTC extra day if now > hms.
|
||||
std::cout << "# ld " << ld << "\n";
|
||||
std::cout << "# ud " << ud << "\n";
|
||||
|
||||
// Aggregated.
|
||||
// input i Year Mo Wk WD Jul Da Secs TZ UTC time_t
|
||||
testParse (t, "12:34:56 ", 8, 0, 0, 0, 0, 0, 0, hms, 0, false, local+hms+ld );
|
||||
|
||||
// time-ext
|
||||
// input i Year Mo Wk WD Jul Da Secs TZ UTC time_t
|
||||
testParse (t, "12:34:56Z", 9, 0, 0, 0, 0, 0, 0, hms, 0, true, utc+hms+ud );
|
||||
testParse (t, "12:34Z", 6, 0, 0, 0, 0, 0, 0, hm, 0, true, utc+hm+ud );
|
||||
testParse (t, "12Z", 3, 0, 0, 0, 0, 0, 0, h, 0, true, utc+h+ud );
|
||||
testParse (t, "12:34:56+01:00", 14, 0, 0, 0, 0, 0, 0, hms, 3600, false, utc+hms-z+ud );
|
||||
testParse (t, "12:34:56+01", 11, 0, 0, 0, 0, 0, 0, hms, 3600, false, utc+hms-z+ud );
|
||||
testParse (t, "12:34+01:00", 11, 0, 0, 0, 0, 0, 0, hm, 3600, false, utc+hm-z+ud );
|
||||
testParse (t, "12:34+01", 8, 0, 0, 0, 0, 0, 0, hm, 3600, false, utc+hm-z+ud );
|
||||
testParse (t, "12+01:00", 8, 0, 0, 0, 0, 0, 0, h, 3600, false, utc+h-z+ud );
|
||||
testParse (t, "12+01", 5, 0, 0, 0, 0, 0, 0, h, 3600, false, utc+h-z+ud );
|
||||
testParse (t, "12:34:56", 8, 0, 0, 0, 0, 0, 0, hms, 0, false, local+hms+ld );
|
||||
testParse (t, "12:34", 5, 0, 0, 0, 0, 0, 0, hm, 0, false, local+hm+ld );
|
||||
#ifdef AMBIGUOUS
|
||||
testParse (t, "12", 2, 0, 0, 0, 0, 0, 0, h, 0, false, local+h+ld );
|
||||
#endif
|
||||
|
||||
// time
|
||||
// input i Year Mo Wk WD Jul Da Secs TZ UTC time_t
|
||||
testParse (t, "123456Z", 7, 0, 0, 0, 0, 0, 0, hms, 0, true, utc+hms+ud );
|
||||
testParse (t, "1234Z", 5, 0, 0, 0, 0, 0, 0, hm, 0, true, utc+hm+ud );
|
||||
testParse (t, "123456+0100", 11, 0, 0, 0, 0, 0, 0, hms, 3600, false, utc+hms-z+ud );
|
||||
testParse (t, "123456+01", 9, 0, 0, 0, 0, 0, 0, hms, 3600, false, utc+hms-z+ud );
|
||||
testParse (t, "1234+0100", 9, 0, 0, 0, 0, 0, 0, hm, 3600, false, utc+hm-z+ud );
|
||||
testParse (t, "1234+01", 7, 0, 0, 0, 0, 0, 0, hm, 3600, false, utc+hm-z+ud );
|
||||
testParse (t, "12+0100", 7, 0, 0, 0, 0, 0, 0, h, 3600, false, utc+h-z+ud );
|
||||
#ifdef AMBIGUOUS
|
||||
testParse (t, "123456", 6, 0, 0, 0, 0, 0, 0, hms, 0, false, local+hms+ld );
|
||||
#endif
|
||||
|
||||
// datetime-ext
|
||||
// input i Year Mo Wk WD Jul Da Secs TZ UTC time_t
|
||||
testParse (t, "2013-12-06", 10, 2013, 12, 0, 0, 0, 6, 0, 0, false, local6 );
|
||||
testParse (t, "2013-340", 8, 2013, 0, 0, 0, 340, 0, 0, 0, false, local6 );
|
||||
testParse (t, "2013-W49-5", 10, 2013, 0, 49, 5, 0, 0, 0, 0, false, local6 );
|
||||
testParse (t, "2013-W49", 8, 2013, 0, 49, 0, 0, 0, 0, 0, false, local1 );
|
||||
|
||||
testParse (t, "2013-12-06T12:34:56", 19, 2013, 12, 0, 0, 0, 6, hms, 0, false, local6+hms);
|
||||
testParse (t, "2013-12-06T12:34", 16, 2013, 12, 0, 0, 0, 6, hm, 0, false, local6+hm );
|
||||
testParse (t, "2013-340T12:34:56", 17, 2013, 0, 0, 0, 340, 0, hms, 0, false, local6+hms);
|
||||
testParse (t, "2013-340T12:34", 14, 2013, 0, 0, 0, 340, 0, hm, 0, false, local6+hm );
|
||||
testParse (t, "2013-W49-5T12:34:56", 19, 2013, 0, 49, 5, 0, 0, hms, 0, false, local6+hms);
|
||||
testParse (t, "2013-W49-5T12:34", 16, 2013, 0, 49, 5, 0, 0, hm, 0, false, local6+hm );
|
||||
testParse (t, "2013-W49T12:34:56", 17, 2013, 0, 49, 0, 0, 0, hms, 0, false, local1+hms);
|
||||
testParse (t, "2013-W49T12:34", 14, 2013, 0, 49, 0, 0, 0, hm, 0, false, local1+hm );
|
||||
|
||||
testParse (t, "2013-12-06T12:34:56Z", 20, 2013, 12, 0, 0, 0, 6, hms, 0, true, utc6+hms );
|
||||
testParse (t, "2013-12-06T12:34Z", 17, 2013, 12, 0, 0, 0, 6, hm, 0, true, utc6+hm );
|
||||
testParse (t, "2013-340T12:34:56Z", 18, 2013, 0, 0, 0, 340, 0, hms, 0, true, utc6+hms );
|
||||
testParse (t, "2013-340T12:34Z", 15, 2013, 0, 0, 0, 340, 0, hm, 0, true, utc6+hm );
|
||||
testParse (t, "2013-W49-5T12:34:56Z", 20, 2013, 0, 49, 5, 0, 0, hms, 0, true, utc6+hms );
|
||||
testParse (t, "2013-W49-5T12:34Z", 17, 2013, 0, 49, 5, 0, 0, hm, 0, true, utc6+hm );
|
||||
testParse (t, "2013-W49T12:34:56Z", 18, 2013, 0, 49, 0, 0, 0, hms, 0, true, utc1+hms );
|
||||
testParse (t, "2013-W49T12:34Z", 15, 2013, 0, 49, 0, 0, 0, hm, 0, true, utc1+hm );
|
||||
|
||||
testParse (t, "2013-12-06T12:34:56+01:00", 25, 2013, 12, 0, 0, 0, 6, hms, 3600, false, utc6+hms-z);
|
||||
testParse (t, "2013-12-06T12:34:56+01", 22, 2013, 12, 0, 0, 0, 6, hms, 3600, false, utc6+hms-z);
|
||||
testParse (t, "2013-12-06T12:34:56-01:00", 25, 2013, 12, 0, 0, 0, 6, hms, -3600, false, utc6+hms+z);
|
||||
testParse (t, "2013-12-06T12:34:56-01", 22, 2013, 12, 0, 0, 0, 6, hms, -3600, false, utc6+hms+z);
|
||||
testParse (t, "2013-12-06T12:34+01:00", 22, 2013, 12, 0, 0, 0, 6, hm, 3600, false, utc6+hm-z );
|
||||
testParse (t, "2013-12-06T12:34+01", 19, 2013, 12, 0, 0, 0, 6, hm, 3600, false, utc6+hm-z );
|
||||
testParse (t, "2013-12-06T12:34-01:00", 22, 2013, 12, 0, 0, 0, 6, hm, -3600, false, utc6+hm+z );
|
||||
testParse (t, "2013-12-06T12:34-01", 19, 2013, 12, 0, 0, 0, 6, hm, -3600, false, utc6+hm+z );
|
||||
testParse (t, "2013-340T12:34:56+01:00", 23, 2013, 0, 0, 0, 340, 0, hms, 3600, false, utc6+hms-z);
|
||||
testParse (t, "2013-340T12:34:56+01", 20, 2013, 0, 0, 0, 340, 0, hms, 3600, false, utc6+hms-z);
|
||||
testParse (t, "2013-340T12:34:56-01:00", 23, 2013, 0, 0, 0, 340, 0, hms, -3600, false, utc6+hms+z);
|
||||
testParse (t, "2013-340T12:34:56-01", 20, 2013, 0, 0, 0, 340, 0, hms, -3600, false, utc6+hms+z);
|
||||
testParse (t, "2013-340T12:34+01:00", 20, 2013, 0, 0, 0, 340, 0, hm, 3600, false, utc6+hm-z );
|
||||
testParse (t, "2013-340T12:34+01", 17, 2013, 0, 0, 0, 340, 0, hm, 3600, false, utc6+hm-z );
|
||||
testParse (t, "2013-340T12:34-01:00", 20, 2013, 0, 0, 0, 340, 0, hm, -3600, false, utc6+hm+z );
|
||||
testParse (t, "2013-340T12:34-01", 17, 2013, 0, 0, 0, 340, 0, hm, -3600, false, utc6+hm+z );
|
||||
testParse (t, "2013-W49-5T12:34:56+01:00", 25, 2013, 0, 49, 5, 0, 0, hms, 3600, false, utc6+hms-z);
|
||||
testParse (t, "2013-W49-5T12:34:56+01", 22, 2013, 0, 49, 5, 0, 0, hms, 3600, false, utc6+hms-z);
|
||||
testParse (t, "2013-W49-5T12:34:56-01:00", 25, 2013, 0, 49, 5, 0, 0, hms, -3600, false, utc6+hms+z);
|
||||
testParse (t, "2013-W49-5T12:34:56-01", 22, 2013, 0, 49, 5, 0, 0, hms, -3600, false, utc6+hms+z);
|
||||
testParse (t, "2013-W49-5T12:34+01:00", 22, 2013, 0, 49, 5, 0, 0, hm, 3600, false, utc6+hm-z );
|
||||
testParse (t, "2013-W49-5T12:34+01", 19, 2013, 0, 49, 5, 0, 0, hm, 3600, false, utc6+hm-z );
|
||||
testParse (t, "2013-W49-5T12:34-01:00", 22, 2013, 0, 49, 5, 0, 0, hm, -3600, false, utc6+hm+z );
|
||||
testParse (t, "2013-W49-5T12:34-01", 19, 2013, 0, 49, 5, 0, 0, hm, -3600, false, utc6+hm+z );
|
||||
testParse (t, "2013-W49T12:34:56+01:00", 23, 2013, 0, 49, 0, 0, 0, hms, 3600, false, utc1+hms-z);
|
||||
testParse (t, "2013-W49T12:34:56+01", 20, 2013, 0, 49, 0, 0, 0, hms, 3600, false, utc1+hms-z);
|
||||
testParse (t, "2013-W49T12:34:56-01:00", 23, 2013, 0, 49, 0, 0, 0, hms, -3600, false, utc1+hms+z);
|
||||
testParse (t, "2013-W49T12:34:56-01", 20, 2013, 0, 49, 0, 0, 0, hms, -3600, false, utc1+hms+z);
|
||||
testParse (t, "2013-W49T12:34+01:00", 20, 2013, 0, 49, 0, 0, 0, hm, 3600, false, utc1+hm-z );
|
||||
testParse (t, "2013-W49T12:34+01", 17, 2013, 0, 49, 0, 0, 0, hm, 3600, false, utc1+hm-z );
|
||||
testParse (t, "2013-W49T12:34-01:00", 20, 2013, 0, 49, 0, 0, 0, hm, -3600, false, utc1+hm+z );
|
||||
testParse (t, "2013-W49T12:34-01", 17, 2013, 0, 49, 0, 0, 0, hm, -3600, false, utc1+hm+z );
|
||||
|
||||
// datetime
|
||||
#ifdef AMBIGUOUS
|
||||
testParse (t, "20131206", 8, 2013, 12, 0, 0, 0, 6, 0, 0, false, local6 );
|
||||
#endif
|
||||
testParse (t, "2013W495", 8, 2013, 0, 49, 5, 0, 0, 0, 0, false, local6 );
|
||||
testParse (t, "2013W49", 7, 2013, 0, 49, 0, 0, 0, 0, 0, false, local1 );
|
||||
#ifdef AMBIGUOUS
|
||||
testParse (t, "2013340", 7, 2013, 0, 0, 0, 340, 0, 0, 0, false, local6 );
|
||||
#endif
|
||||
testParse (t, "2013-12", 7, 2013, 12, 0, 0, 0, 0, 0, 0, false, local1 );
|
||||
|
||||
testParse (t, "20131206T123456", 15, 2013, 12, 0, 0, 0, 6, hms, 0, false, local6+hms);
|
||||
testParse (t, "20131206T12", 11, 2013, 12, 0, 0, 0, 6, h, 0, false, local6+h );
|
||||
testParse (t, "2013W495T123456", 15, 2013, 0, 49, 5, 0, 0, hms, 0, false, local6+hms);
|
||||
testParse (t, "2013W495T12", 11, 2013, 0, 49, 5, 0, 0, h, 0, false, local6+h );
|
||||
testParse (t, "2013W49T123456", 14, 2013, 0, 49, 0, 0, 0, hms, 0, false, local1+hms);
|
||||
testParse (t, "2013W49T12", 10, 2013, 0, 49, 0, 0, 0, h, 0, false, local1+h );
|
||||
testParse (t, "2013340T123456", 14, 2013, 0, 0, 0, 340, 0, hms, 0, false, local6+hms);
|
||||
testParse (t, "2013340T12", 10, 2013, 0, 0, 0, 340, 0, h, 0, false, local6+h );
|
||||
testParse (t, "2013-12T1234", 12, 2013, 12, 0, 0, 0, 0, hm, 0, false, local1+hm );
|
||||
testParse (t, "2013-12T12", 10, 2013, 12, 0, 0, 0, 0, h, 0, false, local1+h );
|
||||
|
||||
testParse (t, "20131206T123456Z", 16, 2013, 12, 0, 0, 0, 6, hms, 0, true, utc6+hms );
|
||||
testParse (t, "20131206T12Z", 12, 2013, 12, 0, 0, 0, 6, h, 0, true, utc6+h );
|
||||
testParse (t, "2013W495T123456Z", 16, 2013, 0, 49, 5, 0, 0, hms, 0, true, utc6+hms );
|
||||
testParse (t, "2013W495T12Z", 12, 2013, 0, 49, 5, 0, 0, h, 0, true, utc6+h );
|
||||
testParse (t, "2013W49T123456Z", 15, 2013, 0, 49, 0, 0, 0, hms, 0, true, utc1+hms );
|
||||
testParse (t, "2013W49T12Z", 11, 2013, 0, 49, 0, 0, 0, h, 0, true, utc1+h );
|
||||
testParse (t, "2013340T123456Z", 15, 2013, 0, 0, 0, 340, 0, hms, 0, true, utc6+hms );
|
||||
testParse (t, "2013340T12Z", 11, 2013, 0, 0, 0, 340, 0, h, 0, true, utc6+h );
|
||||
testParse (t, "2013-12T123456Z", 15, 2013, 12, 0, 0, 0, 0, hms, 0, true, utc1+hms );
|
||||
testParse (t, "2013-12T12Z", 11, 2013, 12, 0, 0, 0, 0, h, 0, true, utc1+h );
|
||||
|
||||
testParse (t, "20131206T123456+0100", 20, 2013, 12, 0, 0, 0, 6, hms, 3600, false, utc6+hms-z);
|
||||
testParse (t, "20131206T123456+01", 18, 2013, 12, 0, 0, 0, 6, hms, 3600, false, utc6+hms-z);
|
||||
testParse (t, "20131206T123456-0100", 20, 2013, 12, 0, 0, 0, 6, hms, -3600, false, utc6+hms+z);
|
||||
testParse (t, "20131206T123456-01", 18, 2013, 12, 0, 0, 0, 6, hms, -3600, false, utc6+hms+z);
|
||||
testParse (t, "20131206T12+0100", 16, 2013, 12, 0, 0, 0, 6, h, 3600, false, utc6+h-z );
|
||||
testParse (t, "20131206T12+01", 14, 2013, 12, 0, 0, 0, 6, h, 3600, false, utc6+h-z );
|
||||
testParse (t, "20131206T12-0100", 16, 2013, 12, 0, 0, 0, 6, h, -3600, false, utc6+h+z );
|
||||
testParse (t, "20131206T12-01", 14, 2013, 12, 0, 0, 0, 6, h, -3600, false, utc6+h+z );
|
||||
testParse (t, "2013W495T123456+0100", 20, 2013, 0, 49, 5, 0, 0, hms, 3600, false, utc6+hms-z);
|
||||
testParse (t, "2013W495T123456+01", 18, 2013, 0, 49, 5, 0, 0, hms, 3600, false, utc6+hms-z);
|
||||
testParse (t, "2013W495T123456-0100", 20, 2013, 0, 49, 5, 0, 0, hms, -3600, false, utc6+hms+z);
|
||||
testParse (t, "2013W495T123456-01", 18, 2013, 0, 49, 5, 0, 0, hms, -3600, false, utc6+hms+z);
|
||||
testParse (t, "2013W495T12+0100", 16, 2013, 0, 49, 5, 0, 0, h, 3600, false, utc6+h-z );
|
||||
testParse (t, "2013W495T12+01", 14, 2013, 0, 49, 5, 0, 0, h, 3600, false, utc6+h-z );
|
||||
testParse (t, "2013W495T12-0100", 16, 2013, 0, 49, 5, 0, 0, h, -3600, false, utc6+h+z );
|
||||
testParse (t, "2013W495T12-01", 14, 2013, 0, 49, 5, 0, 0, h, -3600, false, utc6+h+z );
|
||||
testParse (t, "2013W49T123456+0100", 19, 2013, 0, 49, 0, 0, 0, hms, 3600, false, utc1+hms-z);
|
||||
testParse (t, "2013W49T123456+01", 17, 2013, 0, 49, 0, 0, 0, hms, 3600, false, utc1+hms-z);
|
||||
testParse (t, "2013W49T123456-0100", 19, 2013, 0, 49, 0, 0, 0, hms, -3600, false, utc1+hms+z);
|
||||
testParse (t, "2013W49T123456-01", 17, 2013, 0, 49, 0, 0, 0, hms, -3600, false, utc1+hms+z);
|
||||
testParse (t, "2013W49T12+0100", 15, 2013, 0, 49, 0, 0, 0, h, 3600, false, utc1+h-z );
|
||||
testParse (t, "2013W49T12+01", 13, 2013, 0, 49, 0, 0, 0, h, 3600, false, utc1+h-z );
|
||||
testParse (t, "2013W49T12-0100", 15, 2013, 0, 49, 0, 0, 0, h, -3600, false, utc1+h+z );
|
||||
testParse (t, "2013W49T12-01", 13, 2013, 0, 49, 0, 0, 0, h, -3600, false, utc1+h+z );
|
||||
testParse (t, "2013340T123456+0100", 19, 2013, 0, 0, 0, 340, 0, hms, 3600, false, utc6+hms-z);
|
||||
testParse (t, "2013340T123456+01", 17, 2013, 0, 0, 0, 340, 0, hms, 3600, false, utc6+hms-z);
|
||||
testParse (t, "2013340T123456-0100", 19, 2013, 0, 0, 0, 340, 0, hms, -3600, false, utc6+hms+z);
|
||||
testParse (t, "2013340T123456-01", 17, 2013, 0, 0, 0, 340, 0, hms, -3600, false, utc6+hms+z);
|
||||
testParse (t, "2013340T12+0100", 15, 2013, 0, 0, 0, 340, 0, h, 3600, false, utc6+h-z );
|
||||
testParse (t, "2013340T12+01", 13, 2013, 0, 0, 0, 340, 0, h, 3600, false, utc6+h-z );
|
||||
testParse (t, "2013340T12-0100", 15, 2013, 0, 0, 0, 340, 0, h, -3600, false, utc6+h+z );
|
||||
testParse (t, "2013340T12-01", 13, 2013, 0, 0, 0, 340, 0, h, -3600, false, utc6+h+z );
|
||||
testParse (t, "2013-12T123456+0100", 19, 2013, 12, 0, 0, 0, 0, hms, 3600, false, utc1+hms-z);
|
||||
testParse (t, "2013-12T123456+01", 17, 2013, 12, 0, 0, 0, 0, hms, 3600, false, utc1+hms-z);
|
||||
testParse (t, "2013-12T123456-0100", 19, 2013, 12, 0, 0, 0, 0, hms, -3600, false, utc1+hms+z);
|
||||
testParse (t, "2013-12T123456-01", 17, 2013, 12, 0, 0, 0, 0, hms, -3600, false, utc1+hms+z);
|
||||
testParse (t, "2013-12T12+0100", 15, 2013, 12, 0, 0, 0, 0, h, 3600, false, utc1+h-z );
|
||||
testParse (t, "2013-12T12+01", 13, 2013, 12, 0, 0, 0, 0, h, 3600, false, utc1+h-z );
|
||||
testParse (t, "2013-12T12-0100", 15, 2013, 12, 0, 0, 0, 0, h, -3600, false, utc1+h+z );
|
||||
testParse (t, "2013-12T12-01", 13, 2013, 12, 0, 0, 0, 0, h, -3600, false, utc1+h+z );
|
||||
|
||||
// TODO Test validation of individual values.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
122
test/iso8601p.t.cpp
Normal file
122
test/iso8601p.t.cpp
Normal file
|
@ -0,0 +1,122 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2013 - 2014, Göteborg Bit Factory.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cmake.h>
|
||||
#include <iostream>
|
||||
#include <time.h>
|
||||
#include <test.h>
|
||||
#include <ISO8601.h>
|
||||
#include <Context.h>
|
||||
|
||||
Context context;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void testParse (
|
||||
UnitTest& t,
|
||||
const std::string& input,
|
||||
int in_start,
|
||||
int in_year,
|
||||
int in_month,
|
||||
int in_day,
|
||||
int in_hours,
|
||||
int in_minutes,
|
||||
int in_seconds,
|
||||
time_t in_value)
|
||||
{
|
||||
std::string label = std::string ("parse (\"") + input + "\") --> ";
|
||||
|
||||
ISO8601p iso;
|
||||
std::string::size_type start = 0;
|
||||
|
||||
t.ok (iso.parse (input, start), label + "true");
|
||||
t.is ((int) start, in_start, label + "[]");
|
||||
t.is (iso._year, in_year, label + "_year");
|
||||
t.is (iso._month, in_month, label + "_month");
|
||||
t.is (iso._day, in_day, label + "_day");
|
||||
t.is (iso._hours, in_hours, label + "_hours");
|
||||
t.is (iso._minutes, in_minutes, label + "_minutes");
|
||||
t.is (iso._seconds, in_seconds, label + "_seconds");
|
||||
t.is ((size_t) iso._value, (size_t) in_value, label + "_value");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
UnitTest t (183);
|
||||
|
||||
ISO8601p iso;
|
||||
std::string::size_type start = 0;
|
||||
t.notok (iso.parse ("foo", start), "foo --> false");
|
||||
t.is ((int)start, 0, "foo[0]");
|
||||
|
||||
t.notok (iso.parse ("P", start), "P --> false");
|
||||
t.is ((int)start, 0, "P[0]");
|
||||
|
||||
t.notok (iso.parse ("PT", start), "PT --> false");
|
||||
t.is ((int)start, 0, "PT[0]");
|
||||
|
||||
t.notok (iso.parse ("P1", start), "P1 --> false");
|
||||
t.is ((int)start, 0, "P1[0]");
|
||||
|
||||
t.notok (iso.parse ("P1T", start), "P1T --> false");
|
||||
t.is ((int)start, 0, "P1T[0]");
|
||||
|
||||
t.notok (iso.parse ("PT1", start), "PT1 --> false");
|
||||
t.is ((int)start, 0, "PT1[0]");
|
||||
|
||||
int year = 365 * 86400;
|
||||
int month = 30 * 86400;
|
||||
int day = 86400;
|
||||
int h = 3600;
|
||||
int m = 60;
|
||||
|
||||
// Designated.
|
||||
// input i Year Mo Da Ho Mi Se time_t
|
||||
testParse (t, "P1Y", 3, 1, 0, 0, 0, 0, 0, year);
|
||||
testParse (t, "P1M", 3, 0, 1, 0, 0, 0, 0, month);
|
||||
testParse (t, "P1D", 3, 0, 0, 1, 0, 0, 0, day);
|
||||
testParse (t, "P1Y1M", 5, 1, 1, 0, 0, 0, 0, year + month);
|
||||
testParse (t, "P1Y1D", 5, 1, 0, 1, 0, 0, 0, year + day);
|
||||
testParse (t, "P1M1D", 5, 0, 1, 1, 0, 0, 0, month + day);
|
||||
testParse (t, "P1Y1M1D", 7, 1, 1, 1, 0, 0, 0, year + month + day);
|
||||
testParse (t, "PT1H", 4, 0, 0, 0, 1, 0, 0, h);
|
||||
testParse (t, "PT1M", 4, 0, 0, 0, 0, 1, 0, m);
|
||||
testParse (t, "PT1S", 4, 0, 0, 0, 0, 0, 1, 1);
|
||||
testParse (t, "PT1H1M", 6, 0, 0, 0, 1, 1, 0, h + m);
|
||||
testParse (t, "PT1H1S", 6, 0, 0, 0, 1, 0, 1, h + 1);
|
||||
testParse (t, "PT1M1S", 6, 0, 0, 0, 0, 1, 1, m + 1);
|
||||
testParse (t, "PT1H1M1S", 8, 0, 0, 0, 1, 1, 1, h + m + 1);
|
||||
testParse (t, "P1Y1M1DT1H1M1S", 14, 1, 1, 1, 1, 1, 1, year + month + day + h + m + 1);
|
||||
|
||||
testParse (t, "PT24H", 5, 0, 0, 0, 24, 0, 0, day);
|
||||
testParse (t, "PT40000000S", 11, 0, 0, 0, 0, 0, 40000000, 40000000);
|
||||
testParse (t, "PT3600S", 7, 0, 0, 0, 0, 0, 3600, h);
|
||||
testParse (t, "PT60M", 5, 0, 0, 0, 0, 60, 0, h);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
Loading…
Add table
Add a link
Reference in a new issue