From e8b7114ce819dc2e3250b715cbb2567542a68004 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Sat, 7 Jun 2008 17:09:09 -0400 Subject: [PATCH] - Added the ability to control date formats via the 'dateformat' configuration variable. --- TUTORIAL | 29 ++++++- src/Date.cpp | 71 ++++++++++++++-- src/Date.h | 3 +- src/task.cpp | 84 +++++-------------- src/tests/date.t.cpp | 87 ++++++++++++++++++++ task.html | 192 ++++++++++++++++++++++++++++++++++++------- 6 files changed, 361 insertions(+), 105 deletions(-) create mode 100644 src/tests/date.t.cpp diff --git a/TUTORIAL b/TUTORIAL index ef7a9e5d9..a7d8fa47e 100644 --- a/TUTORIAL +++ b/TUTORIAL @@ -21,10 +21,10 @@ Build the task program according to the directions in the INSTALL file. This transcript illustrates a typical installation: % ls - task-1.0.1.tar.gz + task-1.1.0.tar.gz % gunzip task-1.1.0.tar.gz % tar xf task-1.1.0.tar - % cd task-1.0.1 + % cd task-1.1.0 % ./configure ... % make @@ -625,6 +625,31 @@ Configuring Task unnecessary blank lines so that task makes better use screen real estate on small-screened devices. + dateformat This is a string of characters that define how task + formats dates. The default value is: + + m/d/Y + + which means dates look like: + + 6/7/2008 + + The string should contain the characters: + + m minimal-digit month 1, 12 + d minimal-digit day 1, 30 + y two-digit year 08 + M two-digit month 01, 12 + D two-digit day 01, 30 + Y four-digit year 2008 + + The string may also contain other characters to act as + spacers, or formatting. Other values could include: + + d/m/Y 7/6/2008 + YMD 20080607 + m-d-y 6-7-08 + color May be "on" or "off". Determines whether task uses color. diff --git a/src/Date.cpp b/src/Date.cpp index e37d880de..202d5d144 100644 --- a/src/Date.cpp +++ b/src/Date.cpp @@ -116,20 +116,77 @@ void Date::toMDY (int& m, int& d, int& y) } //////////////////////////////////////////////////////////////////////////////// -void Date::toString (std::string& output) -{ - output = toString (); -} - -//////////////////////////////////////////////////////////////////////////////// -std::string Date::toString (void) +std::string Date::toString (const std::string& format /*= "m/d/Y"*/) { +/* int m, d, y; toMDY (m, d, y); char formatted [11]; sprintf (formatted, "%d/%d/%d", m, d, y); return std::string (formatted); +*/ + + std::string formatted; + for (unsigned int i = 0; i < format.length (); ++i) + { + switch (format[i]) + { + case 'm': + { + char m[3]; + sprintf (m, "%d", this->month ()); + formatted += m; + } + break; + + case 'M': + { + char m[3]; + sprintf (m, "%02d", this->month ()); + formatted += m; + } + break; + + case 'd': + { + char d[3]; + sprintf (d, "%d", this->day ()); + formatted += d; + } + break; + + case 'D': + { + char d[3]; + sprintf (d, "%02d", this->day ()); + formatted += d; + } + break; + + case 'y': + { + char y[3]; + sprintf (y, "%02d", this->year () % 100); + formatted += y; + } + break; + + case 'Y': + { + char y[5]; + sprintf (y, "%d", this->year ()); + formatted += y; + } + break; + + default: + formatted += format[i]; + break; + } + } + + return formatted; } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/Date.h b/src/Date.h index 929097f33..e8a61203f 100644 --- a/src/Date.h +++ b/src/Date.h @@ -44,8 +44,7 @@ public: void toEpoch (time_t&); time_t toEpoch (); void toMDY (int&, int&, int&); - void toString (std::string&); - std::string toString (void); + std::string toString (const std::string& format = "m/d/Y"); static bool valid (const int, const int, const int); static bool leapYear (int); diff --git a/src/task.cpp b/src/task.cpp index 56fd0d871..2b984e2f0 100644 --- a/src/task.cpp +++ b/src/task.cpp @@ -285,22 +285,6 @@ int main (int argc, char** argv) return 0; } -//////////////////////////////////////////////////////////////////////////////// -std::string epochToString (const std::string& epoch) -{ - char formatted[12] = {0}; - - if (epoch.length () && epoch.find ("/") == std::string::npos) - { - Date dt (::atoi (epoch.c_str ())); - int m, d, y; - dt.toMDY (m, d, y); - sprintf (formatted, "%d/%d/%04d", m, d, y); - } - - return formatted; -} - //////////////////////////////////////////////////////////////////////////////// void handleAdd (const TDB& tdb, T& task, Config& conf) { @@ -507,11 +491,7 @@ void handleList (const TDB& tdb, T& task, Config& conf) if (due.length () && due.find ("/") == std::string::npos) { Date dt (::atoi (due.c_str ())); - int m, d, y; - dt.toMDY (m, d, y); - char formatted[12]; - sprintf (formatted, "%d/%d/%04d", m, d, y); - due = formatted; + due = dt.toString (conf.get ("dateformat", "m/d/Y")); overdue = (dt < now) ? true : false; now += 7 * 86400; @@ -671,11 +651,7 @@ void handleSmallList (const TDB& tdb, T& task, Config& conf) if (due.length () && due.find ("/") == std::string::npos) { Date dt (::atoi (due.c_str ())); - int m, d, y; - dt.toMDY (m, d, y); - char formatted[12]; - sprintf (formatted, "%d/%d/%04d", m, d, y); - due = formatted; + due = dt.toString (conf.get ("dateformat", "m/d/Y")); overdue = (dt < now) ? true : false; now += 7 * 86400; @@ -826,7 +802,7 @@ void handleCompleted (const TDB& tdb, T& task, Config& conf) // All criteria match, so add refTask to the output table. int row = table.addRow (); - table.addCell (row, 0, end.toString ()); + table.addCell (row, 0, end.toString (conf.get ("dateformat", "m/d/Y"))); table.addCell (row, 1, refTask.getAttribute ("project")); table.addCell (row, 2, refTask.getDescription ()); @@ -935,7 +911,10 @@ void handleInfo (const TDB& tdb, T& task, Config& conf) { row = table.addRow (); table.addCell (row, 0, "Due"); - table.addCell (row, 1, epochToString (due)); + + Date dt (::atoi (due.c_str ())); + due = dt.toString (conf.get ("dateformat", "m/d/Y")); + table.addCell (row, 1, due); if (due.length () && due.find ("/") == std::string::npos) { @@ -960,7 +939,8 @@ void handleInfo (const TDB& tdb, T& task, Config& conf) { row = table.addRow (); table.addCell (row, 0, "Start"); - table.addCell (row, 1, epochToString (refTask.getAttribute ("start"))); + Date dt (::atoi (refTask.getAttribute ("start").c_str ())); + table.addCell (row, 1, dt.toString (conf.get ("dateformat", "m/d/Y"))); } // end @@ -968,7 +948,8 @@ void handleInfo (const TDB& tdb, T& task, Config& conf) { row = table.addRow (); table.addCell (row, 0, "End"); - table.addCell (row, 1, epochToString (refTask.getAttribute ("end"))); + Date dt (::atoi (refTask.getAttribute ("end").c_str ())); + table.addCell (row, 1, dt.toString (conf.get ("dateformat", "m/d/Y"))); } // tags ... @@ -990,7 +971,8 @@ void handleInfo (const TDB& tdb, T& task, Config& conf) row = table.addRow (); table.addCell (row, 0, "Entered"); - std::string entry = epochToString (refTask.getAttribute ("entry")); + Date dt (::atoi (refTask.getAttribute ("entry").c_str ())); + std::string entry = dt.toString (conf.get ("dateformat", "m/d/Y")); std::string age; std::string created = refTask.getAttribute ("entry"); @@ -1126,22 +1108,14 @@ void handleLongList (const TDB& tdb, T& task, Config& conf) if (started.length () && started.find ("/") == std::string::npos) { Date dt (::atoi (started.c_str ())); - int m, d, y; - dt.toMDY (m, d, y); - char formatted[12]; - sprintf (formatted, "%d/%d/%04d", m, d, y); - started = formatted; + started = dt.toString (conf.get ("dateformat", "m/d/Y")); } std::string entered = refTask.getAttribute ("entry"); if (entered.length () && entered.find ("/") == std::string::npos) { Date dt (::atoi (entered.c_str ())); - int m, d, y; - dt.toMDY (m, d, y); - char formatted[12]; - sprintf (formatted, "%d/%d/%04d", m, d, y); - entered = formatted; + entered = dt.toString (conf.get ("dateformat", "m/d/Y")); } // Now format the matching task. @@ -1151,11 +1125,7 @@ void handleLongList (const TDB& tdb, T& task, Config& conf) if (due.length () && due.find ("/") == std::string::npos) { Date dt (::atoi (due.c_str ())); - int m, d, y; - dt.toMDY (m, d, y); - char formatted[12]; - sprintf (formatted, "%d/%d/%04d", m, d, y); - due = formatted; + due = dt.toString (conf.get ("dateformat", "m/d/Y")); overdue = (dt < now) ? true : false; now += 7 * 86400; @@ -1491,11 +1461,7 @@ void handleReportNext (const TDB& tdb, T& task, Config& conf) if (due.length () && due.find ("/") == std::string::npos) { Date dt (::atoi (due.c_str ())); - int m, d, y; - dt.toMDY (m, d, y); - char formatted[12]; - sprintf (formatted, "%d/%d/%04d", m, d, y); - due = formatted; + due = dt.toString (conf.get ("dateformat", "m/d/Y")); overdue = (dt < now) ? true : false; now += 7 * 86400; @@ -2007,11 +1973,7 @@ void handleReportActive (const TDB& tdb, T& task, Config& conf) if (due.length () && due.find ("/") == std::string::npos) { Date dt (::atoi (due.c_str ())); - int m, d, y; - dt.toMDY (m, d, y); - char formatted[12]; - sprintf (formatted, "%d/%d/%04d", m, d, y); - due = formatted; + due = dt.toString (conf.get ("dateformat", "m/d/Y")); Date now; overdue = dt < now ? true : false; @@ -2129,11 +2091,7 @@ void handleReportOverdue (const TDB& tdb, T& task, Config& conf) if (due.length () && due.find ("/") == std::string::npos) { Date dt (::atoi (due.c_str ())); - int m, d, y; - dt.toMDY (m, d, y); - char formatted[12]; - sprintf (formatted, "%d/%d/%04d", m, d, y); - due = formatted; + due = dt.toString (conf.get ("dateformat", "m/d/Y")); // If overdue. if (dt < now) @@ -2227,9 +2185,9 @@ void handleReportStats (const TDB& tdb, T& task, Config& conf) if (tasks.size ()) { Date e (earliest); - std::cout << "Oldest task " << e.toString () << std::endl; + std::cout << "Oldest task " << e.toString (conf.get ("dateformat", "m/d/Y")) << std::endl; Date l (latest); - std::cout << "Newest task " << l.toString () << std::endl; + std::cout << "Newest task " << l.toString (conf.get ("dateformat", "m/d/Y")) << std::endl; std::cout << "Task used for " << formatSeconds (latest - earliest) << std::endl; } diff --git a/src/tests/date.t.cpp b/src/tests/date.t.cpp new file mode 100644 index 000000000..a83d7d31e --- /dev/null +++ b/src/tests/date.t.cpp @@ -0,0 +1,87 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 2005 - 2008, Paul Beckingham. All rights reserved. +// +//////////////////////////////////////////////////////////////////////////////// +#include +#include +#include + +//////////////////////////////////////////////////////////////////////////////// +int main (int argc, char** argv) +{ + UnitTest t (46); + + Date now; + Date yesterday; + yesterday -= 1; + + t.ok (yesterday <= now, "yesterday <= now"); + t.ok (yesterday < now, "yesterday < now"); + t.notok (yesterday == now, "!(yesterday == now)"); + t.ok (yesterday != now, "yesterday != now"); + t.ok (now >= yesterday, "now >= yesterday"); + t.ok (now > yesterday, "now > yesterday"); + + t.ok (Date::valid (2, 29, 2008), "valid: 2/29/2008"); + t.notok (Date::valid (2, 29, 2007), "invalid: 2/29/2007"); + + t.ok (Date::leapYear (2008), "2008 is a leap year"); + t.notok (Date::leapYear (2007), "2007 is not a leap year"); + + t.is (Date::daysInMonth (2, 2008), 29, "29 days in February 2008"); + t.is (Date::daysInMonth (2, 2007), 28, "28 days in February 2007"); + + t.is (Date::monthName (1), "January", "1 = January"); + t.is (Date::monthName (2), "February", "2 = February"); + t.is (Date::monthName (3), "March", "3 = March"); + t.is (Date::monthName (4), "April", "4 = April"); + t.is (Date::monthName (5), "May", "5 = May"); + t.is (Date::monthName (6), "June", "6 = June"); + t.is (Date::monthName (7), "July", "7 = July"); + t.is (Date::monthName (8), "August", "8 = August"); + t.is (Date::monthName (9), "September", "9 = September"); + t.is (Date::monthName (10), "October", "10 = October"); + t.is (Date::monthName (11), "November", "11 = November"); + t.is (Date::monthName (12), "December", "12 = December"); + + t.is (Date::dayName (0), "Sunday", "0 == Sunday"); + t.is (Date::dayName (1), "Monday", "1 == Monday"); + t.is (Date::dayName (2), "Tuesday", "2 == Tuesday"); + t.is (Date::dayName (3), "Wednesday", "3 == Wednesday"); + t.is (Date::dayName (4), "Thursday", "4 == Thursday"); + t.is (Date::dayName (5), "Friday", "5 == Friday"); + t.is (Date::dayName (6), "Saturday", "6 == Saturday"); + + Date happyNewYear (1, 1, 2008); + t.is (happyNewYear.dayOfWeek (), 2, "1/1/2008 == Tuesday"); + t.is (happyNewYear.month (), 1, "1/1/2008 == January"); + t.is (happyNewYear.day (), 1, "1/1/2008 == 1"); + t.is (happyNewYear.year (), 2008, "1/1/2008 == 2008"); + + t.is (now - yesterday, 1, "today - yesterday == 1"); + + t.is (happyNewYear.toString (), "1/1/2008", "toString 1/1/2008"); + + int m, d, y; + happyNewYear.toMDY (m, d, y); + t.is (m, 1, "1/1/2008 == January"); + t.is (d, 1, "1/1/2008 == 1"); + t.is (y, 2008, "1/1/2008 == 2008"); + + Date epoch (9, 8, 2001); + t.ok ((int)epoch.toEpoch () < 1000000000, "9/8/2001 < 1,000,000,000"); + epoch += 86400; + t.ok ((int)epoch.toEpoch () > 1000000000, "9/9/2001 > 1,000,000,000"); + + Date fromEpoch (epoch.toEpoch ()); + t.is (fromEpoch.toString (), epoch.toString (), "ctor (time_t)"); + + Date fromString ("1/1/2008"); + t.is (fromString.month (), 1, "ctor (std::string) -> m"); + t.is (fromString.day (), 1, "ctor (std::string) -> d"); + t.is (fromString.year (), 2008, "ctor (std::string) -> y"); + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/task.html b/task.html index 9351df9da..8866efa40 100644 --- a/task.html +++ b/task.html @@ -1,22 +1,22 @@ - Task + Task 1.1.0