diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0335b6991..35c182b56 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,7 +10,6 @@ set (task_SRCS CLI2.cpp CLI2.h Config.cpp Config.h Context.cpp Context.h DOM.cpp DOM.h - Date.cpp Date.h Dates.cpp Dates.h Eval.cpp Eval.h Filter.cpp Filter.h diff --git a/src/Config.cpp b/src/Config.cpp index f726176e0..f6617f766 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include @@ -574,7 +574,7 @@ void Config::createDefaultRC (const std::string& rc, const std::string& data) auto loc = _defaults.find ("data.location=~/.task"); // loc+0^ +14^ +21^ - Date now; + ISO8601d now; std::stringstream contents; contents << "# [Created by " << PACKAGE_STRING diff --git a/src/Context.cpp b/src/Context.cpp index 62d879f73..8aae74ee6 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -328,7 +329,7 @@ int Context::run () << "-" #endif << " " - << Date ().toISO () + << ISO8601d ().toISO () << " init:" << timer_init.total () << " load:" << timer_load.total () @@ -621,8 +622,9 @@ void Context::getLimits (int& rows, int& lines) // easier, it has been decoupled from Context. void Context::staticInitialization () { - CLI2::minimumMatchLength = config.getInteger ("abbreviation.minimum"); - Lexer::minimumMatchLength = config.getInteger ("abbreviation.minimum"); + CLI2::minimumMatchLength = config.getInteger ("abbreviation.minimum"); + Lexer::minimumMatchLength = config.getInteger ("abbreviation.minimum"); + ISO8601d::minimumMatchLength = config.getInteger ("abbreviation.minimum"); Task::defaultProject = config.get ("default.project"); Task::defaultDue = config.get ("default.due"); @@ -630,10 +632,12 @@ void Context::staticInitialization () Task::searchCaseSensitive = Variant::searchCaseSensitive = config.getBoolean ("search.case.sensitive"); Task::regex = Variant::searchUsingRegex = config.getBoolean ("regex"); Lexer::dateFormat = Variant::dateFormat = config.get ("dateformat"); - Lexer::isoEnabled = Variant::isoEnabled = config.getBoolean ("date.iso"); + ISO8601p::isoEnabled = ISO8601d::isoEnabled = config.getBoolean ("date.iso"); TDB2::debug_mode = config.getBoolean ("debug"); + ISO8601d::weekstart = config.get ("weekstart"); + for (auto& rc : config) { if (rc.first.substr (0, 4) == "uda." && diff --git a/src/DOM.cpp b/src/DOM.cpp index 929f40823..f9a64a594 100644 --- a/src/DOM.cpp +++ b/src/DOM.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -300,7 +299,7 @@ bool DOM::get (const std::string& name, const Task& task, Variant& value) ISO8601p iso; std::string::size_type cursor = 0; if (iso.parse (period, cursor)) - value = Variant ((time_t) iso._value, Variant::type_duration); + value = Variant ((time_t) iso, Variant::type_duration); else value = Variant ((time_t) ISO8601p (ref.get (canonical)), Variant::type_duration); } @@ -320,7 +319,7 @@ bool DOM::get (const std::string& name, const Task& task, Variant& value) if (ref.size () && size == 2 && column && column->type () == "date") { - Date date (ref.get_date (canonical)); + ISO8601d date (ref.get_date (canonical)); if (elements[1] == "year") { value = Variant (static_cast (date.year ())); return true; } else if (elements[1] == "month") { value = Variant (static_cast (date.month ())); return true; } else if (elements[1] == "day") { value = Variant (static_cast (date.day ())); return true; } @@ -384,7 +383,7 @@ bool DOM::get (const std::string& name, const Task& task, Variant& value) // ..entry.hour // ..entry.minute // ..entry.second - Date date (i.first.substr (11)); + ISO8601d date (i.first.substr (11)); if (elements[3] == "year") { value = Variant (static_cast (date.year ())); return true; } else if (elements[3] == "month") { value = Variant (static_cast (date.month ())); return true; } else if (elements[3] == "day") { value = Variant (static_cast (date.day ())); return true; } diff --git a/src/Date.cpp b/src/Date.cpp deleted file mode 100644 index 6f39d6272..000000000 --- a/src/Date.cpp +++ /dev/null @@ -1,839 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2006 - 2015, 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern Context context; - -//////////////////////////////////////////////////////////////////////////////// -// Defaults to "now". -Date::Date () -{ - _t = time (NULL); -} - -//////////////////////////////////////////////////////////////////////////////// -Date::Date (const time_t t) -{ - _t = t; -} - -//////////////////////////////////////////////////////////////////////////////// -Date::Date (const int m, const int d, const int y) -{ - // Error if not valid. - struct tm t = {0}; - t.tm_isdst = -1; // Requests that mktime determine summer time effect. - t.tm_mday = d; - t.tm_mon = m - 1; - t.tm_year = y - 1900; - - _t = mktime (&t); -} - -//////////////////////////////////////////////////////////////////////////////// -Date::Date (const int m, const int d, const int y, - const int hr, const int mi, const int se) -{ - // Error if not valid. - struct tm t = {0}; - t.tm_isdst = -1; // Requests that mktime determine summer time effect. - t.tm_mday = d; - t.tm_mon = m - 1; - t.tm_year = y - 1900; - t.tm_hour = hr; - t.tm_min = mi; - t.tm_sec = se; - - _t = mktime (&t); -} - -//////////////////////////////////////////////////////////////////////////////// -Date::Date ( - const std::string& input, - const std::string& format /* = "m/d/Y" */, - const bool iso /* = true */, - const bool epoch /* = true */) -{ - // Check first to see if this is supported as a named date. - Variant v; - if (namedDates (input, v)) - { - _t = v.get_date (); - return; - } - - // Parse a formatted date. - Nibbler n (input); - n.save (); -#ifdef NIBBLER_FEATURE_DATE - if (n.getDate (format, _t) && n.depleted ()) - return; -#endif - - // Parse an ISO date. - n.restore (); - if (iso && n.getDateISO (_t) && n.depleted ()) - return; - - // Perhaps it is an epoch date, in string form? - n.restore (); - if (epoch && isEpoch (input)) - return; - - throw ::format (STRING_DATE_INVALID_FORMAT, input, format); -} - -//////////////////////////////////////////////////////////////////////////////// -Date::Date ( - const std::string& input, - std::string::size_type& i, - const std::string& format /* = "m/d/Y" */, - const bool iso /* = true */, - const bool epoch /* = true */) -{ - // Check first to see if this is supported as a named date. - Variant v; - if (namedDates (input, v)) - { - i = v.source ().length (); - _t = v.get_date (); - return; - } - - // Parse a formatted date. - Nibbler n (input); - n.save (); -#ifdef NIBBLER_FEATURE_DATE - if (n.getDate (format, _t)) - { - i = n.cursor (); - return; - } -#endif - - // Parse an ISO date. - n.restore (); - if (iso && n.getDateISO (_t)) - { - i = n.cursor (); - return; - } - - // Perhaps it is an epoch date, in string form? - n.restore (); - if (epoch && isEpoch (input)) - { - i = 10; - return; - } - - throw ::format (STRING_DATE_INVALID_FORMAT, input, format); -} - -//////////////////////////////////////////////////////////////////////////////// -Date::Date (const Date& rhs) -{ - _t = rhs._t; -} - -//////////////////////////////////////////////////////////////////////////////// -Date::~Date () -{ -} - -//////////////////////////////////////////////////////////////////////////////// -time_t Date::toEpoch () -{ - return _t; -} - -//////////////////////////////////////////////////////////////////////////////// -std::string Date::toEpochString () -{ - std::stringstream epoch; - epoch << _t; - return epoch.str (); -} - -//////////////////////////////////////////////////////////////////////////////// -// 19980119T070000Z = YYYYMMDDThhmmssZ -std::string Date::toISO () -{ - struct tm* t = gmtime (&_t); - - std::stringstream iso; - iso << std::setw (4) << std::setfill ('0') << t->tm_year + 1900 - << std::setw (2) << std::setfill ('0') << t->tm_mon + 1 - << std::setw (2) << std::setfill ('0') << t->tm_mday - << "T" - << std::setw (2) << std::setfill ('0') << t->tm_hour - << std::setw (2) << std::setfill ('0') << t->tm_min - << std::setw (2) << std::setfill ('0') << t->tm_sec - << "Z"; - - return iso.str (); -} - -//////////////////////////////////////////////////////////////////////////////// -double Date::toJulian () -{ - return (_t / 86400.0) + 2440587.5; -} - -//////////////////////////////////////////////////////////////////////////////// -void Date::toEpoch (time_t& epoch) -{ - epoch = _t; -} - -//////////////////////////////////////////////////////////////////////////////// -void Date::toMDY (int& m, int& d, int& y) -{ - struct tm* t = localtime (&_t); - - m = t->tm_mon + 1; - d = t->tm_mday; - y = t->tm_year + 1900; -} - -//////////////////////////////////////////////////////////////////////////////// -const std::string Date::toString ( - const std::string& format /*= "m/d/Y" */) const -{ - // Making this local copy seems to fix a bug. Remove the local copy and - // you'll see segmentation faults and all kinds of gibberish. - std::string localFormat = format; - - char buffer[12]; - std::string formatted; - for (unsigned int i = 0; i < localFormat.length (); ++i) - { - int c = localFormat[i]; - switch (c) - { - case 'm': sprintf (buffer, "%d", this->month ()); break; - case 'M': sprintf (buffer, "%02d", this->month ()); break; - case 'd': sprintf (buffer, "%d", this->day ()); break; - case 'D': sprintf (buffer, "%02d", this->day ()); break; - case 'y': sprintf (buffer, "%02d", this->year () % 100); break; - case 'Y': sprintf (buffer, "%d", this->year ()); break; - case 'a': sprintf (buffer, "%.3s", Date::dayName (dayOfWeek ()).c_str ()); break; - case 'A': sprintf (buffer, "%.10s", Date::dayName (dayOfWeek ()).c_str ()); break; - case 'b': sprintf (buffer, "%.3s", Date::monthName (month ()).c_str ()); break; - case 'B': sprintf (buffer, "%.10s", Date::monthName (month ()).c_str ()); break; - case 'v': sprintf (buffer, "%d", Date::weekOfYear (Date::dayOfWeek (context.config.get ("weekstart")))); break; - case 'V': sprintf (buffer, "%02d", Date::weekOfYear (Date::dayOfWeek (context.config.get ("weekstart")))); break; - case 'h': sprintf (buffer, "%d", this->hour ()); break; - case 'H': sprintf (buffer, "%02d", this->hour ()); break; - case 'n': sprintf (buffer, "%d", this->minute ()); break; - case 'N': sprintf (buffer, "%02d", this->minute ()); break; - case 's': sprintf (buffer, "%d", this->second ()); break; - case 'S': sprintf (buffer, "%02d", this->second ()); break; - case 'j': sprintf (buffer, "%d", this->dayOfYear ()); break; - case 'J': sprintf (buffer, "%03d", this->dayOfYear ()); break; - default: sprintf (buffer, "%c", c); break; - } - - formatted += buffer; - } - - return formatted; -} - -//////////////////////////////////////////////////////////////////////////////// -Date Date::startOfDay () const -{ - return Date (month (), day (), year ()); -} - -//////////////////////////////////////////////////////////////////////////////// -Date Date::startOfWeek () const -{ - Date sow (_t); - sow -= (dayOfWeek () * 86400); - return Date (sow.month (), sow.day (), sow.year ()); -} - -//////////////////////////////////////////////////////////////////////////////// -Date Date::startOfMonth () const -{ - return Date (month (), 1, year ()); -} - -//////////////////////////////////////////////////////////////////////////////// -Date Date::startOfYear () const -{ - return Date (1, 1, year ()); -} - -//////////////////////////////////////////////////////////////////////////////// -bool Date::valid (const std::string& input, const std::string& format) -{ - try - { - Date test (input, format); - } - - catch (...) - { - return false; - } - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Date::valid (const int m, const int d, const int y, const int hr, - const int mi, const int se) -{ - if (hr < 0 || hr > 23) - return false; - - if (mi < 0 || mi > 59) - return false; - - if (se < 0 || se > 59) - return false; - - return Date::valid (m, d, y); -} - -//////////////////////////////////////////////////////////////////////////////// -bool Date::valid (const int m, const int d, const int y) -{ - // Check that the year is valid. - if (y < 0) - return false; - - // Check that the month is valid. - if (m < 1 || m > 12) - return false; - - // Finally check that the days fall within the acceptable range for this - // month, and whether or not this is a leap year. - if (d < 1 || d > Date::daysInMonth (m, y)) - return false; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// Julian -bool Date::valid (const int d, const int y) -{ - // Check that the year is valid. - if (y < 0) - return false; - - if (d < 1 || d > Date::daysInYear (y)) - return false; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Date::leapYear (int year) -{ - bool ly = false; - - // (year % 4 == 0) && (year % 100 !=0) OR - // (year % 400 == 0) - // are leapyears - - if (((!(year % 4)) && (year % 100)) || (!(year % 400))) ly = true; - - return ly; -} - -//////////////////////////////////////////////////////////////////////////////// -int Date::daysInMonth (int month, int year) -{ - static int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - - if (month == 2 && Date::leapYear (year)) - return 29; - - return days[month - 1]; -} - -//////////////////////////////////////////////////////////////////////////////// -int Date::daysInYear (int year) -{ - return Date::leapYear (year) ? 366 : 365; -} - -//////////////////////////////////////////////////////////////////////////////// -std::string Date::monthName (int month) -{ - static const char* months[12] = - { - STRING_DATE_JANUARY, - STRING_DATE_FEBRUARY, - STRING_DATE_MARCH, - STRING_DATE_APRIL, - STRING_DATE_MAY, - STRING_DATE_JUNE, - STRING_DATE_JULY, - STRING_DATE_AUGUST, - STRING_DATE_SEPTEMBER, - STRING_DATE_OCTOBER, - STRING_DATE_NOVEMBER, - STRING_DATE_DECEMBER, - }; - - assert (month > 0); - assert (month <= 12); - return ucFirst (months[month - 1]); -} - -//////////////////////////////////////////////////////////////////////////////// -void Date::dayName (int dow, std::string& name) -{ - static const char* days[7] = - { - STRING_DATE_SUNDAY, - STRING_DATE_MONDAY, - STRING_DATE_TUESDAY, - STRING_DATE_WEDNESDAY, - STRING_DATE_THURSDAY, - STRING_DATE_FRIDAY, - STRING_DATE_SATURDAY, - }; - - name = ucFirst (days[dow]); -} - -//////////////////////////////////////////////////////////////////////////////// -std::string Date::dayName (int dow) -{ - static const char* days[7] = - { - STRING_DATE_SUNDAY, - STRING_DATE_MONDAY, - STRING_DATE_TUESDAY, - STRING_DATE_WEDNESDAY, - STRING_DATE_THURSDAY, - STRING_DATE_FRIDAY, - STRING_DATE_SATURDAY, - }; - - return ucFirst (days[dow]); -} - -//////////////////////////////////////////////////////////////////////////////// -int Date::weekOfYear (int weekStart) const -{ - struct tm* t = localtime (&_t); - char weekStr[3]; - - if (weekStart == 0) - strftime(weekStr, sizeof(weekStr), "%U", t); - else if (weekStart == 1) - strftime(weekStr, sizeof(weekStr), "%V", t); - else - throw std::string (STRING_DATE_BAD_WEEKSTART); - - int weekNumber = atoi (weekStr); - - if (weekStart == 0) - weekNumber += 1; - - return weekNumber; -} - -//////////////////////////////////////////////////////////////////////////////// -int Date::dayOfWeek () const -{ - struct tm* t = localtime (&_t); - return t->tm_wday; -} - -//////////////////////////////////////////////////////////////////////////////// -int Date::dayOfWeek (const std::string& input) -{ - int minimum = CLI2::minimumMatchLength; - if (minimum == 0) - minimum = 3; - - if (closeEnough (STRING_DATE_SUNDAY, input, minimum)) return 0; - else if (closeEnough (STRING_DATE_MONDAY, input, minimum)) return 1; - else if (closeEnough (STRING_DATE_TUESDAY, input, minimum)) return 2; - else if (closeEnough (STRING_DATE_WEDNESDAY, input, minimum)) return 3; - else if (closeEnough (STRING_DATE_THURSDAY, input, minimum)) return 4; - else if (closeEnough (STRING_DATE_FRIDAY, input, minimum)) return 5; - else if (closeEnough (STRING_DATE_SATURDAY, input, minimum)) return 6; - - return -1; -} - -//////////////////////////////////////////////////////////////////////////////// -int Date::dayOfYear () const -{ - struct tm* t = localtime (&_t); - return t->tm_yday + 1; -} - -//////////////////////////////////////////////////////////////////////////////// -int Date::monthOfYear (const std::string& input) -{ - int minimum = CLI2::minimumMatchLength; - if (minimum == 0) - minimum = 3; - - if (closeEnough (STRING_DATE_JANUARY, input, minimum)) return 1; - else if (closeEnough (STRING_DATE_FEBRUARY, input, minimum)) return 2; - else if (closeEnough (STRING_DATE_MARCH, input, minimum)) return 3; - else if (closeEnough (STRING_DATE_APRIL, input, minimum)) return 4; - else if (closeEnough (STRING_DATE_MAY, input, minimum)) return 5; - else if (closeEnough (STRING_DATE_JUNE, input, minimum)) return 6; - else if (closeEnough (STRING_DATE_JULY, input, minimum)) return 7; - else if (closeEnough (STRING_DATE_AUGUST, input, minimum)) return 8; - else if (closeEnough (STRING_DATE_SEPTEMBER, input, minimum)) return 9; - else if (closeEnough (STRING_DATE_OCTOBER, input, minimum)) return 10; - else if (closeEnough (STRING_DATE_NOVEMBER, input, minimum)) return 11; - else if (closeEnough (STRING_DATE_DECEMBER, input, minimum)) return 12; - - return -1; -} - -//////////////////////////////////////////////////////////////////////////////// -int Date::length (const std::string& format) -{ - int total = 0; - - for (auto& i : format) - { - switch (i) - { - case 'm': - case 'M': - case 'd': - case 'D': - case 'y': - case 'v': - case 'V': - case 'h': - case 'H': - case 'n': - case 'N': - case 's': - case 'S': total += 2; break; - case 'b': - case 'j': - case 'J': - case 'a': total += 3; break; - case 'Y': total += 4; break; - case 'A': - case 'B': total += 10; break; - - // Calculate the width, don't assume a single character width. - default: total += mk_wcwidth (i); break; - } - } - - return total; -} - -//////////////////////////////////////////////////////////////////////////////// -time_t Date::easter (int year) -{ - int Y = year; - int a = Y % 19; - int b = Y / 100; - int c = Y % 100; - int d = b / 4; - int e = b % 4; - int f = (b + 8) / 25; - int g = (b - f + 1) / 3; - int h = (19 * a + b - d - g + 15) % 30; - int i = c / 4; - int k = c % 4; - int L = (32 + 2 * e + 2 * i - h - k) % 7; - int m = (a + 11 * h + 22 * L) / 451; - int month = (h + L - 7 * m + 114) / 31; - int day = ((h + L - 7 * m + 114) % 31) + 1; - struct tm t = {0}; - t.tm_isdst = -1; // Requests that mktime determine summer time effect. - t.tm_mday = day; - t.tm_mon = month - 1; - t.tm_year = year - 1900; - return mktime (&t); -} - -//////////////////////////////////////////////////////////////////////////////// -int Date::month () const -{ - struct tm* t = localtime (&_t); - return t->tm_mon + 1; -} - -//////////////////////////////////////////////////////////////////////////////// -int Date::week () const -{ - return Date::weekOfYear (Date::dayOfWeek (context.config.get ("weekstart"))); -} - -//////////////////////////////////////////////////////////////////////////////// -int Date::day () const -{ - struct tm* t = localtime (&_t); - return t->tm_mday; -} - -//////////////////////////////////////////////////////////////////////////////// -int Date::year () const -{ - struct tm* t = localtime (&_t); - return t->tm_year + 1900; -} - -//////////////////////////////////////////////////////////////////////////////// -int Date::hour () const -{ - struct tm* t = localtime (&_t); - return t->tm_hour; -} - -//////////////////////////////////////////////////////////////////////////////// -int Date::minute () const -{ - struct tm* t = localtime (&_t); - return t->tm_min; -} - -//////////////////////////////////////////////////////////////////////////////// -int Date::second () const -{ - struct tm* t = localtime (&_t); - return t->tm_sec; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Date::operator== (const Date& rhs) const -{ - return rhs._t == _t; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Date::operator!= (const Date& rhs) const -{ - return rhs._t != _t; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Date::operator< (const Date& rhs) const -{ - return _t < rhs._t; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Date::operator> (const Date& rhs) const -{ - return _t > rhs._t; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Date::operator<= (const Date& rhs) const -{ - return _t <= rhs._t; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Date::operator>= (const Date& rhs) const -{ - return _t >= rhs._t; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Date::sameHour (const Date& rhs) const -{ - if (this->year () == rhs.year () && - this->month () == rhs.month () && - this->day () == rhs.day () && - this->hour () == rhs.hour ()) - return true; - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Date::sameDay (const Date& rhs) const -{ - if (this->year () == rhs.year () && - this->month () == rhs.month () && - this->day () == rhs.day ()) - return true; - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Date::sameWeek (const Date& rhs) const -{ - if (this->year () == rhs.year () && - this->week () == rhs.week ()) - return true; - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Date::sameMonth (const Date& rhs) const -{ - if (this->year () == rhs.year () && - this->month () == rhs.month ()) - return true; - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Date::sameYear (const Date& rhs) const -{ - if (this->year () == rhs.year ()) - return true; - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -Date Date::operator- (const int delta) -{ - return Date (_t - delta); -} - -//////////////////////////////////////////////////////////////////////////////// -Date Date::operator+ (const int delta) -{ - return Date (_t + delta); -} - -//////////////////////////////////////////////////////////////////////////////// -Date& Date::operator+= (const int delta) -{ - _t += (time_t) delta; - return *this; -} - -//////////////////////////////////////////////////////////////////////////////// -Date& Date::operator-= (const int delta) -{ - _t -= (time_t) delta; - return *this; -} - -//////////////////////////////////////////////////////////////////////////////// -time_t Date::operator- (const Date& rhs) -{ - return _t - rhs._t; -} - -//////////////////////////////////////////////////////////////////////////////// -// Prefix decrement by one day. -void Date::operator-- () -{ - Date yesterday = startOfDay () - 1; - yesterday = Date (yesterday.month (), - yesterday.day (), - yesterday.year (), - hour (), - minute (), - second ()); - _t = yesterday._t; -} - -//////////////////////////////////////////////////////////////////////////////// -// Postfix decrement by one day. -void Date::operator-- (int) -{ - Date yesterday = startOfDay () - 1; - yesterday = Date (yesterday.month (), - yesterday.day (), - yesterday.year (), - hour (), - minute (), - second ()); - _t = yesterday._t; -} - -//////////////////////////////////////////////////////////////////////////////// -// Prefix increment by one day. -void Date::operator++ () -{ - Date tomorrow = (startOfDay () + 90001).startOfDay (); - tomorrow = Date (tomorrow.month (), - tomorrow.day (), - tomorrow.year (), - hour (), - minute (), - second ()); - _t = tomorrow._t; -} - -//////////////////////////////////////////////////////////////////////////////// -// Postfix increment by one day. -void Date::operator++ (int) -{ - Date tomorrow = (startOfDay () + 90001).startOfDay (); - tomorrow = Date (tomorrow.month (), - tomorrow.day (), - tomorrow.year (), - hour (), - minute (), - second ()); - _t = tomorrow._t; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Date::isEpoch (const std::string& input) -{ - if (Lexer::isAllDigits (input) && - input.length () <= 10 ) - { - _t = (time_t) atoi (input.c_str ()); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// diff --git a/src/Date.h b/src/Date.h deleted file mode 100644 index 89a0c5f30..000000000 --- a/src/Date.h +++ /dev/null @@ -1,129 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2006 - 2015, 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_DATE -#define INCLUDED_DATE - -#include -#include -#include - -class Date; - -class Date -{ -public: - Date (); - Date (time_t); - Date (const int, const int, const int); - Date (const int, const int, const int, const int, const int, const int); - Date (const std::string&, - const std::string& format = "m/d/Y", - const bool iso = true, - const bool epoch = true); - Date (const std::string&, - std::string::size_type&, - const std::string& format = "m/d/Y", - const bool iso = true, - const bool epoch = true); - Date (const Date&); - virtual ~Date (); - - void toEpoch (time_t&); - time_t toEpoch (); - std::string toEpochString (); - std::string toISO (); - double toJulian (); - void toMDY (int&, int&, int&); - const std::string toString (const std::string& format = "m/d/Y") const; - - Date startOfDay () const; - Date startOfWeek () const; - Date startOfMonth () const; - Date startOfYear () const; - - static bool valid (const std::string&, const std::string& format = "m/d/Y"); - static bool valid (const int, const int, const int, const int, const int, const int); - static bool valid (const int, const int, const int); - static bool valid (const int, const int); - - static time_t easter (int year); - static bool leapYear (int); - static int daysInMonth (int, int); - static int daysInYear (int); - static std::string monthName (int); - static void dayName (int, std::string&); - static std::string dayName (int); - static int weekOfYear (const std::string&); - static int dayOfWeek (const std::string&); - static int monthOfYear (const std::string&); - static int length (const std::string&); - - int month () const; - int week () const; - int day () const; - int year () const; - int weekOfYear (int) const; - int dayOfWeek () const; - int dayOfYear () const; - int hour () const; - int minute () const; - int second () const; - - bool operator== (const Date&) const; - bool operator!= (const Date&) const; - bool operator< (const Date&) const; - bool operator> (const Date&) const; - bool operator<= (const Date&) const; - bool operator>= (const Date&) const; - bool sameHour (const Date&) const; - bool sameDay (const Date&) const; - bool sameWeek (const Date&) const; - bool sameMonth (const Date&) const; - bool sameYear (const Date&) const; - - Date operator+ (const int); - Date operator- (const int); - Date& operator+= (const int); - Date& operator-= (const int); - - time_t operator- (const Date&); - - void operator-- (); // Prefix - void operator-- (int); // Postfix - void operator++ (); // Prefix - void operator++ (int); // Postfix - -private: - bool isEpoch (const std::string&); - -protected: - time_t _t; -}; - -#endif - -//////////////////////////////////////////////////////////////////////////////// diff --git a/src/Dates.cpp b/src/Dates.cpp index a4bb15228..8c7f17ca6 100644 --- a/src/Dates.cpp +++ b/src/Dates.cpp @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include @@ -38,14 +38,14 @@ //////////////////////////////////////////////////////////////////////////////// static bool isMonth (const std::string& name, int& i) { - i = Date::monthOfYear (name) - 1; + i = ISO8601d::monthOfYear (name) - 1; return i != -2 ? true : false; } //////////////////////////////////////////////////////////////////////////////// static bool isDay (const std::string& name, int& i) { - i = Date::dayOfWeek (name); + i = ISO8601d::dayOfWeek (name); return i != -1 ? true : false; } @@ -103,32 +103,33 @@ static void midsommarafton (struct tm* t) } //////////////////////////////////////////////////////////////////////////////// -// -// -// Nth -// socy, eocy -// socq, eocq -// socm, eocm -// som, eom -// soq, eoq -// soy, eoy -// socw, eocw -// sow, eow -// soww, eoww -// sod, eod -// yesterday -// today -// now -// tomorrow -// later = midnight, Jan 18th, 2038. -// someday = midnight, Jan 18th, 2038. -// easter -// eastermonday -// ascension -// pentecost -// goodfriday -// midsommar = midnight, 1st Saturday after 20th June -// midsommarafton = midnight, 1st Friday after 19th June +// Note how these are all single words: +// +// +// Nth +// socy, eocy +// socq, eocq +// socm, eocm +// som, eom +// soq, eoq +// soy, eoy +// socw, eocw +// sow, eow +// soww, eoww +// sod, eod +// yesterday +// today +// now +// tomorrow +// later = midnight, Jan 18th, 2038. +// someday = midnight, Jan 18th, 2038. +// easter +// eastermonday +// ascension +// pentecost +// goodfriday +// midsommar = midnight, 1st Saturday after 20th June +// midsommarafton = midnight, 1st Friday after 19th June // bool namedDates (const std::string& name, Variant& value) { @@ -302,7 +303,7 @@ bool namedDates (const std::string& name, Variant& value) t->tm_hour = 24; t->tm_min = 0; t->tm_sec = -1; - t->tm_mday = Date::daysInMonth (t->tm_mon + 1, t->tm_year + 1900); + t->tm_mday = ISO8601d::daysInMonth (t->tm_mon + 1, t->tm_year + 1900); t->tm_isdst = -1; value = Variant (mktime (t), Variant::type_date); } @@ -414,7 +415,7 @@ bool namedDates (const std::string& name, Variant& value) // If it is this month. if (d < number && - number <= Date::daysInMonth (m, y)) + number <= ISO8601d::daysInMonth (m, y)) { t->tm_hour = t->tm_min = t->tm_sec = 0; t->tm_mon = m - 1; diff --git a/src/ISO8601.cpp b/src/ISO8601.cpp index fe885ed1c..8b7a12163 100644 --- a/src/ISO8601.cpp +++ b/src/ISO8601.cpp @@ -26,11 +26,16 @@ #include #include +#include #include +#include #include #include #include -#include +#include +#include +#include +#include #define DAY 86400 #define HOUR 3600 @@ -106,10 +111,66 @@ static struct #define NUM_DURATIONS (sizeof (durations) / sizeof (durations[0])) +std::string ISO8601d::weekstart = STRING_DATE_SUNDAY; +int ISO8601d::minimumMatchLength = 3; +bool ISO8601d::isoEnabled = true; +bool ISO8601p::isoEnabled = true; + //////////////////////////////////////////////////////////////////////////////// ISO8601d::ISO8601d () { clear (); + _date = time (NULL); +} + +//////////////////////////////////////////////////////////////////////////////// +ISO8601d::ISO8601d (const std::string& input, const std::string& format /*= ""*/) +{ + clear (); + std::string::size_type start = 0; + if (! parse (input, start, format)) + throw ::format (STRING_DATE_INVALID_FORMAT, input, format); +} + +//////////////////////////////////////////////////////////////////////////////// +ISO8601d::ISO8601d (const time_t t) +{ + clear (); + _date = t; +} + +//////////////////////////////////////////////////////////////////////////////// +ISO8601d::ISO8601d (const int m, const int d, const int y) +{ + clear (); + + // Error if not valid. + struct tm t = {0}; + t.tm_isdst = -1; // Requests that mktime determine summer time effect. + t.tm_mday = d; + t.tm_mon = m - 1; + t.tm_year = y - 1900; + + _date = mktime (&t); +} + +//////////////////////////////////////////////////////////////////////////////// +ISO8601d::ISO8601d (const int m, const int d, const int y, + const int hr, const int mi, const int se) +{ + clear (); + + // Error if not valid. + struct tm t = {0}; + t.tm_isdst = -1; // Requests that mktime determine summer time effect. + t.tm_mday = d; + t.tm_mon = m - 1; + t.tm_year = y - 1900; + t.tm_hour = hr; + t.tm_min = mi; + t.tm_sec = se; + + _date = mktime (&t); } //////////////////////////////////////////////////////////////////////////////// @@ -120,7 +181,7 @@ ISO8601d::~ISO8601d () //////////////////////////////////////////////////////////////////////////////// ISO8601d::operator time_t () const { - return _value; + return _date; } //////////////////////////////////////////////////////////////////////////////// @@ -168,29 +229,49 @@ ISO8601d::operator time_t () const // | 'R' [n] '/' datetime '/' datetime # start end // ; // -bool ISO8601d::parse (const std::string& input, std::string::size_type& start) +bool ISO8601d::parse ( + const std::string& input, + std::string::size_type& start, + const std::string& format /* = "" */) { auto i = start; Nibbler n (input.substr (i)); - - if (parse_date_time (n) || // Strictest first. - parse_date_time_ext (n) || - parse_date_ext (n) || - parse_time_utc_ext (n) || - parse_time_off_ext (n) || - parse_time_ext (n)) // Time last, as it is the most permissive. + if (parse_formatted (n, format)) { // Check the values and determine time_t. if (validate ()) { - // Record cursor position. start = n.cursor (); - resolve (); return true; } } + else if (ISO8601d::isoEnabled && + (parse_date_time (n) || // Strictest first. + parse_date_time_ext (n) || + parse_date_ext (n) || + parse_time_utc_ext (n) || + parse_time_off_ext (n) || + parse_time_ext (n))) // Time last, as it is the most permissive. + { + // Check the values and determine time_t. + if (validate ()) + { + start = n.cursor (); + resolve (); + return true; + } + } + + else if (parse_epoch (n) || + parse_named (n)) + { + // ::validate and ::resolve are not needed in this case. + start = n.cursor (); + return true; + } + return false; } @@ -206,7 +287,340 @@ void ISO8601d::clear () _seconds = 0; _offset = 0; _utc = false; - _value = 0; + _date = 0; +} + +//////////////////////////////////////////////////////////////////////////////// +bool ISO8601d::parse_formatted (Nibbler& n, const std::string& format) +{ + // Short-circuit on missing format. + if (format == "") + return false; + + n.save (); + + int month = -1; // So we can check later. + int day = -1; + int year = -1; + int hour = -1; + int minute = -1; + int second = -1; + + // For parsing, unused. + int wday = -1; + int week = -1; + + for (unsigned int f = 0; f < format.length (); ++f) + { + switch (format[f]) + { + case 'm': + if (n.getDigit (month)) + { + if (month == 1) + if (n.getDigit (month)) + month += 10; + } + else + { + n.restore (); + return false; + } + break; + + case 'M': + if (! n.getDigit2 (month)) + { + n.restore (); + return false; + } + break; + + case 'd': + if (n.getDigit (day)) + { + if (day == 1 || day == 2 || day == 3) + { + int tens = day; + if (n.getDigit (day)) + day += 10 * tens; + } + } + else + { + n.restore (); + return false; + } + break; + + case 'D': + if (! n.getDigit2 (day)) + { + n.restore (); + return false; + } + break; + + case 'y': + if (! n.getDigit2 (year)) + { + n.restore (); + return false; + } + year += 2000; + break; + + case 'Y': + if (! n.getDigit4 (year)) + { + n.restore (); + return false; + } + break; + + case 'h': + if (n.getDigit (hour)) + { + if (hour == 1 || hour == 2) + { + int tens = hour; + if (n.getDigit (hour)) + hour += 10 * tens; + } + } + else + { + n.restore (); + return false; + } + break; + + case 'H': + if (! n.getDigit2 (hour)) + { + n.restore (); + return false; + } + break; + + case 'n': + if (n.getDigit (minute)) + { + if (minute < 6) + { + int tens = minute; + if (n.getDigit (minute)) + minute += 10 * tens; + } + } + else + { + n.restore (); + return false; + } + break; + + case 'N': + if (! n.getDigit2 (minute)) + { + n.restore (); + return false; + } + break; + + case 's': + if (n.getDigit (second)) + { + if (second < 6) + { + int tens = second; + if (n.getDigit (second)) + second += 10 * tens; + } + } + else + { + n.restore (); + return false; + } + break; + + case 'S': + if (! n.getDigit2 (second)) + { + n.restore (); + return false; + } + break; + + case 'v': + if (n.getDigit (week)) + { + if (week < 6) + { + int tens = week; + if (n.getDigit (week)) + week += 10 * tens; + } + } + else + { + n.restore (); + return false; + } + break; + + case 'V': + if (! n.getDigit2 (week)) + { + n.restore (); + return false; + } + break; + + case 'a': + { + auto cursor = n.cursor (); + wday = ISO8601d::dayOfWeek (n.str ().substr (cursor, 3)); + if (wday == -1) + { + n.restore (); + return false; + } + + n.skipN (3); + } + break; + + case 'A': + { + auto cursor = n.cursor (); + wday = ISO8601d::dayOfWeek (n.str ().substr (cursor)); + if (wday == -1) + { + n.restore (); + return false; + } + + n.skipN (ISO8601d::dayName (wday).size ()); + } + break; + + case 'b': + { + auto cursor = n.cursor (); + month = ISO8601d::monthOfYear (n.str ().substr (cursor, 3)); + if (month == -1) + { + n.restore (); + return false; + } + + n.skipN (3); + } + break; + + case 'B': + { + auto cursor = n.cursor (); + month = ISO8601d::dayOfWeek (n.str ().substr (cursor)); + if (month == -1) + { + n.restore (); + return false; + } + + n.skipN (ISO8601d::monthName (month).size ()); + } + break; + + default: + if (! n.skip (format[f])) + { + n.restore (); + return false; + } + break; + } + } + + // Missing values are filled in from the current date. + if (year == -1) + { + ISO8601d now; + year = now.year (); + if (month == -1) + { + month = now.month (); + if (day == -1) + { + day = now.day (); + if (hour == -1) + { + hour = now.hour (); + if (minute == -1) + { + minute = now.minute (); + if (second == -1) + second = now.second (); + } + } + } + } + } + + // Any remaining undefined values are assigned defaults. + if (month == -1) month = 1; + if (day == -1) day = 1; + if (hour == -1) hour = 0; + if (minute == -1) minute = 0; + if (second == -1) second = 0; + + _year = year; + _month = month; + _day = day; + _seconds = (hour * 3600) + (minute * 60) + second; + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +bool ISO8601d::parse_named (Nibbler& n) +{ + n.save (); + std::string token; + if (n.getUntilWS (token)) + { + Variant v; + if (namedDates (token, v)) + { + _date = v.get_date (); + return true; + } + } + + n.restore (); + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// Valid epoch values are unsigned integers after 1980-01-01T00:00:00Z. This +// restriction means that '12' will not be identified as an epoch date. +bool ISO8601d::parse_epoch (Nibbler& n) +{ + n.save (); + + int epoch; + if (n.getUnsignedInt (epoch) && + n.depleted () && + epoch >= 315532800) + { + _date = static_cast (epoch); + return true; + } + + n.restore (); + return false; } //////////////////////////////////////////////////////////////////////////////// @@ -435,29 +849,19 @@ bool ISO8601d::parse_time_off_ext (Nibbler& n) 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 > 2200)) || - (_month && (_month < 1 || _month > 12)) || - (_week && (_week < 1 || _week > 53)) || - (_weekday && (_weekday < 0 || _weekday > 6)) || - (_julian && (_julian < 1 || _julian > Date::daysInYear (_year))) || - (_day && (_day < 1 || _day > Date::daysInMonth (_month, _year))) || - (_seconds && (_seconds < 1 || _seconds > 86400)) || - (_offset && (_offset < -86400 || _offset > 86400))) + if ((_year && (_year < 1900 || _year > 2200)) || + (_month && (_month < 1 || _month > 12)) || + (_week && (_week < 1 || _week > 53)) || + (_weekday && (_weekday < 0 || _weekday > 6)) || + (_julian && (_julian < 1 || _julian > ISO8601d::daysInYear (_year))) || + (_day && (_day < 1 || _day > ISO8601d::daysInMonth (_month, _year))) || + (_seconds && (_seconds < 1 || _seconds > 86400)) || + (_offset && (_offset < -86400 || _offset > 86400))) return false; return true; @@ -572,13 +976,628 @@ void ISO8601d::resolve () seconds %= 86400; } - t.tm_hour = seconds / 3600; - t.tm_min = (seconds % 3600) / 60; - t.tm_sec = seconds % 60; + t.tm_hour = seconds / 3600; + t.tm_min = (seconds % 3600) / 60; + t.tm_sec = seconds % 60; - _value = utc ? timegm (&t) : mktime (&t); + _date = utc ? timegm (&t) : mktime (&t); } +//////////////////////////////////////////////////////////////////////////////// +time_t ISO8601d::toEpoch () +{ + return _date; +} + +//////////////////////////////////////////////////////////////////////////////// +std::string ISO8601d::toEpochString () +{ + std::stringstream epoch; + epoch << _date; + return epoch.str (); +} + +//////////////////////////////////////////////////////////////////////////////// +// 19980119T070000Z = YYYYMMDDThhmmssZ +std::string ISO8601d::toISO () +{ + struct tm* t = gmtime (&_date); + + std::stringstream iso; + iso << std::setw (4) << std::setfill ('0') << t->tm_year + 1900 + << std::setw (2) << std::setfill ('0') << t->tm_mon + 1 + << std::setw (2) << std::setfill ('0') << t->tm_mday + << "T" + << std::setw (2) << std::setfill ('0') << t->tm_hour + << std::setw (2) << std::setfill ('0') << t->tm_min + << std::setw (2) << std::setfill ('0') << t->tm_sec + << "Z"; + + return iso.str (); +} + +//////////////////////////////////////////////////////////////////////////////// +double ISO8601d::toJulian () +{ + return (_date / 86400.0) + 2440587.5; +} + +//////////////////////////////////////////////////////////////////////////////// +void ISO8601d::toMDY (int& m, int& d, int& y) +{ + struct tm* t = localtime (&_date); + + m = t->tm_mon + 1; + d = t->tm_mday; + y = t->tm_year + 1900; +} + +//////////////////////////////////////////////////////////////////////////////// +const std::string ISO8601d::toString ( + const std::string& format /*= "m/d/Y" */) const +{ + // Making this local copy seems to fix a bug. Remove the local copy and + // you'll see segmentation faults and all kinds of gibberish. + std::string localFormat = format; + + char buffer[12]; + std::string formatted; + for (unsigned int i = 0; i < localFormat.length (); ++i) + { + int c = localFormat[i]; + switch (c) + { + case 'm': sprintf (buffer, "%d", this->month ()); break; + case 'M': sprintf (buffer, "%02d", this->month ()); break; + case 'd': sprintf (buffer, "%d", this->day ()); break; + case 'D': sprintf (buffer, "%02d", this->day ()); break; + case 'y': sprintf (buffer, "%02d", this->year () % 100); break; + case 'Y': sprintf (buffer, "%d", this->year ()); break; + case 'a': sprintf (buffer, "%.3s", ISO8601d::dayName (dayOfWeek ()).c_str ()); break; + case 'A': sprintf (buffer, "%.10s", ISO8601d::dayName (dayOfWeek ()).c_str ()); break; + case 'b': sprintf (buffer, "%.3s", ISO8601d::monthName (month ()).c_str ()); break; + case 'B': sprintf (buffer, "%.10s", ISO8601d::monthName (month ()).c_str ()); break; + case 'v': sprintf (buffer, "%d", ISO8601d::weekOfYear (ISO8601d::dayOfWeek (ISO8601d::weekstart))); break; + case 'V': sprintf (buffer, "%02d", ISO8601d::weekOfYear (ISO8601d::dayOfWeek (ISO8601d::weekstart))); break; + case 'h': sprintf (buffer, "%d", this->hour ()); break; + case 'H': sprintf (buffer, "%02d", this->hour ()); break; + case 'n': sprintf (buffer, "%d", this->minute ()); break; + case 'N': sprintf (buffer, "%02d", this->minute ()); break; + case 's': sprintf (buffer, "%d", this->second ()); break; + case 'S': sprintf (buffer, "%02d", this->second ()); break; + case 'j': sprintf (buffer, "%d", this->dayOfYear ()); break; + case 'J': sprintf (buffer, "%03d", this->dayOfYear ()); break; + default: sprintf (buffer, "%c", c); break; + } + + formatted += buffer; + } + + return formatted; +} + +//////////////////////////////////////////////////////////////////////////////// +ISO8601d ISO8601d::startOfDay () const +{ + return ISO8601d (month (), day (), year ()); +} + +//////////////////////////////////////////////////////////////////////////////// +ISO8601d ISO8601d::startOfWeek () const +{ + ISO8601d sow (_date); + sow -= (dayOfWeek () * 86400); + return ISO8601d (sow.month (), sow.day (), sow.year ()); +} + +//////////////////////////////////////////////////////////////////////////////// +ISO8601d ISO8601d::startOfMonth () const +{ + return ISO8601d (month (), 1, year ()); +} + +//////////////////////////////////////////////////////////////////////////////// +ISO8601d ISO8601d::startOfYear () const +{ + return ISO8601d (1, 1, year ()); +} + +//////////////////////////////////////////////////////////////////////////////// +bool ISO8601d::valid (const std::string& input, const std::string& format /*= ""*/) +{ + try + { + ISO8601d test (input, format); + } + + catch (...) + { + return false; + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +bool ISO8601d::valid (const int m, const int d, const int y, const int hr, + const int mi, const int se) +{ + if (hr < 0 || hr > 23) + return false; + + if (mi < 0 || mi > 59) + return false; + + if (se < 0 || se > 59) + return false; + + return ISO8601d::valid (m, d, y); +} + +//////////////////////////////////////////////////////////////////////////////// +bool ISO8601d::valid (const int m, const int d, const int y) +{ + // Check that the year is valid. + if (y < 0) + return false; + + // Check that the month is valid. + if (m < 1 || m > 12) + return false; + + // Finally check that the days fall within the acceptable range for this + // month, and whether or not this is a leap year. + if (d < 1 || d > ISO8601d::daysInMonth (m, y)) + return false; + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// Julian +bool ISO8601d::valid (const int d, const int y) +{ + // Check that the year is valid. + if (y < 0) + return false; + + if (d < 1 || d > ISO8601d::daysInYear (y)) + return false; + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// Static +bool ISO8601d::leapYear (int year) +{ + return ((! (year % 4)) && (year % 100)) || + ! (year % 400); +} + +//////////////////////////////////////////////////////////////////////////////// +// Static +int ISO8601d::daysInMonth (int month, int year) +{ + static int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + + if (month == 2 && ISO8601d::leapYear (year)) + return 29; + + return days[month - 1]; +} + +//////////////////////////////////////////////////////////////////////////////// +// Static +int ISO8601d::daysInYear (int year) +{ + return ISO8601d::leapYear (year) ? 366 : 365; +} + +//////////////////////////////////////////////////////////////////////////////// +// Static +std::string ISO8601d::monthName (int month) +{ + static const char* months[12] = + { + STRING_DATE_JANUARY, + STRING_DATE_FEBRUARY, + STRING_DATE_MARCH, + STRING_DATE_APRIL, + STRING_DATE_MAY, + STRING_DATE_JUNE, + STRING_DATE_JULY, + STRING_DATE_AUGUST, + STRING_DATE_SEPTEMBER, + STRING_DATE_OCTOBER, + STRING_DATE_NOVEMBER, + STRING_DATE_DECEMBER, + }; + + assert (month > 0); + assert (month <= 12); + return ucFirst (months[month - 1]); +} + +//////////////////////////////////////////////////////////////////////////////// +// Static +void ISO8601d::dayName (int dow, std::string& name) +{ + static const char* days[7] = + { + STRING_DATE_SUNDAY, + STRING_DATE_MONDAY, + STRING_DATE_TUESDAY, + STRING_DATE_WEDNESDAY, + STRING_DATE_THURSDAY, + STRING_DATE_FRIDAY, + STRING_DATE_SATURDAY, + }; + + name = ucFirst (days[dow]); +} + +//////////////////////////////////////////////////////////////////////////////// +// Static +std::string ISO8601d::dayName (int dow) +{ + static const char* days[7] = + { + STRING_DATE_SUNDAY, + STRING_DATE_MONDAY, + STRING_DATE_TUESDAY, + STRING_DATE_WEDNESDAY, + STRING_DATE_THURSDAY, + STRING_DATE_FRIDAY, + STRING_DATE_SATURDAY, + }; + + return ucFirst (days[dow]); +} + +//////////////////////////////////////////////////////////////////////////////// +// Static +int ISO8601d::dayOfWeek (const std::string& input) +{ + if (ISO8601d::minimumMatchLength== 0) + ISO8601d::minimumMatchLength= 3; + + if (closeEnough (STRING_DATE_SUNDAY, input, ISO8601d::minimumMatchLength)) return 0; + else if (closeEnough (STRING_DATE_MONDAY, input, ISO8601d::minimumMatchLength)) return 1; + else if (closeEnough (STRING_DATE_TUESDAY, input, ISO8601d::minimumMatchLength)) return 2; + else if (closeEnough (STRING_DATE_WEDNESDAY, input, ISO8601d::minimumMatchLength)) return 3; + else if (closeEnough (STRING_DATE_THURSDAY, input, ISO8601d::minimumMatchLength)) return 4; + else if (closeEnough (STRING_DATE_FRIDAY, input, ISO8601d::minimumMatchLength)) return 5; + else if (closeEnough (STRING_DATE_SATURDAY, input, ISO8601d::minimumMatchLength)) return 6; + + return -1; +} + +//////////////////////////////////////////////////////////////////////////////// +// Using Zeller's Congruence. +// Static +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; +} + +//////////////////////////////////////////////////////////////////////////////// +// Static +int ISO8601d::monthOfYear (const std::string& input) +{ + if (ISO8601d::minimumMatchLength== 0) + ISO8601d::minimumMatchLength= 3; + + if (closeEnough (STRING_DATE_JANUARY, input, ISO8601d::minimumMatchLength)) return 1; + else if (closeEnough (STRING_DATE_FEBRUARY, input, ISO8601d::minimumMatchLength)) return 2; + else if (closeEnough (STRING_DATE_MARCH, input, ISO8601d::minimumMatchLength)) return 3; + else if (closeEnough (STRING_DATE_APRIL, input, ISO8601d::minimumMatchLength)) return 4; + else if (closeEnough (STRING_DATE_MAY, input, ISO8601d::minimumMatchLength)) return 5; + else if (closeEnough (STRING_DATE_JUNE, input, ISO8601d::minimumMatchLength)) return 6; + else if (closeEnough (STRING_DATE_JULY, input, ISO8601d::minimumMatchLength)) return 7; + else if (closeEnough (STRING_DATE_AUGUST, input, ISO8601d::minimumMatchLength)) return 8; + else if (closeEnough (STRING_DATE_SEPTEMBER, input, ISO8601d::minimumMatchLength)) return 9; + else if (closeEnough (STRING_DATE_OCTOBER, input, ISO8601d::minimumMatchLength)) return 10; + else if (closeEnough (STRING_DATE_NOVEMBER, input, ISO8601d::minimumMatchLength)) return 11; + else if (closeEnough (STRING_DATE_DECEMBER, input, ISO8601d::minimumMatchLength)) return 12; + + return -1; +} + +//////////////////////////////////////////////////////////////////////////////// +// Static +int ISO8601d::length (const std::string& format) +{ + int len = 0; + for (auto& i : format) + { + switch (i) + { + case 'm': + case 'M': + case 'd': + case 'D': + case 'y': + case 'v': + case 'V': + case 'h': + case 'H': + case 'n': + case 'N': + case 's': + case 'S': len += 2; break; + case 'b': + case 'j': + case 'J': + case 'a': len += 3; break; + case 'Y': len += 4; break; + case 'A': + case 'B': len += 10; break; + + // Calculate the width, don't assume a single character width. + default: len += mk_wcwidth (i); break; + } + } + + return len; +} + +//////////////////////////////////////////////////////////////////////////////// +int ISO8601d::month () const +{ + struct tm* t = localtime (&_date); + return t->tm_mon + 1; +} + +//////////////////////////////////////////////////////////////////////////////// +int ISO8601d::week () const +{ + return ISO8601d::weekOfYear (ISO8601d::dayOfWeek (ISO8601d::weekstart)); +} + +//////////////////////////////////////////////////////////////////////////////// +int ISO8601d::day () const +{ + struct tm* t = localtime (&_date); + return t->tm_mday; +} + +//////////////////////////////////////////////////////////////////////////////// +int ISO8601d::year () const +{ + struct tm* t = localtime (&_date); + return t->tm_year + 1900; +} + +//////////////////////////////////////////////////////////////////////////////// +int ISO8601d::weekOfYear (int weekStart) const +{ + struct tm* t = localtime (&_date); + char weekStr[3]; + + if (weekStart == 0) + strftime(weekStr, sizeof(weekStr), "%U", t); + else if (weekStart == 1) + strftime(weekStr, sizeof(weekStr), "%V", t); + else + throw std::string (STRING_DATE_BAD_WEEKSTART); + + int weekNumber = atoi (weekStr); + + if (weekStart == 0) + weekNumber += 1; + + return weekNumber; +} + +//////////////////////////////////////////////////////////////////////////////// +int ISO8601d::dayOfWeek () const +{ + struct tm* t = localtime (&_date); + return t->tm_wday; +} + +//////////////////////////////////////////////////////////////////////////////// +int ISO8601d::dayOfYear () const +{ + struct tm* t = localtime (&_date); + return t->tm_yday + 1; +} + +//////////////////////////////////////////////////////////////////////////////// +int ISO8601d::hour () const +{ + struct tm* t = localtime (&_date); + return t->tm_hour; +} + +//////////////////////////////////////////////////////////////////////////////// +int ISO8601d::minute () const +{ + struct tm* t = localtime (&_date); + return t->tm_min; +} + +//////////////////////////////////////////////////////////////////////////////// +int ISO8601d::second () const +{ + struct tm* t = localtime (&_date); + return t->tm_sec; +} + +//////////////////////////////////////////////////////////////////////////////// +bool ISO8601d::operator== (const ISO8601d& rhs) const +{ + return rhs._date == _date; +} + +//////////////////////////////////////////////////////////////////////////////// +bool ISO8601d::operator!= (const ISO8601d& rhs) const +{ + return rhs._date != _date; +} + +//////////////////////////////////////////////////////////////////////////////// +bool ISO8601d::operator< (const ISO8601d& rhs) const +{ + return _date < rhs._date; +} + +//////////////////////////////////////////////////////////////////////////////// +bool ISO8601d::operator> (const ISO8601d& rhs) const +{ + return _date > rhs._date; +} + +//////////////////////////////////////////////////////////////////////////////// +bool ISO8601d::operator<= (const ISO8601d& rhs) const +{ + return _date <= rhs._date; +} + +//////////////////////////////////////////////////////////////////////////////// +bool ISO8601d::operator>= (const ISO8601d& rhs) const +{ + return _date >= rhs._date; +} + +//////////////////////////////////////////////////////////////////////////////// +bool ISO8601d::sameHour (const ISO8601d& rhs) const +{ + return this->year () == rhs.year () && + this->month () == rhs.month () && + this->day () == rhs.day () && + this->hour () == rhs.hour (); +} + +//////////////////////////////////////////////////////////////////////////////// +bool ISO8601d::sameDay (const ISO8601d& rhs) const +{ + return this->year () == rhs.year () && + this->month () == rhs.month () && + this->day () == rhs.day (); +} + +//////////////////////////////////////////////////////////////////////////////// +bool ISO8601d::sameWeek (const ISO8601d& rhs) const +{ + return this->year () == rhs.year () && + this->week () == rhs.week (); +} + +//////////////////////////////////////////////////////////////////////////////// +bool ISO8601d::sameMonth (const ISO8601d& rhs) const +{ + return this->year () == rhs.year () && + this->month () == rhs.month (); +} + +//////////////////////////////////////////////////////////////////////////////// +bool ISO8601d::sameYear (const ISO8601d& rhs) const +{ + return this->year () == rhs.year (); +} + +//////////////////////////////////////////////////////////////////////////////// +ISO8601d ISO8601d::operator+ (time_t delta) +{ + return ISO8601d (_date + delta); +} + +//////////////////////////////////////////////////////////////////////////////// +ISO8601d ISO8601d::operator+ (const int delta) +{ + return ISO8601d (_date + delta); +} + +//////////////////////////////////////////////////////////////////////////////// +ISO8601d ISO8601d::operator- (const int delta) +{ + return ISO8601d (_date - delta); +} + +//////////////////////////////////////////////////////////////////////////////// +ISO8601d& ISO8601d::operator+= (const int delta) +{ + _date += (time_t) delta; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +ISO8601d& ISO8601d::operator-= (const int delta) +{ + _date -= (time_t) delta; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +time_t ISO8601d::operator- (const ISO8601d& rhs) +{ + return _date - rhs._date; +} + +//////////////////////////////////////////////////////////////////////////////// +// Prefix decrement by one day. +void ISO8601d::operator-- () +{ + ISO8601d yesterday = startOfDay () - 1; + yesterday = ISO8601d (yesterday.month (), + yesterday.day (), + yesterday.year (), + hour (), + minute (), + second ()); + _date = yesterday._date; +} + +//////////////////////////////////////////////////////////////////////////////// +// Postfix decrement by one day. +void ISO8601d::operator-- (int) +{ + ISO8601d yesterday = startOfDay () - 1; + yesterday = ISO8601d (yesterday.month (), + yesterday.day (), + yesterday.year (), + hour (), + minute (), + second ()); + _date = yesterday._date; +} + +//////////////////////////////////////////////////////////////////////////////// +// Prefix increment by one day. +void ISO8601d::operator++ () +{ + ISO8601d tomorrow = (startOfDay () + 90001).startOfDay (); + tomorrow = ISO8601d (tomorrow.month (), + tomorrow.day (), + tomorrow.year (), + hour (), + minute (), + second ()); + _date = tomorrow._date; +} + +//////////////////////////////////////////////////////////////////////////////// +// Postfix increment by one day. +void ISO8601d::operator++ (int) +{ + ISO8601d tomorrow = (startOfDay () + 90001).startOfDay (); + tomorrow = ISO8601d (tomorrow.month (), + tomorrow.day (), + tomorrow.year (), + hour (), + minute (), + second ()); + _date = tomorrow._date; +} + + + + //////////////////////////////////////////////////////////////////////////////// ISO8601p::ISO8601p () { @@ -589,7 +1608,7 @@ ISO8601p::ISO8601p () ISO8601p::ISO8601p (time_t input) { clear (); - _value = input; + _period = input; } //////////////////////////////////////////////////////////////////////////////// @@ -602,7 +1621,7 @@ ISO8601p::ISO8601p (const std::string& input) time_t value = (time_t) strtol (input.c_str (), NULL, 10); if (value == 0 || value > 60) { - _value = value; + _period = value; return; } } @@ -627,7 +1646,7 @@ ISO8601p& ISO8601p::operator= (const ISO8601p& other) _hours = other._hours; _minutes = other._minutes; _seconds = other._seconds; - _value = other._value; + _period = other._period; } return *this; @@ -636,27 +1655,27 @@ ISO8601p& ISO8601p::operator= (const ISO8601p& other) //////////////////////////////////////////////////////////////////////////////// bool ISO8601p::operator< (const ISO8601p& other) { - return _value < other._value; + return _period < other._period; } //////////////////////////////////////////////////////////////////////////////// bool ISO8601p::operator> (const ISO8601p& other) { - return _value > other._value; + return _period > other._period; } //////////////////////////////////////////////////////////////////////////////// ISO8601p::operator std::string () const { std::stringstream s; - s << _value; + s << _period; return s.str (); } //////////////////////////////////////////////////////////////////////////////// ISO8601p::operator time_t () const { - return _value; + return _period; } //////////////////////////////////////////////////////////////////////////////// @@ -729,7 +1748,7 @@ bool ISO8601p::parse (const std::string& input, std::string::size_type& start) if (durations[i].unit == unit && durations[i].standalone == true) { - _value = static_cast (durations[i].seconds); + _period = static_cast (durations[i].seconds); return true; } } @@ -778,7 +1797,7 @@ bool ISO8601p::parse (const std::string& input, std::string::size_type& start) if (durations[i].unit == unit) { seconds = durations[i].seconds; - _value = static_cast (quantity * static_cast (seconds)); + _period = static_cast (quantity * static_cast (seconds)); return true; } } @@ -798,15 +1817,15 @@ void ISO8601p::clear () _hours = 0; _minutes = 0; _seconds = 0; - _value = 0; + _period = 0; } //////////////////////////////////////////////////////////////////////////////// const std::string ISO8601p::format () const { - if (_value) + if (_period) { - time_t t = _value; + time_t t = _period; int seconds = t % 60; t /= 60; int minutes = t % 60; t /= 60; int hours = t % 24; t /= 24; @@ -836,15 +1855,15 @@ const std::string ISO8601p::format () const const std::string ISO8601p::formatVague () const { char formatted[24]; - float days = (float) _value / 86400.0; + float days = (float) _period / 86400.0; - if (_value >= 86400 * 365) sprintf (formatted, "%.1fy", (days / 365.0)); - else if (_value >= 86400 * 84) sprintf (formatted, "%1dmo", (int) (days / 30)); - else if (_value >= 86400 * 13) sprintf (formatted, "%dw", (int) (float) (days / 7.0)); - else if (_value >= 86400) sprintf (formatted, "%dd", (int) days); - else if (_value >= 3600) sprintf (formatted, "%dh", (int) (_value / 3600)); - else if (_value >= 60) sprintf (formatted, "%dmin", (int) (_value / 60)); - else if (_value >= 1) sprintf (formatted, "%ds", (int) _value); + if (_period >= 86400 * 365) sprintf (formatted, "%.1fy", (days / 365.0)); + else if (_period >= 86400 * 84) sprintf (formatted, "%1dmo", (int) (days / 30)); + else if (_period >= 86400 * 13) sprintf (formatted, "%dw", (int) (float) (days / 7.0)); + else if (_period >= 86400) sprintf (formatted, "%dd", (int) days); + else if (_period >= 3600) sprintf (formatted, "%dh", (int) (_period / 3600)); + else if (_period >= 60) sprintf (formatted, "%dmin", (int) (_period / 60)); + else if (_period >= 1) sprintf (formatted, "%ds", (int) _period); else formatted[0] = '\0'; return std::string (formatted); @@ -920,12 +1939,12 @@ bool ISO8601p::validate () // Allow un-normalized values. void ISO8601p::resolve () { - _value = (_year * 365 * 86400) + - (_month * 30 * 86400) + - (_day * 86400) + - (_hours * 3600) + - (_minutes * 60) + - _seconds; + _period = (_year * 365 * 86400) + + (_month * 30 * 86400) + + (_day * 86400) + + (_hours * 3600) + + (_minutes * 60) + + _seconds; } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/ISO8601.h b/src/ISO8601.h index 9a6b60e79..b336ccb15 100644 --- a/src/ISO8601.h +++ b/src/ISO8601.h @@ -23,6 +23,7 @@ // http://www.opensource.org/licenses/mit-license.php // //////////////////////////////////////////////////////////////////////////////// + #ifndef INCLUDED_ISO8601 #define INCLUDED_ISO8601 @@ -33,15 +34,84 @@ class ISO8601d { public: + static std::string weekstart; + static int minimumMatchLength; + static bool isoEnabled; + ISO8601d (); + ISO8601d (const std::string&, const std::string& format = ""); + ISO8601d (time_t); + ISO8601d (const int, const int, const int); + ISO8601d (const int, const int, const int, const int, const int, const int); ~ISO8601d (); - ISO8601d (const ISO8601d&); // Unimplemented - ISO8601d& operator= (const ISO8601d&); // Unimplemented operator time_t () const; - bool parse (const std::string&, std::string::size_type&); - void clear (); + bool parse (const std::string&, std::string::size_type&, const std::string& format = ""); + + time_t toEpoch (); + std::string toEpochString (); + std::string toISO (); + double toJulian (); + void toMDY (int&, int&, int&); + const std::string toString (const std::string& format = "m/d/Y") const; + + ISO8601d startOfDay () const; + ISO8601d startOfWeek () const; + ISO8601d startOfMonth () const; + ISO8601d startOfYear () const; + + static bool valid (const std::string&, const std::string& format = ""); + static bool valid (const int, const int, const int, const int, const int, const int); + static bool valid (const int, const int, const int); + static bool valid (const int, const int); + static bool leapYear (int); + static int daysInMonth (int, int); + static int daysInYear (int); + static std::string monthName (int); + static void dayName (int, std::string&); + static std::string dayName (int); + static int dayOfWeek (const std::string&); + static int dayOfWeek (int, int, int); + static int monthOfYear (const std::string&); + static int length (const std::string&); + + int month () const; + int week () const; + int day () const; + int year () const; + int weekOfYear (int) const; + int dayOfWeek () const; + int dayOfYear () const; + int hour () const; + int minute () const; + int second () const; + + bool operator== (const ISO8601d&) const; + bool operator!= (const ISO8601d&) const; + bool operator< (const ISO8601d&) const; + bool operator> (const ISO8601d&) const; + bool operator<= (const ISO8601d&) const; + bool operator>= (const ISO8601d&) const; + bool sameHour (const ISO8601d&) const; + bool sameDay (const ISO8601d&) const; + bool sameWeek (const ISO8601d&) const; + bool sameMonth (const ISO8601d&) const; + bool sameYear (const ISO8601d&) const; + ISO8601d operator+ (time_t); + ISO8601d operator+ (const int); + ISO8601d operator- (const int); + ISO8601d& operator+= (const int); + ISO8601d& operator-= (const int); + time_t operator- (const ISO8601d&); + void operator-- (); // Prefix + void operator-- (int); // Postfix + void operator++ (); // Prefix + void operator++ (int); // Postfix private: + void clear (); + bool parse_formatted (Nibbler&, const std::string&); + bool parse_named (Nibbler&); + bool parse_epoch (Nibbler&); bool parse_date_time (Nibbler&); bool parse_date_time_ext (Nibbler&); bool parse_date_ext (Nibbler&); @@ -49,7 +119,6 @@ private: bool parse_time_ext (Nibbler&); bool parse_time_utc_ext (Nibbler&); bool parse_time_off_ext (Nibbler&); - int dayOfWeek (int, int, int); bool validate (); void resolve (); @@ -63,13 +132,15 @@ public: int _seconds; int _offset; bool _utc; - time_t _value; + time_t _date; }; // Period class ISO8601p { public: + static bool isoEnabled; + ISO8601p (); ISO8601p (time_t); ISO8601p (const std::string&); @@ -81,11 +152,11 @@ public: operator std::string () const; operator time_t () const; bool parse (const std::string&, std::string::size_type&); - void clear (); const std::string format () const; const std::string formatVague () const; private: + void clear (); bool parse_designated (Nibbler&); bool validate (); void resolve (); @@ -97,11 +168,9 @@ public: int _hours; int _minutes; int _seconds; - time_t _value; + time_t _period; }; -// TODO Recurrence - #endif //////////////////////////////////////////////////////////////////////////////// diff --git a/src/Lexer.cpp b/src/Lexer.cpp index 93a74a34a..2c7f04df3 100644 --- a/src/Lexer.cpp +++ b/src/Lexer.cpp @@ -28,14 +28,12 @@ #include #include #include -#include #include static const std::string uuid_pattern = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; static const unsigned int uuid_min_length = 8; std::string Lexer::dateFormat = ""; -bool Lexer::isoEnabled = true; std::string::size_type Lexer::minimumMatchLength = 3; std::map Lexer::attributes; @@ -432,38 +430,18 @@ bool Lexer::isString (std::string& token, Lexer::Type& type, const std::string& //////////////////////////////////////////////////////////////////////////////// // Lexer::Type::date -// | +// bool Lexer::isDate (std::string& token, Lexer::Type& type) { // Try an ISO date parse. - if (Lexer::isoEnabled) + std::size_t iso_i = 0; + ISO8601d iso; + if (iso.parse (_text.substr (_cursor), iso_i, Lexer::dateFormat)) { - std::size_t iso_i = 0; - ISO8601d iso; - if (iso.parse (_text.substr (_cursor), iso_i)) - { - type = Lexer::Type::date; - token = _text.substr (_cursor, iso_i); - _cursor += iso_i; - return true; - } - } - - // Try a legacy rc.dateformat parse here. - if (Lexer::dateFormat != "") - { - try - { - std::size_t legacy_i = 0; - Date legacyDate (_text.substr (_cursor), legacy_i, Lexer::dateFormat, false, false); - - type = Lexer::Type::date; - token = _text.substr (_cursor, legacy_i); - _cursor += legacy_i; - return true; - } - - catch (...) { /* Never mind. */ } + type = Lexer::Type::date; + token = _text.substr (_cursor, iso_i); + _cursor += iso_i; + return true; } return false; diff --git a/src/Lexer.h b/src/Lexer.h index 1cb7aab0c..9aa510596 100644 --- a/src/Lexer.h +++ b/src/Lexer.h @@ -40,7 +40,6 @@ class Lexer public: // These are overridable. static std::string dateFormat; - static bool isoEnabled; static std::string::size_type minimumMatchLength; static std::map attributes; diff --git a/src/Nibbler.cpp b/src/Nibbler.cpp index 88d7b9f32..3261fa2d7 100644 --- a/src/Nibbler.cpp +++ b/src/Nibbler.cpp @@ -33,7 +33,7 @@ #include #include #ifdef NIBBLER_FEATURE_DATE -#include +#include #endif #ifdef NIBBLER_FEATURE_REGEX #include @@ -708,7 +708,8 @@ bool Nibbler::getDateISO (time_t& t) // Parse the longest integer using the next 'limit' characters of 'result' // following position 'i' (when strict is true, the number of digits must be // equal to limit). -bool Nibbler::parseDigits(std::string::size_type& i, +bool Nibbler::parseDigits( + std::string::size_type& i, int& result, unsigned int limit, bool strict /* = true */) @@ -819,8 +820,8 @@ bool Nibbler::getDate (const std::string& format, time_t& t) ! Lexer::isDigit ((*_input)[i + 1]) && ! Lexer::isDigit ((*_input)[i + 2])) { - wday = Date::dayOfWeek (_input->substr (i, 3).c_str ()); - i += (format[f] == 'a') ? 3 : Date::dayName (wday).size (); + wday = ISO8601d::dayOfWeek (_input->substr (i, 3).c_str ()); + i += (format[f] == 'a') ? 3 : ISO8601d::dayName (wday).size (); } else return false; @@ -835,8 +836,8 @@ bool Nibbler::getDate (const std::string& format, time_t& t) { if (month != -1) return false; - month = Date::monthOfYear (_input->substr (i, 3).c_str()); - i += (format[f] == 'b') ? 3 : Date::monthName (month).size (); + month = ISO8601d::monthOfYear (_input->substr (i, 3).c_str()); + i += (format[f] == 'b') ? 3 : ISO8601d::monthName (month).size (); } else return false; @@ -858,7 +859,7 @@ bool Nibbler::getDate (const std::string& format, time_t& t) // now. if (year == -1) { - Date now = Date (); + ISO8601d now; year = now.year (); if (month == -1) { @@ -889,7 +890,7 @@ bool Nibbler::getDate (const std::string& format, time_t& t) second = (second == -1) ? 0 : second; // Check that values are correct - if (! Date::valid (month, day, year, hour, minute, second)) + if (! ISO8601d::valid (month, day, year, hour, minute, second)) return false; // Convert to epoch. diff --git a/src/Nibbler.h b/src/Nibbler.h index 1fda8ac76..b3754aa5a 100644 --- a/src/Nibbler.h +++ b/src/Nibbler.h @@ -57,10 +57,6 @@ public: bool getUntilEOL (std::string&); bool getUntilEOS (std::string&); -/* - bool getAllOneOf (const std::string&, std::string&); -*/ - bool getN (const int, std::string&); bool getQuoted (char, std::string&, bool quote = false); bool getDigit (int&); diff --git a/src/TDB2.cpp b/src/TDB2.cpp index 6a82f10f1..0148a51e6 100644 --- a/src/TDB2.cpp +++ b/src/TDB2.cpp @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include @@ -638,7 +638,7 @@ void TDB2::update ( // old // new // --- - undo.add_line ("time " + Date ().toEpochString () + "\n"); + undo.add_line ("time " + ISO8601d ().toEpochString () + "\n"); undo.add_line ("old " + original.composeF4 () + "\n"); undo.add_line ("new " + task.composeF4 () + "\n"); undo.add_line ("---\n"); @@ -657,7 +657,7 @@ void TDB2::update ( // time