mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +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
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
Loading…
Add table
Add a link
Reference in a new issue