- Merged libexpr ISO8601 code.
This commit is contained in:
Paul Beckingham 2014-01-02 00:45:16 -05:00
parent 4cf0763845
commit 712b0bb4b5
6 changed files with 1429 additions and 1 deletions

View file

@ -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
View 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
View 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
////////////////////////////////////////////////////////////////////////////////

View file

@ -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
View 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
View 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;
}
////////////////////////////////////////////////////////////////////////////////