mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
From: Paul Beckingham <paul@beckingham.net>
Date: Sun, 28 Feb 2010 12:10:06 -0500 Subject: [PATCH] Enhancement - time support in the Date object. - Added ability to parse and display time, using: h - single digit hour H - double digit hour N - double digit minutes S - double digit seconds - Added a request for mktime() to automatically determine whether summer time should be considered. - Added Date::Date (m, d, y, hr, mi, se) constructor. - Added Date::sameHour comparison method. - Added unit tests.
This commit is contained in:
parent
dbf8def7db
commit
70da455f1a
3 changed files with 167 additions and 11 deletions
135
src/Date.cpp
135
src/Date.cpp
|
@ -55,9 +55,27 @@ Date::Date (const int m, const int d, const int y)
|
||||||
{
|
{
|
||||||
// Error if not valid.
|
// Error if not valid.
|
||||||
struct tm t = {0};
|
struct tm t = {0};
|
||||||
t.tm_mday = d;
|
t.tm_isdst = -1; // Requests that mktime determine summer time effect.
|
||||||
t.tm_mon = m - 1;
|
t.tm_mday = d;
|
||||||
t.tm_year = y - 1900;
|
t.tm_mon = m - 1;
|
||||||
|
t.tm_year = y - 1900;
|
||||||
|
|
||||||
|
mT = 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;
|
||||||
|
|
||||||
mT = mktime (&t);
|
mT = mktime (&t);
|
||||||
}
|
}
|
||||||
|
@ -65,9 +83,12 @@ Date::Date (const int m, const int d, const int y)
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
Date::Date (const std::string& mdy, const std::string& format /* = "m/d/Y" */)
|
Date::Date (const std::string& mdy, const std::string& format /* = "m/d/Y" */)
|
||||||
{
|
{
|
||||||
int month = 0;
|
int month = 0;
|
||||||
int day = 0;
|
int day = 0;
|
||||||
int year = 0;
|
int year = 0;
|
||||||
|
int hour = 0;
|
||||||
|
int minute = 0;
|
||||||
|
int second = 0;
|
||||||
|
|
||||||
// Perhaps it is an epoch date, in string form?
|
// Perhaps it is an epoch date, in string form?
|
||||||
if (isEpoch (mdy))
|
if (isEpoch (mdy))
|
||||||
|
@ -241,6 +262,64 @@ Date::Date (const std::string& mdy, const std::string& format /* = "m/d/Y" */)
|
||||||
i += Date::monthName(month).size();
|
i += Date::monthName(month).size();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// Single or double digit.
|
||||||
|
case 'h':
|
||||||
|
if (i >= mdy.length () ||
|
||||||
|
! isdigit (mdy[i]))
|
||||||
|
{
|
||||||
|
throw std::string ("\"") + mdy + "\" is not a valid date (h).";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i + 1 < mdy.length () &&
|
||||||
|
(mdy[i + 0] == '0' || mdy[i + 0] == '1' || mdy[i + 0] == '2') &&
|
||||||
|
isdigit (mdy[i + 1]))
|
||||||
|
{
|
||||||
|
hour = atoi (mdy.substr (i, 2).c_str ());
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hour = atoi (mdy.substr (i, 1).c_str ());
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'H':
|
||||||
|
if (i + 1 >= mdy.length () ||
|
||||||
|
! isdigit (mdy[i + 0]) ||
|
||||||
|
! isdigit (mdy[i + 1]))
|
||||||
|
{
|
||||||
|
throw std::string ("\"") + mdy + "\" is not a valid date (H).";
|
||||||
|
}
|
||||||
|
|
||||||
|
hour = atoi (mdy.substr (i, 2).c_str ());
|
||||||
|
i += 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'N':
|
||||||
|
if (i + 1 >= mdy.length () ||
|
||||||
|
! isdigit (mdy[i + 0]) ||
|
||||||
|
! isdigit (mdy[i + 1]))
|
||||||
|
{
|
||||||
|
throw std::string ("\"") + mdy + "\" is not a valid date (N).";
|
||||||
|
}
|
||||||
|
|
||||||
|
minute = atoi (mdy.substr (i, 2).c_str ());
|
||||||
|
i += 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'S':
|
||||||
|
if (i + 1 >= mdy.length () ||
|
||||||
|
! isdigit (mdy[i + 0]) ||
|
||||||
|
! isdigit (mdy[i + 1]))
|
||||||
|
{
|
||||||
|
throw std::string ("\"") + mdy + "\" is not a valid date (S).";
|
||||||
|
}
|
||||||
|
|
||||||
|
second = atoi (mdy.substr (i, 2).c_str ());
|
||||||
|
i += 2;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (i >= mdy.length () ||
|
if (i >= mdy.length () ||
|
||||||
mdy[i] != format[f])
|
mdy[i] != format[f])
|
||||||
|
@ -258,11 +337,15 @@ Date::Date (const std::string& mdy, const std::string& format /* = "m/d/Y" */)
|
||||||
if (!valid (month, day, year))
|
if (!valid (month, day, year))
|
||||||
throw std::string ("\"") + mdy + "\" is not a valid date (VALID).";
|
throw std::string ("\"") + mdy + "\" is not a valid date (VALID).";
|
||||||
|
|
||||||
// Duplicate Date::Date (const int, const int, const int);
|
// Convert to epoch.
|
||||||
struct tm t = {0};
|
struct tm t = {0};
|
||||||
t.tm_mday = day;
|
t.tm_isdst = -1; // Requests that mktime determine summer time effect.
|
||||||
t.tm_mon = month - 1;
|
t.tm_mday = day;
|
||||||
t.tm_year = year - 1900;
|
t.tm_mon = month - 1;
|
||||||
|
t.tm_year = year - 1900;
|
||||||
|
t.tm_hour = hour;
|
||||||
|
t.tm_min = minute;
|
||||||
|
t.tm_sec = second;
|
||||||
|
|
||||||
mT = mktime (&t);
|
mT = mktime (&t);
|
||||||
}
|
}
|
||||||
|
@ -333,6 +416,10 @@ const std::string Date::toString (const std::string& format /*= "m/d/Y" */) cons
|
||||||
case 'b': sprintf (buffer, "%.3s", Date::monthName (month ()).c_str ()); break;
|
case 'b': sprintf (buffer, "%.3s", Date::monthName (month ()).c_str ()); break;
|
||||||
case 'B': sprintf (buffer, "%.9s", Date::monthName (month ()).c_str ()); break;
|
case 'B': sprintf (buffer, "%.9s", Date::monthName (month ()).c_str ()); break;
|
||||||
case 'V': sprintf (buffer, "%02d", 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, "%02d", this->minute ()); break;
|
||||||
|
case 'S': sprintf (buffer, "%02d", this->second ()); break;
|
||||||
default: sprintf (buffer, "%c", c); break;
|
default: sprintf (buffer, "%c", c); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,6 +458,22 @@ bool Date::valid (const std::string& input, const std::string& format)
|
||||||
return true;
|
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)
|
bool Date::valid (const int m, const int d, const int y)
|
||||||
{
|
{
|
||||||
|
@ -618,6 +721,18 @@ bool Date::operator>= (const Date& rhs)
|
||||||
return mT >= rhs.mT;
|
return mT >= rhs.mT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool Date::sameHour (const Date& rhs)
|
||||||
|
{
|
||||||
|
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)
|
bool Date::sameDay (const Date& rhs)
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,6 +38,7 @@ public:
|
||||||
Date ();
|
Date ();
|
||||||
Date (time_t);
|
Date (time_t);
|
||||||
Date (const int, const int, const int);
|
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");
|
Date (const std::string&, const std::string& format = "m/d/Y");
|
||||||
Date (const Date&);
|
Date (const Date&);
|
||||||
virtual ~Date ();
|
virtual ~Date ();
|
||||||
|
@ -49,6 +50,7 @@ public:
|
||||||
const std::string toString (const std::string& format = "m/d/Y") const;
|
const std::string toString (const std::string& format = "m/d/Y") const;
|
||||||
const std::string toStringWithTime (const std::string& format = "m/d/Y") const;
|
const std::string toStringWithTime (const std::string& format = "m/d/Y") const;
|
||||||
static bool valid (const std::string&, const std::string& format = "m/d/Y");
|
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, const int);
|
||||||
|
|
||||||
static bool leapYear (int);
|
static bool leapYear (int);
|
||||||
|
@ -75,6 +77,7 @@ public:
|
||||||
bool operator> (const Date&);
|
bool operator> (const Date&);
|
||||||
bool operator<= (const Date&);
|
bool operator<= (const Date&);
|
||||||
bool operator>= (const Date&);
|
bool operator>= (const Date&);
|
||||||
|
bool sameHour (const Date&);
|
||||||
bool sameDay (const Date&);
|
bool sameDay (const Date&);
|
||||||
bool sameMonth (const Date&);
|
bool sameMonth (const Date&);
|
||||||
bool sameYear (const Date&);
|
bool sameYear (const Date&);
|
||||||
|
|
|
@ -34,7 +34,7 @@ Context context;
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
int main (int argc, char** argv)
|
int main (int argc, char** argv)
|
||||||
{
|
{
|
||||||
UnitTest t (111);
|
UnitTest t (135);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -78,6 +78,12 @@ int main (int argc, char** argv)
|
||||||
t.ok (Date::valid ("2/29/2008"), "valid: 2/29/2008");
|
t.ok (Date::valid ("2/29/2008"), "valid: 2/29/2008");
|
||||||
t.notok (Date::valid ("2/29/2007"), "invalid: 2/29/2007");
|
t.notok (Date::valid ("2/29/2007"), "invalid: 2/29/2007");
|
||||||
|
|
||||||
|
// Time validity.
|
||||||
|
t.ok (Date::valid (2, 28, 2010, 0, 0, 0), "valid 2/28/2010 0:00:00");
|
||||||
|
t.ok (Date::valid (2, 28, 2010, 23, 59, 59), "valid 2/28/2010 23:59:59");
|
||||||
|
t.notok (Date::valid (2, 28, 2010, 24, 59, 59), "valid 2/28/2010 24:59:59");
|
||||||
|
t.notok (Date::valid (2, 28, 2010, -1, 0, 0), "valid 2/28/2010 -1:00:00");
|
||||||
|
|
||||||
// Leap year.
|
// Leap year.
|
||||||
t.ok (Date::leapYear (2008), "2008 is a leap year");
|
t.ok (Date::leapYear (2008), "2008 is a leap year");
|
||||||
t.notok (Date::leapYear (2007), "2007 is not a leap year");
|
t.notok (Date::leapYear (2007), "2007 is not a leap year");
|
||||||
|
@ -195,6 +201,30 @@ int main (int argc, char** argv)
|
||||||
t.is (fromString10.day (), 1, "ctor (std::string) -> d");
|
t.is (fromString10.day (), 1, "ctor (std::string) -> d");
|
||||||
t.is (fromString10.year (), 2008, "ctor (std::string) -> y");
|
t.is (fromString10.year (), 2008, "ctor (std::string) -> y");
|
||||||
|
|
||||||
|
Date fromString11 ("6/7/2010 1:23:45", "m/d/Y h:N:S");
|
||||||
|
t.is (fromString11.month (), 6, "ctor (std::string) -> m");
|
||||||
|
t.is (fromString11.day (), 7, "ctor (std::string) -> d");
|
||||||
|
t.is (fromString11.year (), 2010, "ctor (std::string) -> Y");
|
||||||
|
t.is (fromString11.hour (), 1, "ctor (std::string) -> h");
|
||||||
|
t.is (fromString11.minute (), 23, "ctor (std::string) -> N");
|
||||||
|
t.is (fromString11.second (), 45, "ctor (std::string) -> S");
|
||||||
|
|
||||||
|
Date fromString12 ("6/7/2010 01:23:45", "m/d/Y H:N:S");
|
||||||
|
t.is (fromString12.month (), 6, "ctor (std::string) -> m");
|
||||||
|
t.is (fromString12.day (), 7, "ctor (std::string) -> d");
|
||||||
|
t.is (fromString12.year (), 2010, "ctor (std::string) -> Y");
|
||||||
|
t.is (fromString12.hour (), 1, "ctor (std::string) -> h");
|
||||||
|
t.is (fromString12.minute (), 23, "ctor (std::string) -> N");
|
||||||
|
t.is (fromString12.second (), 45, "ctor (std::string) -> S");
|
||||||
|
|
||||||
|
Date fromString13 ("6/7/2010 12:34:56", "m/d/Y H:N:S");
|
||||||
|
t.is (fromString13.month (), 6, "ctor (std::string) -> m");
|
||||||
|
t.is (fromString13.day (), 7, "ctor (std::string) -> d");
|
||||||
|
t.is (fromString13.year (), 2010, "ctor (std::string) -> Y");
|
||||||
|
t.is (fromString13.hour (), 12, "ctor (std::string) -> h");
|
||||||
|
t.is (fromString13.minute (), 34, "ctor (std::string) -> N");
|
||||||
|
t.is (fromString13.second (), 56, "ctor (std::string) -> S");
|
||||||
|
|
||||||
// Relative dates.
|
// Relative dates.
|
||||||
Date r1 ("today");
|
Date r1 ("today");
|
||||||
t.ok (r1.sameDay (now), "today = now");
|
t.ok (r1.sameDay (now), "today = now");
|
||||||
|
@ -255,6 +285,14 @@ int main (int argc, char** argv)
|
||||||
|
|
||||||
Date r13 ("eoy");
|
Date r13 ("eoy");
|
||||||
t.ok (r13.sameYear (now), "eoy in same year as now");
|
t.ok (r13.sameYear (now), "eoy in same year as now");
|
||||||
|
|
||||||
|
// Date::sameHour
|
||||||
|
Date r14 ("6/7/2010 01:00:00", "m/d/Y H:N:S");
|
||||||
|
Date r15 ("6/7/2010 01:59:59", "m/d/Y H:N:S");
|
||||||
|
t.ok (r14.sameHour (r15), "two dates within the same hour");
|
||||||
|
|
||||||
|
Date r16 ("6/7/2010 00:59:59", "m/d/Y H:N:S");
|
||||||
|
t.notok (r14.sameHour (r16), "two dates not within the same hour");
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (std::string& e)
|
catch (std::string& e)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue