chronic 0.2.2 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.travis.yml +8 -0
- data/HISTORY.md +243 -0
- data/LICENSE +21 -0
- data/README.md +182 -0
- data/Rakefile +62 -15
- data/chronic.gemspec +23 -0
- data/lib/chronic/date.rb +82 -0
- data/lib/chronic/grabber.rb +24 -17
- data/lib/chronic/handler.rb +97 -0
- data/lib/chronic/handlers.rb +490 -312
- data/lib/chronic/mini_date.rb +38 -0
- data/lib/chronic/numerizer.rb +130 -0
- data/lib/chronic/ordinal.rb +33 -24
- data/lib/chronic/parser.rb +268 -0
- data/lib/chronic/pointer.rb +22 -17
- data/lib/chronic/repeater.rb +137 -107
- data/lib/chronic/repeaters/repeater_day.rb +51 -44
- data/lib/chronic/repeaters/repeater_day_name.rb +50 -43
- data/lib/chronic/repeaters/repeater_day_portion.rb +97 -81
- data/lib/chronic/repeaters/repeater_fortnight.rb +61 -54
- data/lib/chronic/repeaters/repeater_hour.rb +51 -44
- data/lib/chronic/repeaters/repeater_minute.rb +51 -44
- data/lib/chronic/repeaters/repeater_month.rb +79 -60
- data/lib/chronic/repeaters/repeater_month_name.rb +85 -83
- data/lib/chronic/repeaters/repeater_season.rb +110 -22
- data/lib/chronic/repeaters/repeater_season_name.rb +41 -22
- data/lib/chronic/repeaters/repeater_second.rb +41 -34
- data/lib/chronic/repeaters/repeater_time.rb +128 -104
- data/lib/chronic/repeaters/repeater_week.rb +65 -58
- data/lib/chronic/repeaters/repeater_weekday.rb +86 -0
- data/lib/chronic/repeaters/repeater_weekend.rb +59 -52
- data/lib/chronic/repeaters/repeater_year.rb +72 -52
- data/lib/chronic/scalar.rb +53 -46
- data/lib/chronic/season.rb +26 -0
- data/lib/chronic/separator.rb +174 -43
- data/lib/chronic/sign.rb +49 -0
- data/lib/chronic/span.rb +31 -0
- data/lib/chronic/tag.rb +37 -0
- data/lib/chronic/time.rb +40 -0
- data/lib/chronic/time_zone.rb +21 -11
- data/lib/chronic/token.rb +51 -0
- data/lib/chronic.rb +94 -69
- data/test/helper.rb +12 -0
- data/test/test_chronic.rb +183 -0
- data/test/test_daylight_savings.rb +118 -0
- data/test/{test_Handler.rb → test_handler.rb} +73 -55
- data/test/test_mini_date.rb +32 -0
- data/test/test_numerizer.rb +86 -0
- data/test/test_parsing.rb +891 -248
- data/test/{test_RepeaterDayName.rb → test_repeater_day_name.rb} +16 -17
- data/test/test_repeater_day_portion.rb +254 -0
- data/test/{test_RepeaterFortnight.rb → test_repeater_fortnight.rb} +17 -18
- data/test/{test_RepeaterHour.rb → test_repeater_hour.rb} +23 -20
- data/test/test_repeater_minute.rb +34 -0
- data/test/{test_RepeaterMonth.rb → test_repeater_month.rb} +21 -18
- data/test/{test_RepeaterMonthName.rb → test_repeater_month_name.rb} +18 -19
- data/test/test_repeater_season.rb +40 -0
- data/test/{test_RepeaterTime.rb → test_repeater_time.rb} +39 -23
- data/test/{test_RepeaterWeek.rb → test_repeater_week.rb} +17 -18
- data/test/test_repeater_weekday.rb +55 -0
- data/test/{test_RepeaterWeekend.rb → test_repeater_weekend.rb} +22 -23
- data/test/{test_RepeaterYear.rb → test_repeater_year.rb} +25 -19
- data/test/{test_Span.rb → test_span.rb} +7 -8
- data/test/{test_Token.rb → test_token.rb} +6 -7
- metadata +163 -85
- data/History.txt +0 -49
- data/Manifest.txt +0 -47
- data/README.txt +0 -149
- data/lib/chronic/chronic.rb +0 -239
- data/lib/numerizer/numerizer.rb +0 -103
- data/test/suite.rb +0 -9
- data/test/test_Chronic.rb +0 -50
- data/test/test_Numerizer.rb +0 -48
- data/test/test_Time.rb +0 -50
data/lib/chronic.rb
CHANGED
|
@@ -1,16 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
# Name: Chronic
|
|
4
|
-
# Author: Tom Preston-Werner
|
|
5
|
-
# Purpose: Parse natural language dates and times into Time or
|
|
6
|
-
# Chronic::Span objects
|
|
7
|
-
#
|
|
8
|
-
#=============================================================================
|
|
1
|
+
require 'time'
|
|
2
|
+
require 'date'
|
|
9
3
|
|
|
10
|
-
|
|
4
|
+
require 'chronic/parser'
|
|
5
|
+
require 'chronic/date'
|
|
6
|
+
require 'chronic/time'
|
|
11
7
|
|
|
12
|
-
require 'chronic/
|
|
8
|
+
require 'chronic/handler'
|
|
13
9
|
require 'chronic/handlers'
|
|
10
|
+
require 'chronic/mini_date'
|
|
11
|
+
require 'chronic/tag'
|
|
12
|
+
require 'chronic/span'
|
|
13
|
+
require 'chronic/token'
|
|
14
|
+
require 'chronic/grabber'
|
|
15
|
+
require 'chronic/pointer'
|
|
16
|
+
require 'chronic/scalar'
|
|
17
|
+
require 'chronic/ordinal'
|
|
18
|
+
require 'chronic/separator'
|
|
19
|
+
require 'chronic/sign'
|
|
20
|
+
require 'chronic/time_zone'
|
|
21
|
+
require 'chronic/numerizer'
|
|
22
|
+
require 'chronic/season'
|
|
14
23
|
|
|
15
24
|
require 'chronic/repeater'
|
|
16
25
|
require 'chronic/repeaters/repeater_year'
|
|
@@ -21,6 +30,7 @@ require 'chronic/repeaters/repeater_month_name'
|
|
|
21
30
|
require 'chronic/repeaters/repeater_fortnight'
|
|
22
31
|
require 'chronic/repeaters/repeater_week'
|
|
23
32
|
require 'chronic/repeaters/repeater_weekend'
|
|
33
|
+
require 'chronic/repeaters/repeater_weekday'
|
|
24
34
|
require 'chronic/repeaters/repeater_day'
|
|
25
35
|
require 'chronic/repeaters/repeater_day_name'
|
|
26
36
|
require 'chronic/repeaters/repeater_day_portion'
|
|
@@ -29,87 +39,95 @@ require 'chronic/repeaters/repeater_minute'
|
|
|
29
39
|
require 'chronic/repeaters/repeater_second'
|
|
30
40
|
require 'chronic/repeaters/repeater_time'
|
|
31
41
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
require 'chronic
|
|
37
|
-
|
|
42
|
+
# Parse natural language dates and times into Time or Chronic::Span objects.
|
|
43
|
+
#
|
|
44
|
+
# Examples:
|
|
45
|
+
#
|
|
46
|
+
# require 'chronic'
|
|
47
|
+
#
|
|
48
|
+
# Time.now #=> Sun Aug 27 23:18:25 PDT 2006
|
|
49
|
+
#
|
|
50
|
+
# Chronic.parse('tomorrow')
|
|
51
|
+
# #=> Mon Aug 28 12:00:00 PDT 2006
|
|
52
|
+
#
|
|
53
|
+
# Chronic.parse('monday', :context => :past)
|
|
54
|
+
# #=> Mon Aug 21 12:00:00 PDT 2006
|
|
55
|
+
module Chronic
|
|
56
|
+
VERSION = "0.10.2"
|
|
38
57
|
|
|
39
|
-
|
|
58
|
+
class << self
|
|
40
59
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def self.debug; false; end
|
|
45
|
-
end
|
|
60
|
+
# Returns true when debug mode is enabled.
|
|
61
|
+
attr_accessor :debug
|
|
46
62
|
|
|
47
|
-
|
|
63
|
+
# Examples:
|
|
64
|
+
#
|
|
65
|
+
# require 'chronic'
|
|
66
|
+
# require 'active_support/time'
|
|
67
|
+
#
|
|
68
|
+
# Time.zone = 'UTC'
|
|
69
|
+
# Chronic.time_class = Time.zone
|
|
70
|
+
# Chronic.parse('June 15 2006 at 5:54 AM')
|
|
71
|
+
# # => Thu, 15 Jun 2006 05:45:00 UTC +00:00
|
|
72
|
+
#
|
|
73
|
+
# Returns The Time class Chronic uses internally.
|
|
74
|
+
attr_accessor :time_class
|
|
75
|
+
end
|
|
48
76
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
puts
|
|
52
|
-
end
|
|
77
|
+
self.debug = false
|
|
78
|
+
self.time_class = ::Time
|
|
53
79
|
|
|
54
|
-
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
#
|
|
68
|
-
#
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
#
|
|
78
|
-
|
|
79
|
-
# end
|
|
80
|
-
|
|
81
|
-
class Time
|
|
82
|
-
def self.construct(year, month = 1, day = 1, hour = 0, minute = 0, second = 0)
|
|
80
|
+
|
|
81
|
+
# Parses a string containing a natural language date or time.
|
|
82
|
+
#
|
|
83
|
+
# If the parser can find a date or time, either a Time or Chronic::Span
|
|
84
|
+
# will be returned (depending on the value of `:guess`). If no
|
|
85
|
+
# date or time can be found, `nil` will be returned.
|
|
86
|
+
#
|
|
87
|
+
# text - The String text to parse.
|
|
88
|
+
# opts - An optional Hash of configuration options passed to Parser::new.
|
|
89
|
+
def self.parse(text, options = {})
|
|
90
|
+
Parser.new(options).parse(text)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Construct a new time object determining possible month overflows
|
|
94
|
+
# and leap years.
|
|
95
|
+
#
|
|
96
|
+
# year - Integer year.
|
|
97
|
+
# month - Integer month.
|
|
98
|
+
# day - Integer day.
|
|
99
|
+
# hour - Integer hour.
|
|
100
|
+
# minute - Integer minute.
|
|
101
|
+
# second - Integer second.
|
|
102
|
+
#
|
|
103
|
+
# Returns a new Time object constructed from these params.
|
|
104
|
+
def self.construct(year, month = 1, day = 1, hour = 0, minute = 0, second = 0, offset = nil)
|
|
83
105
|
if second >= 60
|
|
84
106
|
minute += second / 60
|
|
85
107
|
second = second % 60
|
|
86
108
|
end
|
|
87
|
-
|
|
109
|
+
|
|
88
110
|
if minute >= 60
|
|
89
111
|
hour += minute / 60
|
|
90
112
|
minute = minute % 60
|
|
91
113
|
end
|
|
92
|
-
|
|
114
|
+
|
|
93
115
|
if hour >= 24
|
|
94
116
|
day += hour / 24
|
|
95
117
|
hour = hour % 24
|
|
96
118
|
end
|
|
97
|
-
|
|
119
|
+
|
|
98
120
|
# determine if there is a day overflow. this is complicated by our crappy calendar
|
|
99
121
|
# system (non-constant number of days per month)
|
|
100
122
|
day <= 56 || raise("day must be no more than 56 (makes month resolution easier)")
|
|
101
|
-
if day > 28
|
|
102
|
-
|
|
103
|
-
leap_year = (year % 4 == 0) && !(year % 100 == 0)
|
|
104
|
-
leap_year_month_days = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
|
105
|
-
common_year_month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
|
106
|
-
days_this_month = leap_year ? leap_year_month_days[month - 1] : common_year_month_days[month - 1]
|
|
123
|
+
if day > 28 # no month ever has fewer than 28 days, so only do this if necessary
|
|
124
|
+
days_this_month = ::Date.leap?(year) ? Date::MONTH_DAYS_LEAP[month] : Date::MONTH_DAYS[month]
|
|
107
125
|
if day > days_this_month
|
|
108
126
|
month += day / days_this_month
|
|
109
127
|
day = day % days_this_month
|
|
110
128
|
end
|
|
111
129
|
end
|
|
112
|
-
|
|
130
|
+
|
|
113
131
|
if month > 12
|
|
114
132
|
if month % 12 == 0
|
|
115
133
|
year += (month - 12) / 12
|
|
@@ -119,7 +137,14 @@ class Time
|
|
|
119
137
|
month = month % 12
|
|
120
138
|
end
|
|
121
139
|
end
|
|
122
|
-
|
|
123
|
-
|
|
140
|
+
if Chronic.time_class.name == "Date"
|
|
141
|
+
Chronic.time_class.new(year, month, day)
|
|
142
|
+
elsif not Chronic.time_class.respond_to?(:new) or (RUBY_VERSION.to_f < 1.9 and Chronic.time_class.name == "Time")
|
|
143
|
+
Chronic.time_class.local(year, month, day, hour, minute, second)
|
|
144
|
+
else
|
|
145
|
+
offset = Time::normalize_offset(offset) if Chronic.time_class.name == "DateTime"
|
|
146
|
+
Chronic.time_class.new(year, month, day, hour, minute, second, offset)
|
|
147
|
+
end
|
|
124
148
|
end
|
|
125
|
-
|
|
149
|
+
|
|
150
|
+
end
|
data/test/helper.rb
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
unless defined? Chronic
|
|
2
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
|
3
|
+
require 'chronic'
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
require 'minitest/autorun'
|
|
7
|
+
|
|
8
|
+
class TestCase < MiniTest::Test
|
|
9
|
+
def self.test(name, &block)
|
|
10
|
+
define_method("test_#{name.gsub(/\W/, '_')}", &block) if block
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
require 'helper'
|
|
2
|
+
|
|
3
|
+
class TestChronic < TestCase
|
|
4
|
+
|
|
5
|
+
def setup
|
|
6
|
+
# Wed Aug 16 14:00:00 UTC 2006
|
|
7
|
+
@now = Time.local(2006, 8, 16, 14, 0, 0, 0)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def test_pre_normalize
|
|
11
|
+
assert_equal Chronic::Parser.new.pre_normalize('12:55 pm'), Chronic::Parser.new.pre_normalize('12.55 pm')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_pre_normalize_numerized_string
|
|
15
|
+
string = 'two and a half years'
|
|
16
|
+
assert_equal Chronic::Numerizer.numerize(string), Chronic::Parser.new.pre_normalize(string)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_post_normalize_am_pm_aliases
|
|
20
|
+
# affect wanted patterns
|
|
21
|
+
|
|
22
|
+
tokens = [Chronic::Token.new("5:00"), Chronic::Token.new("morning")]
|
|
23
|
+
tokens[0].tag(Chronic::RepeaterTime.new("5:00"))
|
|
24
|
+
tokens[1].tag(Chronic::RepeaterDayPortion.new(:morning))
|
|
25
|
+
|
|
26
|
+
assert_equal :morning, tokens[1].tags[0].type
|
|
27
|
+
|
|
28
|
+
tokens = Chronic::Handlers.dealias_and_disambiguate_times(tokens, {})
|
|
29
|
+
|
|
30
|
+
assert_equal :am, tokens[1].tags[0].type
|
|
31
|
+
assert_equal 2, tokens.size
|
|
32
|
+
|
|
33
|
+
# don't affect unwanted patterns
|
|
34
|
+
|
|
35
|
+
tokens = [Chronic::Token.new("friday"), Chronic::Token.new("morning")]
|
|
36
|
+
tokens[0].tag(Chronic::RepeaterDayName.new(:friday))
|
|
37
|
+
tokens[1].tag(Chronic::RepeaterDayPortion.new(:morning))
|
|
38
|
+
|
|
39
|
+
assert_equal :morning, tokens[1].tags[0].type
|
|
40
|
+
|
|
41
|
+
tokens = Chronic::Handlers.dealias_and_disambiguate_times(tokens, {})
|
|
42
|
+
|
|
43
|
+
assert_equal :morning, tokens[1].tags[0].type
|
|
44
|
+
assert_equal 2, tokens.size
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def test_guess
|
|
48
|
+
span = Chronic::Span.new(Time.local(2006, 8, 16, 0), Time.local(2006, 8, 17, 0))
|
|
49
|
+
assert_equal Time.local(2006, 8, 16, 12), Chronic::Parser.new.guess(span)
|
|
50
|
+
|
|
51
|
+
span = Chronic::Span.new(Time.local(2006, 8, 16, 0), Time.local(2006, 8, 17, 0, 0, 1))
|
|
52
|
+
assert_equal Time.local(2006, 8, 16, 12), Chronic::Parser.new.guess(span)
|
|
53
|
+
|
|
54
|
+
span = Chronic::Span.new(Time.local(2006, 11), Time.local(2006, 12))
|
|
55
|
+
assert_equal Time.local(2006, 11, 16), Chronic::Parser.new.guess(span)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def test_endian_definitions
|
|
59
|
+
# middle, little
|
|
60
|
+
endians = [
|
|
61
|
+
Chronic::Handler.new([:scalar_month, [:separator_slash, :separator_dash], :scalar_day, [:separator_slash, :separator_dash], :scalar_year, :separator_at?, 'time?'], :handle_sm_sd_sy),
|
|
62
|
+
Chronic::Handler.new([:scalar_month, [:separator_slash, :separator_dash], :scalar_day, :separator_at?, 'time?'], :handle_sm_sd),
|
|
63
|
+
Chronic::Handler.new([:scalar_day, [:separator_slash, :separator_dash], :scalar_month, :separator_at?, 'time?'], :handle_sd_sm),
|
|
64
|
+
Chronic::Handler.new([:scalar_day, [:separator_slash, :separator_dash], :scalar_month, [:separator_slash, :separator_dash], :scalar_year, :separator_at?, 'time?'], :handle_sd_sm_sy)
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
assert_equal endians, Chronic::Parser.new.definitions[:endian]
|
|
68
|
+
|
|
69
|
+
defs = Chronic::Parser.new.definitions(:endian_precedence => :little)
|
|
70
|
+
assert_equal endians.reverse, defs[:endian]
|
|
71
|
+
|
|
72
|
+
defs = Chronic::Parser.new.definitions(:endian_precedence => [:little, :middle])
|
|
73
|
+
assert_equal endians.reverse, defs[:endian]
|
|
74
|
+
|
|
75
|
+
assert_raises(ArgumentError) do
|
|
76
|
+
Chronic::Parser.new.definitions(:endian_precedence => :invalid)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def test_debug
|
|
81
|
+
require 'stringio'
|
|
82
|
+
$stdout = StringIO.new
|
|
83
|
+
Chronic.debug = true
|
|
84
|
+
|
|
85
|
+
Chronic.parse 'now'
|
|
86
|
+
assert $stdout.string.include?('this(grabber-this)')
|
|
87
|
+
ensure
|
|
88
|
+
$stdout = STDOUT
|
|
89
|
+
Chronic.debug = false
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Chronic.construct
|
|
93
|
+
|
|
94
|
+
def test_normal
|
|
95
|
+
assert_equal Time.local(2006, 1, 2, 0, 0, 0), Chronic.construct(2006, 1, 2, 0, 0, 0)
|
|
96
|
+
assert_equal Time.local(2006, 1, 2, 3, 0, 0), Chronic.construct(2006, 1, 2, 3, 0, 0)
|
|
97
|
+
assert_equal Time.local(2006, 1, 2, 3, 4, 0), Chronic.construct(2006, 1, 2, 3, 4, 0)
|
|
98
|
+
assert_equal Time.local(2006, 1, 2, 3, 4, 5), Chronic.construct(2006, 1, 2, 3, 4, 5)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def test_second_overflow
|
|
102
|
+
assert_equal Time.local(2006, 1, 1, 0, 1, 30), Chronic.construct(2006, 1, 1, 0, 0, 90)
|
|
103
|
+
assert_equal Time.local(2006, 1, 1, 0, 5, 0), Chronic.construct(2006, 1, 1, 0, 0, 300)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def test_minute_overflow
|
|
107
|
+
assert_equal Time.local(2006, 1, 1, 1, 30), Chronic.construct(2006, 1, 1, 0, 90)
|
|
108
|
+
assert_equal Time.local(2006, 1, 1, 5), Chronic.construct(2006, 1, 1, 0, 300)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def test_hour_overflow
|
|
112
|
+
assert_equal Time.local(2006, 1, 2, 12), Chronic.construct(2006, 1, 1, 36)
|
|
113
|
+
assert_equal Time.local(2006, 1, 7), Chronic.construct(2006, 1, 1, 144)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def test_day_overflow
|
|
117
|
+
assert_equal Time.local(2006, 2, 1), Chronic.construct(2006, 1, 32)
|
|
118
|
+
assert_equal Time.local(2006, 3, 5), Chronic.construct(2006, 2, 33)
|
|
119
|
+
assert_equal Time.local(2004, 3, 4), Chronic.construct(2004, 2, 33)
|
|
120
|
+
assert_equal Time.local(2000, 3, 4), Chronic.construct(2000, 2, 33)
|
|
121
|
+
|
|
122
|
+
assert_raises(RuntimeError) do
|
|
123
|
+
Chronic.construct(2006, 1, 57)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def test_month_overflow
|
|
128
|
+
assert_equal Time.local(2006, 1), Chronic.construct(2005, 13)
|
|
129
|
+
assert_equal Time.local(2005, 12), Chronic.construct(2000, 72)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def test_time
|
|
133
|
+
org = Chronic.time_class
|
|
134
|
+
begin
|
|
135
|
+
Chronic.time_class = ::Time
|
|
136
|
+
assert_equal ::Time.new(2013, 8, 27, 20, 30, 40, '+05:30'), Chronic.construct(2013, 8, 27, 20, 30, 40, '+05:30')
|
|
137
|
+
assert_equal ::Time.new(2013, 8, 27, 20, 30, 40, '-08:00'), Chronic.construct(2013, 8, 27, 20, 30, 40, -28800)
|
|
138
|
+
ensure
|
|
139
|
+
Chronic.time_class = org
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def test_date
|
|
144
|
+
org = Chronic.time_class
|
|
145
|
+
begin
|
|
146
|
+
Chronic.time_class = ::Date
|
|
147
|
+
assert_equal Date.new(2013, 8, 27), Chronic.construct(2013, 8, 27)
|
|
148
|
+
ensure
|
|
149
|
+
Chronic.time_class = org
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def test_datetime
|
|
154
|
+
org = Chronic.time_class
|
|
155
|
+
begin
|
|
156
|
+
Chronic.time_class = ::DateTime
|
|
157
|
+
assert_equal DateTime.new(2013, 8, 27, 20, 30, 40, '+05:30'), Chronic.construct(2013, 8, 27, 20, 30, 40, '+05:30')
|
|
158
|
+
assert_equal DateTime.new(2013, 8, 27, 20, 30, 40, '-08:00'), Chronic.construct(2013, 8, 27, 20, 30, 40, -28800)
|
|
159
|
+
ensure
|
|
160
|
+
Chronic.time_class = org
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def test_activesupport
|
|
165
|
+
=begin
|
|
166
|
+
# ActiveSupport needs MiniTest '~> 4.2' which conflicts with '~> 5.0'
|
|
167
|
+
require 'active_support/time'
|
|
168
|
+
org = Chronic.time_class
|
|
169
|
+
org_zone = ::Time.zone
|
|
170
|
+
begin
|
|
171
|
+
::Time.zone = "Tokyo"
|
|
172
|
+
Chronic.time_class = ::Time.zone
|
|
173
|
+
assert_equal Time.new(2013, 8, 27, 20, 30, 40, '+09:00'), Chronic.construct(2013, 8, 27, 20, 30, 40)
|
|
174
|
+
::Time.zone = "Indiana (East)"
|
|
175
|
+
Chronic.time_class = ::Time.zone
|
|
176
|
+
assert_equal Time.new(2013, 8, 27, 20, 30, 40, -14400), Chronic.construct(2013, 8, 27, 20, 30, 40)
|
|
177
|
+
ensure
|
|
178
|
+
Chronic.time_class = org
|
|
179
|
+
::Time.zone = org_zone
|
|
180
|
+
end
|
|
181
|
+
=end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
require 'helper'
|
|
2
|
+
|
|
3
|
+
class TestDaylightSavings < TestCase
|
|
4
|
+
|
|
5
|
+
def setup
|
|
6
|
+
@begin_daylight_savings = Time.local(2008, 3, 9, 5, 0, 0, 0)
|
|
7
|
+
@end_daylight_savings = Time.local(2008, 11, 2, 5, 0, 0, 0)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def test_begin_past
|
|
11
|
+
# ambiguous - resolve to last night
|
|
12
|
+
t = Chronic::RepeaterTime.new('900')
|
|
13
|
+
t.start = @begin_daylight_savings
|
|
14
|
+
assert_equal Time.local(2008, 3, 8, 21), t.next(:past).begin
|
|
15
|
+
|
|
16
|
+
# ambiguous - resolve to this afternoon
|
|
17
|
+
t = Chronic::RepeaterTime.new('900')
|
|
18
|
+
t.start = Time.local(2008, 3, 9, 22, 0, 0, 0)
|
|
19
|
+
assert_equal Time.local(2008, 3, 9, 21), t.next(:past).begin
|
|
20
|
+
|
|
21
|
+
# ambiguous - resolve to this morning
|
|
22
|
+
t = Chronic::RepeaterTime.new('400')
|
|
23
|
+
t.start = @begin_daylight_savings
|
|
24
|
+
assert_equal Time.local(2008, 3, 9, 4), t.next(:past).begin
|
|
25
|
+
|
|
26
|
+
# unambiguous - resolve to today
|
|
27
|
+
t = Chronic::RepeaterTime.new('0400')
|
|
28
|
+
t.start = @begin_daylight_savings
|
|
29
|
+
assert_equal Time.local(2008, 3, 9, 4), t.next(:past).begin
|
|
30
|
+
|
|
31
|
+
# unambiguous - resolve to yesterday
|
|
32
|
+
t = Chronic::RepeaterTime.new('1300')
|
|
33
|
+
t.start = @begin_daylight_savings
|
|
34
|
+
assert_equal Time.local(2008, 3, 8, 13), t.next(:past).begin
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_begin_future
|
|
38
|
+
# ambiguous - resolve to this morning
|
|
39
|
+
t = Chronic::RepeaterTime.new('900')
|
|
40
|
+
t.start = @begin_daylight_savings
|
|
41
|
+
assert_equal Time.local(2008, 3, 9, 9), t.next(:future).begin
|
|
42
|
+
|
|
43
|
+
# ambiguous - resolve to this afternoon
|
|
44
|
+
t = Chronic::RepeaterTime.new('900')
|
|
45
|
+
t.start = Time.local(2008, 3, 9, 13, 0, 0, 0)
|
|
46
|
+
assert_equal Time.local(2008, 3, 9, 21), t.next(:future).begin
|
|
47
|
+
|
|
48
|
+
# ambiguous - resolve to tomorrow
|
|
49
|
+
t = Chronic::RepeaterTime.new('900')
|
|
50
|
+
t.start = Time.local(2008, 3, 9, 22, 0, 0, 0)
|
|
51
|
+
assert_equal Time.local(2008, 3, 10, 9), t.next(:future).begin
|
|
52
|
+
|
|
53
|
+
# unambiguous - resolve to today
|
|
54
|
+
t = Chronic::RepeaterTime.new('0900')
|
|
55
|
+
t.start = @begin_daylight_savings
|
|
56
|
+
assert_equal Time.local(2008, 3, 9, 9), t.next(:future).begin
|
|
57
|
+
|
|
58
|
+
# unambiguous - resolve to tomorrow
|
|
59
|
+
t = Chronic::RepeaterTime.new('0400')
|
|
60
|
+
t.start = @begin_daylight_savings
|
|
61
|
+
assert_equal Time.local(2008, 3, 10, 4), t.next(:future).begin
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def test_end_past
|
|
65
|
+
# ambiguous - resolve to last night
|
|
66
|
+
t = Chronic::RepeaterTime.new('900')
|
|
67
|
+
t.start = @end_daylight_savings
|
|
68
|
+
assert_equal Time.local(2008, 11, 1, 21), t.next(:past).begin
|
|
69
|
+
|
|
70
|
+
# ambiguous - resolve to this afternoon
|
|
71
|
+
t = Chronic::RepeaterTime.new('900')
|
|
72
|
+
t.start = Time.local(2008, 11, 2, 22, 0, 0, 0)
|
|
73
|
+
assert_equal Time.local(2008, 11, 2, 21), t.next(:past).begin
|
|
74
|
+
|
|
75
|
+
# ambiguous - resolve to this morning
|
|
76
|
+
t = Chronic::RepeaterTime.new('400')
|
|
77
|
+
t.start = @end_daylight_savings
|
|
78
|
+
assert_equal Time.local(2008, 11, 2, 4), t.next(:past).begin
|
|
79
|
+
|
|
80
|
+
# unambiguous - resolve to today
|
|
81
|
+
t = Chronic::RepeaterTime.new('0400')
|
|
82
|
+
t.start = @end_daylight_savings
|
|
83
|
+
assert_equal Time.local(2008, 11, 2, 4), t.next(:past).begin
|
|
84
|
+
|
|
85
|
+
# unambiguous - resolve to yesterday
|
|
86
|
+
t = Chronic::RepeaterTime.new('1300')
|
|
87
|
+
t.start = @end_daylight_savings
|
|
88
|
+
assert_equal Time.local(2008, 11, 1, 13), t.next(:past).begin
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def test_end_future
|
|
92
|
+
# ambiguous - resolve to this morning
|
|
93
|
+
t = Chronic::RepeaterTime.new('900')
|
|
94
|
+
t.start = @end_daylight_savings
|
|
95
|
+
assert_equal Time.local(2008, 11, 2, 9), t.next(:future).begin
|
|
96
|
+
|
|
97
|
+
# ambiguous - resolve to this afternoon
|
|
98
|
+
t = Chronic::RepeaterTime.new('900')
|
|
99
|
+
t.start = Time.local(2008, 11, 2, 13, 0, 0, 0)
|
|
100
|
+
assert_equal Time.local(2008, 11, 2, 21), t.next(:future).begin
|
|
101
|
+
|
|
102
|
+
# ambiguous - resolve to tomorrow
|
|
103
|
+
t = Chronic::RepeaterTime.new('900')
|
|
104
|
+
t.start = Time.local(2008, 11, 2, 22, 0, 0, 0)
|
|
105
|
+
assert_equal Time.local(2008, 11, 3, 9), t.next(:future).begin
|
|
106
|
+
|
|
107
|
+
# unambiguous - resolve to today
|
|
108
|
+
t = Chronic::RepeaterTime.new('0900')
|
|
109
|
+
t.start = @end_daylight_savings
|
|
110
|
+
assert_equal Time.local(2008, 11, 2, 9), t.next(:future).begin
|
|
111
|
+
|
|
112
|
+
# unambiguous - resolve to tomorrow
|
|
113
|
+
t = Chronic::RepeaterTime.new('0400')
|
|
114
|
+
t.start = @end_daylight_savings
|
|
115
|
+
assert_equal Time.local(2008, 11, 3, 4), t.next(:future).begin
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
end
|