mirror of
https://github.com/GothenburgBitFactory/timewarrior.git
synced 2025-07-07 20:06:39 +02:00
Detect whether a date is meant as range
- Add DatetimeParser::parse_range: If a date contains no time, it is assumed to be a fixed range, else an open range starting at given datetime - Add tests for summary with named dates 'yesterday' and 'today' - Remove closing of filter in CmdSummary.cpp - Closes #333 Signed-off-by: Thomas Lauf <thomas.lauf@tngtech.com>
This commit is contained in:
parent
2906f36830
commit
63f230013a
8 changed files with 3757 additions and 7 deletions
|
@ -36,6 +36,7 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <Duration.h>
|
#include <Duration.h>
|
||||||
#include <timew.h>
|
#include <timew.h>
|
||||||
|
#include "DatetimeParser.h"
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
A2::A2 (const std::string& raw, Lexer::Type lextype)
|
A2::A2 (const std::string& raw, Lexer::Type lextype)
|
||||||
|
@ -724,7 +725,9 @@ Interval CLI::getFilter (const Range& default_range) const
|
||||||
else if (args.size () == 1 &&
|
else if (args.size () == 1 &&
|
||||||
args[0] == "<date>")
|
args[0] == "<date>")
|
||||||
{
|
{
|
||||||
filter.setRange ({Datetime (start), 0});
|
DatetimeParser dtp;
|
||||||
|
Range range = dtp.parse_range(start);
|
||||||
|
filter.setRange (range);
|
||||||
}
|
}
|
||||||
|
|
||||||
// from <date>
|
// from <date>
|
||||||
|
@ -734,7 +737,6 @@ Interval CLI::getFilter (const Range& default_range) const
|
||||||
{
|
{
|
||||||
filter.setRange ({Datetime (start), 0});
|
filter.setRange ({Datetime (start), 0});
|
||||||
}
|
}
|
||||||
|
|
||||||
// <date> to/- <date>
|
// <date> to/- <date>
|
||||||
else if (args.size () == 3 &&
|
else if (args.size () == 3 &&
|
||||||
args[0] == "<date>" &&
|
args[0] == "<date>" &&
|
||||||
|
|
|
@ -11,6 +11,7 @@ set (timew_SRCS AtomicFile.cpp AtomicFile.h
|
||||||
ChartConfig.h
|
ChartConfig.h
|
||||||
Database.cpp Database.h
|
Database.cpp Database.h
|
||||||
Datafile.cpp Datafile.h
|
Datafile.cpp Datafile.h
|
||||||
|
DatetimeParser.cpp DatetimeParser.h
|
||||||
Exclusion.cpp Exclusion.h
|
Exclusion.cpp Exclusion.h
|
||||||
Extensions.cpp Extensions.h
|
Extensions.cpp Extensions.h
|
||||||
Interval.cpp Interval.h
|
Interval.cpp Interval.h
|
||||||
|
|
2924
src/DatetimeParser.cpp
Normal file
2924
src/DatetimeParser.cpp
Normal file
File diff suppressed because it is too large
Load diff
148
src/DatetimeParser.h
Normal file
148
src/DatetimeParser.h
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright 2020, Thomas Lauf, 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_DATETIMEPARSER
|
||||||
|
#define INCLUDED_DATETIMEPARSER
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <ctime>
|
||||||
|
#include <Pig.h>
|
||||||
|
#include <Range.h>
|
||||||
|
|
||||||
|
class DatetimeParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DatetimeParser () = default;
|
||||||
|
Range parse_range(const std::string&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void clear ();
|
||||||
|
|
||||||
|
bool parse_named (Pig&);
|
||||||
|
bool parse_named_day (Pig&);
|
||||||
|
bool parse_named_month (Pig&);
|
||||||
|
bool parse_epoch (Pig&);
|
||||||
|
bool parse_date_time_ext (Pig&);
|
||||||
|
bool parse_date_ext (Pig&);
|
||||||
|
bool parse_off_ext (Pig&);
|
||||||
|
bool parse_time_ext (Pig&, bool terminated = true);
|
||||||
|
bool parse_time_utc_ext (Pig&);
|
||||||
|
bool parse_time_off_ext (Pig&);
|
||||||
|
bool parse_date_time (Pig&);
|
||||||
|
bool parse_date (Pig&);
|
||||||
|
bool parse_time_utc (Pig&);
|
||||||
|
bool parse_time_off (Pig&);
|
||||||
|
bool parse_time (Pig&, bool terminated = true);
|
||||||
|
bool parse_informal_time (Pig&);
|
||||||
|
bool parse_off (Pig&);
|
||||||
|
|
||||||
|
bool parse_year (Pig&, int&);
|
||||||
|
bool parse_month (Pig&, int&);
|
||||||
|
bool parse_week (Pig&, int&);
|
||||||
|
bool parse_julian (Pig&, int&);
|
||||||
|
bool parse_day (Pig&, int&);
|
||||||
|
bool parse_weekday (Pig&, int&);
|
||||||
|
bool parse_hour (Pig&, int&);
|
||||||
|
bool parse_minute (Pig&, int&);
|
||||||
|
bool parse_second (Pig&, int&);
|
||||||
|
bool parse_off_hour (Pig&, int&);
|
||||||
|
bool parse_off_minute (Pig&, int&);
|
||||||
|
|
||||||
|
bool initializeNow (Pig&);
|
||||||
|
bool initializeYesterday (Pig&);
|
||||||
|
bool initializeToday (Pig&);
|
||||||
|
bool initializeTomorrow (Pig&);
|
||||||
|
bool initializeOrdinal (Pig&);
|
||||||
|
bool initializeDayName (Pig&);
|
||||||
|
bool initializeMonthName (Pig&);
|
||||||
|
bool initializeLater (Pig&);
|
||||||
|
bool initializeSopd (Pig&);
|
||||||
|
bool initializeSod (Pig&);
|
||||||
|
bool initializeSond (Pig&);
|
||||||
|
bool initializeEopd (Pig&);
|
||||||
|
bool initializeEod (Pig&);
|
||||||
|
bool initializeEond (Pig&);
|
||||||
|
bool initializeSopw (Pig&);
|
||||||
|
bool initializeSow (Pig&);
|
||||||
|
bool initializeSonw (Pig&);
|
||||||
|
bool initializeEopw (Pig&);
|
||||||
|
bool initializeEow (Pig&);
|
||||||
|
bool initializeEonw (Pig&);
|
||||||
|
bool initializeSopww (Pig&);
|
||||||
|
bool initializeSonww (Pig&);
|
||||||
|
bool initializeSoww (Pig&);
|
||||||
|
bool initializeEopww (Pig&);
|
||||||
|
bool initializeEonww (Pig&);
|
||||||
|
bool initializeEoww (Pig&);
|
||||||
|
bool initializeSopm (Pig&);
|
||||||
|
bool initializeSom (Pig&);
|
||||||
|
bool initializeSonm (Pig&);
|
||||||
|
bool initializeEopm (Pig&);
|
||||||
|
bool initializeEom (Pig&);
|
||||||
|
bool initializeEonm (Pig&);
|
||||||
|
bool initializeSopq (Pig&);
|
||||||
|
bool initializeSoq (Pig&);
|
||||||
|
bool initializeSonq (Pig&);
|
||||||
|
bool initializeEopq (Pig&);
|
||||||
|
bool initializeEoq (Pig&);
|
||||||
|
bool initializeEonq (Pig&);
|
||||||
|
bool initializeSopy (Pig&);
|
||||||
|
bool initializeSoy (Pig&);
|
||||||
|
bool initializeSony (Pig&);
|
||||||
|
bool initializeEopy (Pig&);
|
||||||
|
bool initializeEoy (Pig&);
|
||||||
|
bool initializeEony (Pig&);
|
||||||
|
bool initializeEaster (Pig&);
|
||||||
|
bool initializeMidsommar (Pig&);
|
||||||
|
bool initializeMidsommarafton (Pig&);
|
||||||
|
bool initializeInformalTime (Pig&);
|
||||||
|
|
||||||
|
void easter (struct tm*) const;
|
||||||
|
void midsommar (struct tm*) const;
|
||||||
|
void midsommarafton (struct tm*) const;
|
||||||
|
|
||||||
|
bool initializeNthDayInMonth (const std::vector <std::string>&);
|
||||||
|
|
||||||
|
bool isOrdinal (const std::string&, int&);
|
||||||
|
|
||||||
|
bool validate ();
|
||||||
|
void resolve ();
|
||||||
|
|
||||||
|
public:
|
||||||
|
int _year {0};
|
||||||
|
int _month {0};
|
||||||
|
int _week {0};
|
||||||
|
int _weekday {0};
|
||||||
|
int _julian {0};
|
||||||
|
int _day {0};
|
||||||
|
int _seconds {0};
|
||||||
|
int _offset {0};
|
||||||
|
bool _utc {false};
|
||||||
|
time_t _date {0};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -47,9 +47,6 @@ int CmdSummary (
|
||||||
// Create a filter, and if empty, choose 'today'.
|
// Create a filter, and if empty, choose 'today'.
|
||||||
auto filter = cli.getFilter (Range { Datetime ("today"), Datetime ("tomorrow") });
|
auto filter = cli.getFilter (Range { Datetime ("today"), Datetime ("tomorrow") });
|
||||||
|
|
||||||
if (! filter.is_ended())
|
|
||||||
filter.end = filter.start + Duration("1d").toTime_t();
|
|
||||||
|
|
||||||
// Load the data.
|
// Load the data.
|
||||||
auto tracked = getTracked (database, rules, filter);
|
auto tracked = getTracked (database, rules, filter);
|
||||||
|
|
||||||
|
@ -115,7 +112,11 @@ int CmdSummary (
|
||||||
// Each day is rendered separately.
|
// Each day is rendered separately.
|
||||||
time_t grand_total = 0;
|
time_t grand_total = 0;
|
||||||
Datetime previous;
|
Datetime previous;
|
||||||
for (Datetime day = filter.start; day < filter.end; day++)
|
|
||||||
|
auto days_start = filter.is_started() ? filter.start : tracked.front ().start;
|
||||||
|
auto days_end = filter.is_ended() ? filter.end : tracked.back ().end;
|
||||||
|
|
||||||
|
for (Datetime day = days_start; day < days_end; day++)
|
||||||
{
|
{
|
||||||
auto day_range = getFullDay (day);
|
auto day_range = getFullDay (day);
|
||||||
time_t daily_total = 0;
|
time_t daily_total = 0;
|
||||||
|
|
|
@ -34,7 +34,7 @@ include_directories (${CMAKE_SOURCE_DIR}
|
||||||
include_directories (${CMAKE_INSTALL_PREFIX}/include)
|
include_directories (${CMAKE_INSTALL_PREFIX}/include)
|
||||||
link_directories(${CMAKE_INSTALL_PREFIX}/lib)
|
link_directories(${CMAKE_INSTALL_PREFIX}/lib)
|
||||||
|
|
||||||
set (test_SRCS AtomicFileTest data.t exclusion.t helper.t interval.t range.t rules.t util.t TagInfoDatabase.t)
|
set (test_SRCS AtomicFileTest data.t DatetimeParser.t exclusion.t helper.t interval.t range.t rules.t util.t TagInfoDatabase.t)
|
||||||
|
|
||||||
add_custom_target (test ./run_all --verbose
|
add_custom_target (test ./run_all --verbose
|
||||||
DEPENDS ${test_SRCS}
|
DEPENDS ${test_SRCS}
|
||||||
|
|
634
test/DatetimeParser.t.cpp
Normal file
634
test/DatetimeParser.t.cpp
Normal file
|
@ -0,0 +1,634 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright 2020, Thomas Lauf, Paul Beckingham, Federico Hernandez.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included
|
||||||
|
// in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
//
|
||||||
|
// http://www.opensource.org/licenses/mit-license.php
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <cmake.h>
|
||||||
|
#include <Datetime.h>
|
||||||
|
#include <test.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <time.h>
|
||||||
|
#include <src/DatetimeParser.h>
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void testParseOpenRange (
|
||||||
|
UnitTest& t,
|
||||||
|
const std::string& input)
|
||||||
|
{
|
||||||
|
std::string label = std::string ("DatetimeParser::parse_range (\"") + input + "\") --> ";
|
||||||
|
|
||||||
|
DatetimeParser iso;
|
||||||
|
|
||||||
|
auto range = iso.parse_range (input);
|
||||||
|
|
||||||
|
t.ok (range.is_open (), label + "[start,...)");
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void testParseClosedRange (
|
||||||
|
UnitTest& t,
|
||||||
|
const std::string& input)
|
||||||
|
{
|
||||||
|
std::string label = std::string ("DatetimeParser::parse_range (\"") + input + "\") --> ";
|
||||||
|
|
||||||
|
DatetimeParser iso;
|
||||||
|
|
||||||
|
auto range = iso.parse_range (input);
|
||||||
|
|
||||||
|
t.ok (!range.is_open (), label + "[start,end)");
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void testParse (
|
||||||
|
UnitTest& t,
|
||||||
|
const std::string& input)
|
||||||
|
{
|
||||||
|
std::string label = std::string ("DatetimeParser::parse_range positive '") + input + "' --> success";
|
||||||
|
|
||||||
|
DatetimeParser positive;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
positive.parse_range (input);
|
||||||
|
t.pass (label);
|
||||||
|
}
|
||||||
|
catch (const std::string& e)
|
||||||
|
{
|
||||||
|
t.fail ("exception thrown");
|
||||||
|
t.diag (e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void testParseError (
|
||||||
|
UnitTest& t,
|
||||||
|
const std::string& input)
|
||||||
|
{
|
||||||
|
std::string label = std::string ("DatetimeParser::parse_range negative '") + input + "' --> fail";
|
||||||
|
|
||||||
|
DatetimeParser neg;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
neg.parse_range (input);
|
||||||
|
t.fail ("No exception thrown");
|
||||||
|
}
|
||||||
|
catch (const std::string& e)
|
||||||
|
{
|
||||||
|
t.pass (label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int main (int, char**)
|
||||||
|
{
|
||||||
|
UnitTest t (361);
|
||||||
|
|
||||||
|
// Determine local and UTC time.
|
||||||
|
time_t now = time (nullptr);
|
||||||
|
struct tm* local_now = localtime (&now);
|
||||||
|
int local_s = (local_now->tm_hour * 3600) +
|
||||||
|
(local_now->tm_min * 60) +
|
||||||
|
local_now->tm_sec;
|
||||||
|
local_now->tm_hour = 0;
|
||||||
|
local_now->tm_min = 0;
|
||||||
|
local_now->tm_sec = 0;
|
||||||
|
local_now->tm_isdst = -1;
|
||||||
|
time_t local = mktime (local_now);
|
||||||
|
std::cout << "# local midnight today " << local << '\n';
|
||||||
|
|
||||||
|
int year = 2013;
|
||||||
|
int mo = 12;
|
||||||
|
|
||||||
|
local_now->tm_year = year - 1900;
|
||||||
|
local_now->tm_mon = mo - 1;
|
||||||
|
local_now->tm_mday = 6;
|
||||||
|
local_now->tm_isdst = 0;
|
||||||
|
time_t local6 = mktime (local_now);
|
||||||
|
std::cout << "# local midnight 2013-12-06 " << local6 << '\n';
|
||||||
|
|
||||||
|
local_now->tm_year = year - 1900;
|
||||||
|
local_now->tm_mon = mo - 1;
|
||||||
|
local_now->tm_mday = 1;
|
||||||
|
local_now->tm_isdst = 0;
|
||||||
|
time_t local1 = mktime (local_now);
|
||||||
|
std::cout << "# local midnight 2013-12-01 " << local1 << '\n';
|
||||||
|
|
||||||
|
struct tm* utc_now = gmtime (&now);
|
||||||
|
int utc_s = (utc_now->tm_hour * 3600) +
|
||||||
|
(utc_now->tm_min * 60) +
|
||||||
|
utc_now->tm_sec;
|
||||||
|
utc_now->tm_hour = 0;
|
||||||
|
utc_now->tm_min = 0;
|
||||||
|
utc_now->tm_sec = 0;
|
||||||
|
utc_now->tm_isdst = -1;
|
||||||
|
time_t utc = timegm (utc_now);
|
||||||
|
std::cout << "# utc midnight today " << utc << '\n';
|
||||||
|
|
||||||
|
utc_now->tm_year = year - 1900;
|
||||||
|
utc_now->tm_mon = mo - 1;
|
||||||
|
utc_now->tm_mday = 6;
|
||||||
|
utc_now->tm_isdst = 0;
|
||||||
|
time_t utc6 = timegm (utc_now);
|
||||||
|
std::cout << "# utc midnight 2013-12-06 " << utc6 << '\n';
|
||||||
|
|
||||||
|
utc_now->tm_year = year - 1900;
|
||||||
|
utc_now->tm_mon = mo - 1;
|
||||||
|
utc_now->tm_mday = 1;
|
||||||
|
utc_now->tm_isdst = 0;
|
||||||
|
time_t utc1 = timegm (utc_now);
|
||||||
|
std::cout << "# utc midnight 2013-12-01 " << utc1 << '\n';
|
||||||
|
|
||||||
|
int hms = (12 * 3600) + (34 * 60) + 56; // The time 12:34:56 in seconds.
|
||||||
|
int hm = (12 * 3600) + (34 * 60); // The time 12:34:00 in seconds.
|
||||||
|
int z = 3600; // TZ offset.
|
||||||
|
|
||||||
|
int ld = local_s > hms ? 86400 : 0; // Local extra day if now > hms.
|
||||||
|
int ud = utc_s > hms ? 86400 : 0; // UTC extra day if now > hms.
|
||||||
|
std::cout << "# ld " << ld << '\n';
|
||||||
|
std::cout << "# ud " << ud << '\n';
|
||||||
|
|
||||||
|
// Aggregated
|
||||||
|
testParseOpenRange(t, "12:34:56 ");
|
||||||
|
|
||||||
|
// time-ext
|
||||||
|
testParseOpenRange(t, "12:34:56Z");
|
||||||
|
testParseOpenRange(t, "12:34Z");
|
||||||
|
testParseOpenRange(t, "12:34:56+01:00");
|
||||||
|
testParseOpenRange(t, "12:34:56+01");
|
||||||
|
testParseOpenRange(t, "12:34+01:00");
|
||||||
|
testParseOpenRange(t, "12:34+01");
|
||||||
|
testParseOpenRange(t, "12:34:56");
|
||||||
|
testParseOpenRange(t, "12:34");
|
||||||
|
|
||||||
|
// datetime-ext
|
||||||
|
testParseClosedRange(t, "2013-12-06");
|
||||||
|
testParseClosedRange(t, "2013-340");
|
||||||
|
testParseClosedRange(t, "2013-W49-5");
|
||||||
|
testParseClosedRange(t, "2013-W49");
|
||||||
|
testParseClosedRange(t, "2013-12");
|
||||||
|
|
||||||
|
testParseOpenRange(t, "2013-12-06T12:34:56");
|
||||||
|
testParseOpenRange(t, "2013-12-06T12:34");
|
||||||
|
testParseOpenRange(t, "2013-340T12:34:56");
|
||||||
|
testParseOpenRange(t, "2013-340T12:34");
|
||||||
|
testParseOpenRange(t, "2013-W49-5T12:34:56");
|
||||||
|
testParseOpenRange(t, "2013-W49-5T12:34");
|
||||||
|
testParseOpenRange(t, "2013-W49T12:34:56");
|
||||||
|
testParseOpenRange(t, "2013-W49T12:34");
|
||||||
|
|
||||||
|
testParseOpenRange(t, "2013-12-06T12:34:56Z");
|
||||||
|
testParseOpenRange(t, "2013-12-06T12:34Z");
|
||||||
|
testParseOpenRange(t, "2013-340T12:34:56Z");
|
||||||
|
testParseOpenRange(t, "2013-340T12:34Z");
|
||||||
|
testParseOpenRange(t, "2013-W49-5T12:34:56Z");
|
||||||
|
testParseOpenRange(t, "2013-W49-5T12:34Z");
|
||||||
|
testParseOpenRange(t, "2013-W49T12:34:56Z");
|
||||||
|
testParseOpenRange(t, "2013-W49T12:34Z");
|
||||||
|
|
||||||
|
testParseOpenRange(t, "2013-12-06T12:34:56+01:00");
|
||||||
|
testParseOpenRange(t, "2013-12-06T12:34:56+01");
|
||||||
|
testParseOpenRange(t, "2013-12-06T12:34:56-01:00");
|
||||||
|
testParseOpenRange(t, "2013-12-06T12:34:56-01");
|
||||||
|
testParseOpenRange(t, "2013-12-06T12:34+01:00");
|
||||||
|
testParseOpenRange(t, "2013-12-06T12:34+01");
|
||||||
|
testParseOpenRange(t, "2013-12-06T12:34-01:00");
|
||||||
|
testParseOpenRange(t, "2013-12-06T12:34-01");
|
||||||
|
testParseOpenRange(t, "2013-340T12:34:56+01:00");
|
||||||
|
testParseOpenRange(t, "2013-340T12:34:56+01");
|
||||||
|
testParseOpenRange(t, "2013-340T12:34:56-01:00");
|
||||||
|
testParseOpenRange(t, "2013-340T12:34:56-01");
|
||||||
|
testParseOpenRange(t, "2013-340T12:34+01:00");
|
||||||
|
testParseOpenRange(t, "2013-340T12:34+01");
|
||||||
|
testParseOpenRange(t, "2013-340T12:34-01:00");
|
||||||
|
testParseOpenRange(t, "2013-340T12:34-01");
|
||||||
|
testParseOpenRange(t, "2013-W49-5T12:34:56+01:00");
|
||||||
|
testParseOpenRange(t, "2013-W49-5T12:34:56+01");
|
||||||
|
testParseOpenRange(t, "2013-W49-5T12:34:56-01:00");
|
||||||
|
testParseOpenRange(t, "2013-W49-5T12:34:56-01");
|
||||||
|
testParseOpenRange(t, "2013-W49-5T12:34+01:00");
|
||||||
|
testParseOpenRange(t, "2013-W49-5T12:34+01");
|
||||||
|
testParseOpenRange(t, "2013-W49-5T12:34-01:00");
|
||||||
|
testParseOpenRange(t, "2013-W49-5T12:34-01");
|
||||||
|
testParseOpenRange(t, "2013-W49T12:34:56+01:00");
|
||||||
|
testParseOpenRange(t, "2013-W49T12:34:56+01");
|
||||||
|
testParseOpenRange(t, "2013-W49T12:34:56-01:00");
|
||||||
|
testParseOpenRange(t, "2013-W49T12:34:56-01");
|
||||||
|
testParseOpenRange(t, "2013-W49T12:34+01:00");
|
||||||
|
testParseOpenRange(t, "2013-W49T12:34+01");
|
||||||
|
testParseOpenRange(t, "2013-W49T12:34-01:00");
|
||||||
|
testParseOpenRange(t, "2013-W49T12:34-01");
|
||||||
|
|
||||||
|
// The only non-extended forms.
|
||||||
|
testParseOpenRange(t, "20131206T123456Z");
|
||||||
|
testParseOpenRange(t, "20131206T123456");
|
||||||
|
|
||||||
|
// Non-extended forms.
|
||||||
|
|
||||||
|
// time
|
||||||
|
testParseOpenRange(t, "123456Z");
|
||||||
|
testParseOpenRange(t, "1234Z");
|
||||||
|
testParseOpenRange(t, "123456+0100");
|
||||||
|
testParseOpenRange(t, "123456+01");
|
||||||
|
testParseOpenRange(t, "1234+0100");
|
||||||
|
testParseOpenRange(t, "1234+01");
|
||||||
|
testParseOpenRange(t, "123456");
|
||||||
|
testParseOpenRange(t, "1234");
|
||||||
|
|
||||||
|
// datetime
|
||||||
|
testParseClosedRange(t, "20131206");
|
||||||
|
testParseClosedRange(t, "2013340");
|
||||||
|
testParseClosedRange(t, "2013W495");
|
||||||
|
testParseClosedRange(t, "2013W49");
|
||||||
|
testParseClosedRange(t, "201312");
|
||||||
|
|
||||||
|
testParseOpenRange(t, "20131206T123456");
|
||||||
|
testParseOpenRange(t, "20131206T1234");
|
||||||
|
testParseOpenRange(t, "2013340T123456");
|
||||||
|
testParseOpenRange(t, "2013340T1234");
|
||||||
|
testParseOpenRange(t, "2013W495T123456");
|
||||||
|
testParseOpenRange(t, "2013W495T1234");
|
||||||
|
testParseOpenRange(t, "2013W49T123456");
|
||||||
|
testParseOpenRange(t, "2013W49T1234");
|
||||||
|
|
||||||
|
testParseOpenRange(t, "20131206T123456Z");
|
||||||
|
testParseOpenRange(t, "20131206T1234Z");
|
||||||
|
testParseOpenRange(t, "2013340T123456Z");
|
||||||
|
testParseOpenRange(t, "2013340T1234Z");
|
||||||
|
testParseOpenRange(t, "2013W495T123456Z");
|
||||||
|
testParseOpenRange(t, "2013W495T1234Z");
|
||||||
|
testParseOpenRange(t, "2013W49T123456Z");
|
||||||
|
testParseOpenRange(t, "2013W49T1234Z");
|
||||||
|
|
||||||
|
testParseOpenRange(t, "20131206T123456+0100");
|
||||||
|
testParseOpenRange(t, "20131206T123456+01");
|
||||||
|
testParseOpenRange(t, "20131206T123456-0100");
|
||||||
|
testParseOpenRange(t, "20131206T123456-01");
|
||||||
|
testParseOpenRange(t, "20131206T1234+0100");
|
||||||
|
testParseOpenRange(t, "20131206T1234+01");
|
||||||
|
testParseOpenRange(t, "20131206T1234-0100");
|
||||||
|
testParseOpenRange(t, "20131206T1234-01");
|
||||||
|
testParseOpenRange(t, "2013340T123456+0100");
|
||||||
|
testParseOpenRange(t, "2013340T123456+01");
|
||||||
|
testParseOpenRange(t, "2013340T123456-0100");
|
||||||
|
testParseOpenRange(t, "2013340T123456-01");
|
||||||
|
testParseOpenRange(t, "2013340T1234+0100");
|
||||||
|
testParseOpenRange(t, "2013340T1234+01");
|
||||||
|
testParseOpenRange(t, "2013340T1234-0100");
|
||||||
|
testParseOpenRange(t, "2013340T1234-01");
|
||||||
|
testParseOpenRange(t, "2013W495T123456+0100");
|
||||||
|
testParseOpenRange(t, "2013W495T123456+01");
|
||||||
|
testParseOpenRange(t, "2013W495T123456-0100");
|
||||||
|
testParseOpenRange(t, "2013W495T123456-01");
|
||||||
|
testParseOpenRange(t, "2013W495T1234+0100");
|
||||||
|
testParseOpenRange(t, "2013W495T1234+01");
|
||||||
|
testParseOpenRange(t, "2013W495T1234-0100");
|
||||||
|
testParseOpenRange(t, "2013W495T1234-01");
|
||||||
|
testParseOpenRange(t, "2013W49T123456+0100");
|
||||||
|
testParseOpenRange(t, "2013W49T123456+01");
|
||||||
|
testParseOpenRange(t, "2013W49T123456-0100");
|
||||||
|
testParseOpenRange(t, "2013W49T123456-01");
|
||||||
|
testParseOpenRange(t, "2013W49T1234+0100");
|
||||||
|
testParseOpenRange(t, "2013W49T1234+01");
|
||||||
|
testParseOpenRange(t, "2013W49T1234-0100");
|
||||||
|
testParseOpenRange(t, "2013W49T1234-01");
|
||||||
|
|
||||||
|
// Informal time.
|
||||||
|
int t8a = (8 * 3600);
|
||||||
|
int t830a = (8 * 3600) + (30 * 60);
|
||||||
|
int t8p = (20 * 3600);
|
||||||
|
int t830p = (20 * 3600) + (30 * 60);
|
||||||
|
int t12p = (12 * 3600);
|
||||||
|
int t1p = (13 * 3600);
|
||||||
|
|
||||||
|
Datetime time_now;
|
||||||
|
int adjust = (time_now.hour () > 10 || (time_now.hour () == 10 && time_now.minute () > 30)) ? 86400 : 0;
|
||||||
|
testParseOpenRange(t, "10:30am");
|
||||||
|
|
||||||
|
adjust = (time_now.hour () > 8 || (time_now.hour () == 8 && time_now.minute () > 30)) ? 86400 : 0;
|
||||||
|
testParseOpenRange(t, "8:30am");
|
||||||
|
testParseOpenRange(t, "8:30a");
|
||||||
|
testParseOpenRange(t, "8:30");
|
||||||
|
|
||||||
|
adjust = (time_now.hour () >= 8) ? 86400 : 0;
|
||||||
|
testParseOpenRange(t, "8am");
|
||||||
|
testParseOpenRange(t, "8a");
|
||||||
|
|
||||||
|
adjust = (time_now.hour () > 20 || (time_now.hour () == 20 && time_now.minute () > 30)) ? 86400 : 0;
|
||||||
|
testParseOpenRange(t, "8:30pm");
|
||||||
|
testParseOpenRange(t, "8:30p");
|
||||||
|
|
||||||
|
adjust = (time_now.hour () >= 20) ? 86400 : 0;
|
||||||
|
testParseOpenRange(t, "8pm");
|
||||||
|
testParseOpenRange(t, "8p");
|
||||||
|
|
||||||
|
adjust = (time_now.hour () >= 12) ? 86400 : 0;
|
||||||
|
testParseOpenRange(t, "12pm");
|
||||||
|
|
||||||
|
adjust = (time_now.hour () >= 13) ? 86400 : 0;
|
||||||
|
testParseOpenRange(t, "1pm");
|
||||||
|
|
||||||
|
// Names.
|
||||||
|
testParseClosedRange (t, "yesterday");
|
||||||
|
testParseClosedRange (t, "tomorrow");
|
||||||
|
|
||||||
|
testParseClosedRange (t, "january");
|
||||||
|
testParseClosedRange (t, "february");
|
||||||
|
testParseClosedRange (t, "march");
|
||||||
|
testParseClosedRange (t, "april");
|
||||||
|
testParseClosedRange (t, "may");
|
||||||
|
testParseClosedRange (t, "june");
|
||||||
|
testParseClosedRange (t, "july");
|
||||||
|
testParseClosedRange (t, "august");
|
||||||
|
testParseClosedRange (t, "september");
|
||||||
|
testParseClosedRange (t, "october");
|
||||||
|
testParseClosedRange (t, "november");
|
||||||
|
testParseClosedRange (t, "december");
|
||||||
|
|
||||||
|
testParseClosedRange (t, "jan");
|
||||||
|
testParseClosedRange (t, "feb");
|
||||||
|
testParseClosedRange (t, "mar");
|
||||||
|
testParseClosedRange (t, "apr");
|
||||||
|
testParseClosedRange (t, "may");
|
||||||
|
testParseClosedRange (t, "jun");
|
||||||
|
testParseClosedRange (t, "jul");
|
||||||
|
testParseClosedRange (t, "aug");
|
||||||
|
testParseClosedRange (t, "sep");
|
||||||
|
testParseClosedRange (t, "oct");
|
||||||
|
testParseClosedRange (t, "nov");
|
||||||
|
testParseClosedRange (t, "dec");
|
||||||
|
|
||||||
|
testParseClosedRange (t, "sunday");
|
||||||
|
testParseClosedRange (t, "monday");
|
||||||
|
testParseClosedRange (t, "tuesday");
|
||||||
|
testParseClosedRange (t, "wednesday");
|
||||||
|
testParseClosedRange (t, "thursday");
|
||||||
|
testParseClosedRange (t, "friday");
|
||||||
|
testParseClosedRange (t, "saturday");
|
||||||
|
|
||||||
|
testParseClosedRange (t, "sun");
|
||||||
|
testParseClosedRange (t, "mon");
|
||||||
|
testParseClosedRange (t, "tue");
|
||||||
|
testParseClosedRange (t, "wed");
|
||||||
|
testParseClosedRange (t, "thu");
|
||||||
|
testParseClosedRange (t, "fri");
|
||||||
|
testParseClosedRange (t, "sat");
|
||||||
|
|
||||||
|
Datetime r11 ("eow");
|
||||||
|
Datetime r16 ("sonw");
|
||||||
|
Datetime r23 ("sow");
|
||||||
|
Datetime r17 ("sonm");
|
||||||
|
Datetime r18 ("som");
|
||||||
|
Datetime r19 ("sony");
|
||||||
|
Datetime r19a ("soy");
|
||||||
|
Datetime r19b ("eoy");
|
||||||
|
Datetime r19c ("soq");
|
||||||
|
Datetime r19d ("eoq");
|
||||||
|
|
||||||
|
Datetime first ("1st");
|
||||||
|
Datetime second ("2nd");
|
||||||
|
Datetime third ("3rd");
|
||||||
|
Datetime fourth ("4th");
|
||||||
|
|
||||||
|
Datetime later ("later");
|
||||||
|
|
||||||
|
// Test all format options.
|
||||||
|
Datetime r32 ("2015-10-28T12:55:00");
|
||||||
|
|
||||||
|
// Test all parse options.
|
||||||
|
Datetime r33 ("2015 10 28 19 28 01", "Y M D H N S");
|
||||||
|
t.is(r33.year (), 2015, "Y works");
|
||||||
|
t.is(r33.month (), 10, "M works");
|
||||||
|
t.is(r33.day (), 28, "D works");
|
||||||
|
t.is(r33.hour (), 19, "H works");
|
||||||
|
t.is(r33.minute (), 28, "N works");
|
||||||
|
t.is(r33.second (), 1, "S works");
|
||||||
|
|
||||||
|
Datetime r34 ("15 5 4 3 2 1", "y m d h n s");
|
||||||
|
t.is(r34.year (), 2015, "y works");
|
||||||
|
t.is(r34.month (), 5, "m works");
|
||||||
|
t.is(r34.day (), 4, "d works");
|
||||||
|
t.is(r34.hour (), 3, "h works");
|
||||||
|
t.is(r34.minute (), 2, "n works");
|
||||||
|
t.is(r34.second (), 1, "s works");
|
||||||
|
|
||||||
|
Datetime r35 ("Wednesday October 28 2015", "A B D Y");
|
||||||
|
t.is(r35.year (), 2015, "Y works");
|
||||||
|
t.is(r35.month (), 10, "B works");
|
||||||
|
t.is(r35.day (), 28, "D works");
|
||||||
|
t.is(r35.dayOfWeek (), 3, "A works");
|
||||||
|
|
||||||
|
Datetime r36 ("Wed Oct 28 15", "a b d y");
|
||||||
|
t.is(r36.year (), 2015, "y works");
|
||||||
|
t.is(r36.month (), 10, "b works");
|
||||||
|
t.is(r36.day (), 28, "d works");
|
||||||
|
t.is(r36.dayOfWeek (), 3, "a works");
|
||||||
|
|
||||||
|
Datetime r37 ("19th");
|
||||||
|
t.is (r37.day (), 19, "'19th' --> 19");
|
||||||
|
|
||||||
|
// Embedded parsing.
|
||||||
|
testParseError (t, "nowadays");
|
||||||
|
testParse (t, "now+1d");
|
||||||
|
testParse (t, "now-1d");
|
||||||
|
testParseOpenRange (t, "now)");
|
||||||
|
testParseError (t, "now7");
|
||||||
|
testParseError (t, "tomorrov");
|
||||||
|
|
||||||
|
testParseError (t, "yesteryear");
|
||||||
|
testParseClosedRange (t, "yest+1d");
|
||||||
|
testParseClosedRange (t, "yest-1d");
|
||||||
|
testParseClosedRange (t, "yest)");
|
||||||
|
testParseError (t, "yest7");
|
||||||
|
testParseClosedRange (t, "yesterday");
|
||||||
|
|
||||||
|
testParse (t, "1234567890+0");
|
||||||
|
testParse (t, "1234567890-0");
|
||||||
|
testParse (t, "1234567890)");
|
||||||
|
|
||||||
|
// Negative tests, all expected to fail.
|
||||||
|
testParseError (t, "");
|
||||||
|
testParseError (t, "foo");
|
||||||
|
testParseError (t, "-2014-07-07");
|
||||||
|
testParseError (t, "2014-07-");
|
||||||
|
testParseError (t, "2014-0-12");
|
||||||
|
testParseError (t, "abcd-ab-ab");
|
||||||
|
testParseError (t, "2014-000");
|
||||||
|
testParseClosedRange (t, "2014-001");
|
||||||
|
testParseClosedRange (t, "2014-365");
|
||||||
|
testParseError (t, "2014-366");
|
||||||
|
testParseError (t, "2014-367");
|
||||||
|
testParseError (t, "2014-999");
|
||||||
|
testParseError (t, "2014-999999999");
|
||||||
|
testParseError (t, "2014-W00");
|
||||||
|
testParseError (t, "2014-W54");
|
||||||
|
testParseError (t, "2014-W240");
|
||||||
|
testParseError (t, "2014-W248");
|
||||||
|
testParseError (t, "2014-W24200");
|
||||||
|
//testParseError (t, "2014-00"); // Looks like Datetime::parse_time_off 'hhmm-hh'
|
||||||
|
testParseError (t, "2014-13");
|
||||||
|
testParseError (t, "2014-99");
|
||||||
|
testParseError (t, "25:00");
|
||||||
|
testParseError (t, "99:00");
|
||||||
|
testParseError (t, "12:60");
|
||||||
|
testParseError (t, "12:99");
|
||||||
|
testParseError (t, "12:ab");
|
||||||
|
testParseError (t, "ab:12");
|
||||||
|
testParseError (t, "ab:cd");
|
||||||
|
testParseError (t, "-12:12");
|
||||||
|
testParseError (t, "12:-12");
|
||||||
|
testParseError (t, "25:00Z");
|
||||||
|
testParseError (t, "99:00Z");
|
||||||
|
testParseError (t, "12:60Z");
|
||||||
|
testParseError (t, "12:99Z");
|
||||||
|
testParseError (t, "12:abZ");
|
||||||
|
testParseError (t, "ab:12Z");
|
||||||
|
testParseError (t, "ab:cdZ");
|
||||||
|
testParseError (t, "-12:12Z");
|
||||||
|
testParseError (t, "12:-12Z");
|
||||||
|
testParseError (t, "25:00+01:00");
|
||||||
|
testParseError (t, "99:00+01:00");
|
||||||
|
testParseError (t, "12:60+01:00");
|
||||||
|
testParseError (t, "12:99+01:00");
|
||||||
|
testParseError (t, "12:ab+01:00");
|
||||||
|
testParseError (t, "ab:12+01:00");
|
||||||
|
testParseError (t, "ab:cd+01:00");
|
||||||
|
testParseError (t, "-12:12+01:00");
|
||||||
|
testParseError (t, "12:-12+01:00");
|
||||||
|
testParseError (t, "25:00-01:00");
|
||||||
|
testParseError (t, "99:00-01:00");
|
||||||
|
testParseError (t, "12:60-01:00");
|
||||||
|
testParseError (t, "12:99-01:00");
|
||||||
|
testParseError (t, "12:ab-01:00");
|
||||||
|
testParseError (t, "ab:12-01:00");
|
||||||
|
testParseError (t, "ab:cd-01:00");
|
||||||
|
testParseError (t, "-12:12-01:00");
|
||||||
|
testParseError (t, "12:-12-01:00");
|
||||||
|
testParseError (t, "25:00:00");
|
||||||
|
testParseError (t, "99:00:00");
|
||||||
|
testParseError (t, "12:60:00");
|
||||||
|
testParseError (t, "12:99:00");
|
||||||
|
testParseError (t, "12:12:60");
|
||||||
|
testParseError (t, "12:12:99");
|
||||||
|
testParseError (t, "12:ab:00");
|
||||||
|
testParseError (t, "ab:12:00");
|
||||||
|
testParseError (t, "12:12:ab");
|
||||||
|
testParseError (t, "ab:cd:ef");
|
||||||
|
testParseError (t, "-12:12:12");
|
||||||
|
testParseError (t, "12:-12:12");
|
||||||
|
testParseError (t, "12:12:-12");
|
||||||
|
testParseError (t, "25:00:00Z");
|
||||||
|
testParseError (t, "99:00:00Z");
|
||||||
|
testParseError (t, "12:60:00Z");
|
||||||
|
testParseError (t, "12:99:00Z");
|
||||||
|
testParseError (t, "12:12:60Z");
|
||||||
|
testParseError (t, "12:12:99Z");
|
||||||
|
testParseError (t, "12:ab:00Z");
|
||||||
|
testParseError (t, "ab:12:00Z");
|
||||||
|
testParseError (t, "12:12:abZ");
|
||||||
|
testParseError (t, "ab:cd:efZ");
|
||||||
|
testParseError (t, "-12:12:12Z");
|
||||||
|
testParseError (t, "12:-12:12Z");
|
||||||
|
testParseError (t, "12:12:-12Z");
|
||||||
|
testParseError (t, "25:00:00+01:00");
|
||||||
|
testParseError (t, "95:00:00+01:00");
|
||||||
|
testParseError (t, "12:60:00+01:00");
|
||||||
|
testParseError (t, "12:99:00+01:00");
|
||||||
|
testParseError (t, "12:12:60+01:00");
|
||||||
|
testParseError (t, "12:12:99+01:00");
|
||||||
|
testParseError (t, "12:ab:00+01:00");
|
||||||
|
testParseError (t, "ab:12:00+01:00");
|
||||||
|
testParseError (t, "12:12:ab+01:00");
|
||||||
|
testParseError (t, "ab:cd:ef+01:00");
|
||||||
|
testParseError (t, "-12:12:12+01:00");
|
||||||
|
testParseError (t, "12:-12:12+01:00");
|
||||||
|
testParseError (t, "12:12:-12+01:00");
|
||||||
|
testParseError (t, "25:00:00-01:00");
|
||||||
|
testParseError (t, "95:00:00-01:00");
|
||||||
|
testParseError (t, "12:60:00-01:00");
|
||||||
|
testParseError (t, "12:99:00-01:00");
|
||||||
|
testParseError (t, "12:12:60-01:00");
|
||||||
|
testParseError (t, "12:12:99-01:00");
|
||||||
|
testParseError (t, "12:ab:00-01:00");
|
||||||
|
testParseError (t, "ab:12:00-01:00");
|
||||||
|
testParseError (t, "12:12:ab-01:00");
|
||||||
|
testParseError (t, "ab:cd:ef-01:00");
|
||||||
|
testParseError (t, "-12:12:12-01:00");
|
||||||
|
testParseError (t, "12:-12:12-01:00");
|
||||||
|
testParseError (t, "12:12:-12-01:00");
|
||||||
|
testParseError (t, "12:12:12-13:00");
|
||||||
|
testParseError (t, "12:12:12-24:00");
|
||||||
|
testParseError (t, "12:12:12-99:00");
|
||||||
|
testParseError (t, "12:12:12-03:60");
|
||||||
|
testParseError (t, "12:12:12-03:99");
|
||||||
|
testParseError (t, "12:12:12-3:20");
|
||||||
|
testParseError (t, "12:12:12-03:2");
|
||||||
|
testParseError (t, "12:12:12-3:2");
|
||||||
|
testParseError (t, "12:12:12+13:00");
|
||||||
|
testParseError (t, "12:12:12+24:00");
|
||||||
|
testParseError (t, "12:12:12+99:00");
|
||||||
|
testParseError (t, "12:12:12+03:60");
|
||||||
|
testParseError (t, "12:12:12+03:99");
|
||||||
|
testParseError (t, "12:12:12+3:20");
|
||||||
|
testParseError (t, "12:12:12+03:2");
|
||||||
|
testParseError (t, "12:12:12+3:2");
|
||||||
|
testParseError (t, "12:12-13:00");
|
||||||
|
testParseError (t, "12:12-24:00");
|
||||||
|
testParseError (t, "12:12-99:00");
|
||||||
|
testParseError (t, "12:12-03:60");
|
||||||
|
testParseError (t, "12:12-03:99");
|
||||||
|
testParseError (t, "12:12-3:20");
|
||||||
|
testParseError (t, "12:12-03:2");
|
||||||
|
testParseError (t, "12:12-3:2");
|
||||||
|
testParseError (t, "12:12+13:00");
|
||||||
|
testParseError (t, "12:12+24:00");
|
||||||
|
testParseError (t, "12:12+99:00");
|
||||||
|
testParseError (t, "12:12+03:60");
|
||||||
|
testParseError (t, "12:12+03:99");
|
||||||
|
testParseError (t, "12:12+3:20");
|
||||||
|
testParseError (t, "12:12+03:2");
|
||||||
|
testParseError (t, "12:12+3:2");
|
||||||
|
|
||||||
|
// Test with standalone date enable/disabled.
|
||||||
|
Datetime::standaloneDateEnabled = true;
|
||||||
|
testParseClosedRange(t, "20170319");
|
||||||
|
Datetime::standaloneDateEnabled = false;
|
||||||
|
testParseError (t, "20170319");
|
||||||
|
Datetime::standaloneDateEnabled = true;
|
||||||
|
|
||||||
|
Datetime::standaloneTimeEnabled = true;
|
||||||
|
testParseOpenRange(t, "235959");
|
||||||
|
Datetime::standaloneTimeEnabled = false;
|
||||||
|
testParseError (t, "235959");
|
||||||
|
Datetime::standaloneTimeEnabled = true;
|
||||||
|
|
||||||
|
// Weekdays and month names can no longer be followed by ':' or '='.
|
||||||
|
testParseClosedRange(t, "jan");
|
||||||
|
testParseError (t, "jan:");
|
||||||
|
testParseClosedRange(t, "mon");
|
||||||
|
testParseError (t, "mon:");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
|
@ -177,6 +177,46 @@ W{5} {2:%Y-%m-%d} {2:%a} @1 BAZ 10:00:00 11:00:00 1:00:00 1:00:00
|
||||||
""".format(yesterday, now, tomorrow,
|
""".format(yesterday, now, tomorrow,
|
||||||
yesterday.isocalendar()[1], now.isocalendar()[1], tomorrow.isocalendar()[1]), out)
|
yesterday.isocalendar()[1], now.isocalendar()[1], tomorrow.isocalendar()[1]), out)
|
||||||
|
|
||||||
|
def test_with_named_date_yesterday(self):
|
||||||
|
"""Summary should work with 'yesterday'"""
|
||||||
|
now = datetime.now()
|
||||||
|
yesterday = now - timedelta(days=1)
|
||||||
|
tomorrow = now + timedelta(days=1)
|
||||||
|
|
||||||
|
self.t("track {0:%Y-%m-%d}T10:00:00 - {0:%Y-%m-%d}T11:00:00 FOO".format(yesterday))
|
||||||
|
self.t("track {0:%Y-%m-%d}T10:00:00 - {0:%Y-%m-%d}T11:00:00 BAR".format(now))
|
||||||
|
self.t("track {0:%Y-%m-%d}T10:00:00 - {0:%Y-%m-%d}T11:00:00 BAZ".format(tomorrow))
|
||||||
|
|
||||||
|
code, out, err = self.t("summary :ids yesterday")
|
||||||
|
|
||||||
|
self.assertIn("""
|
||||||
|
Wk Date Day ID Tags Start End Time Total
|
||||||
|
--- ---------- --- -- ---- -------- -------- ------- -------
|
||||||
|
W{1} {0:%Y-%m-%d} {0:%a} @3 FOO 10:00:00 11:00:00 1:00:00 1:00:00
|
||||||
|
|
||||||
|
1:00:00
|
||||||
|
""".format(yesterday, yesterday.isocalendar()[1]), out)
|
||||||
|
|
||||||
|
def test_with_named_date_today(self):
|
||||||
|
"""Summary should work with 'today'"""
|
||||||
|
now = datetime.now()
|
||||||
|
yesterday = now - timedelta(days=1)
|
||||||
|
tomorrow = now + timedelta(days=1)
|
||||||
|
|
||||||
|
self.t("track {0:%Y-%m-%d}T10:00:00 - {0:%Y-%m-%d}T11:00:00 FOO".format(yesterday))
|
||||||
|
self.t("track {0:%Y-%m-%d}T10:00:00 - {0:%Y-%m-%d}T11:00:00 BAR".format(now))
|
||||||
|
self.t("track {0:%Y-%m-%d}T10:00:00 - {0:%Y-%m-%d}T11:00:00 BAZ".format(tomorrow))
|
||||||
|
|
||||||
|
code, out, err = self.t("summary :ids today")
|
||||||
|
|
||||||
|
self.assertIn("""
|
||||||
|
Wk Date Day ID Tags Start End Time Total
|
||||||
|
--- ---------- --- -- ---- -------- -------- ------- -------
|
||||||
|
W{1} {0:%Y-%m-%d} {0:%a} @2 BAR 10:00:00 11:00:00 1:00:00 1:00:00
|
||||||
|
|
||||||
|
1:00:00
|
||||||
|
""".format(now, now.isocalendar()[1]), out)
|
||||||
|
|
||||||
def test_with_day_gap(self):
|
def test_with_day_gap(self):
|
||||||
"""Summary should skip days with no data"""
|
"""Summary should skip days with no data"""
|
||||||
self.t("track 2017-03-09T10:00:00 - 2017-03-09T11:00:00")
|
self.t("track 2017-03-09T10:00:00 - 2017-03-09T11:00:00")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue