chronic 0.1.5 → 0.6.5

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.
Files changed (68) hide show
  1. data/.gemtest +0 -0
  2. data/.gitignore +5 -0
  3. data/.yardopts +3 -0
  4. data/HISTORY.md +180 -0
  5. data/LICENSE +21 -0
  6. data/README.md +176 -0
  7. data/Rakefile +39 -32
  8. data/chronic.gemspec +17 -0
  9. data/lib/chronic/chronic.rb +294 -208
  10. data/lib/chronic/grabber.rb +22 -17
  11. data/lib/chronic/handler.rb +90 -0
  12. data/lib/chronic/handlers.rb +365 -278
  13. data/lib/chronic/mini_date.rb +38 -0
  14. data/lib/chronic/numerizer.rb +121 -0
  15. data/lib/chronic/ordinal.rb +23 -19
  16. data/lib/chronic/pointer.rb +20 -17
  17. data/lib/chronic/repeater.rb +126 -105
  18. data/lib/chronic/repeaters/repeater_day.rb +49 -43
  19. data/lib/chronic/repeaters/repeater_day_name.rb +48 -42
  20. data/lib/chronic/repeaters/repeater_day_portion.rb +81 -80
  21. data/lib/chronic/repeaters/repeater_fortnight.rb +59 -53
  22. data/lib/chronic/repeaters/repeater_hour.rb +49 -43
  23. data/lib/chronic/repeaters/repeater_minute.rb +55 -39
  24. data/lib/chronic/repeaters/repeater_month.rb +77 -55
  25. data/lib/chronic/repeaters/repeater_month_name.rb +83 -82
  26. data/lib/chronic/repeaters/repeater_season.rb +107 -21
  27. data/lib/chronic/repeaters/repeater_season_name.rb +41 -22
  28. data/lib/chronic/repeaters/repeater_second.rb +39 -33
  29. data/lib/chronic/repeaters/repeater_time.rb +117 -103
  30. data/lib/chronic/repeaters/repeater_week.rb +63 -57
  31. data/lib/chronic/repeaters/repeater_weekday.rb +85 -0
  32. data/lib/chronic/repeaters/repeater_weekend.rb +64 -9
  33. data/lib/chronic/repeaters/repeater_year.rb +70 -51
  34. data/lib/chronic/scalar.rb +64 -29
  35. data/lib/chronic/season.rb +37 -0
  36. data/lib/chronic/separator.rb +50 -38
  37. data/lib/chronic/span.rb +31 -0
  38. data/lib/chronic/tag.rb +42 -0
  39. data/lib/chronic/time_zone.rb +30 -0
  40. data/lib/chronic/token.rb +45 -0
  41. data/lib/chronic.rb +86 -22
  42. data/test/helper.rb +6 -0
  43. data/test/test_Chronic.rb +118 -20
  44. data/test/test_DaylightSavings.rb +118 -0
  45. data/test/test_Handler.rb +36 -42
  46. data/test/test_MiniDate.rb +32 -0
  47. data/test/test_Numerizer.rb +72 -0
  48. data/test/test_RepeaterDayName.rb +15 -16
  49. data/test/test_RepeaterFortnight.rb +16 -17
  50. data/test/test_RepeaterHour.rb +22 -19
  51. data/test/test_RepeaterMinute.rb +34 -0
  52. data/test/test_RepeaterMonth.rb +20 -17
  53. data/test/test_RepeaterMonthName.rb +17 -18
  54. data/test/test_RepeaterSeason.rb +40 -0
  55. data/test/test_RepeaterTime.rb +20 -22
  56. data/test/test_RepeaterWeek.rb +16 -17
  57. data/test/test_RepeaterWeekday.rb +55 -0
  58. data/test/test_RepeaterWeekend.rb +74 -0
  59. data/test/test_RepeaterYear.rb +24 -18
  60. data/test/test_Span.rb +5 -6
  61. data/test/test_Token.rb +5 -6
  62. data/test/test_parsing.rb +743 -338
  63. metadata +81 -54
  64. data/History.txt +0 -29
  65. data/Manifest.txt +0 -43
  66. data/README.txt +0 -149
  67. data/test/parse_numbers.rb +0 -50
  68. data/test/suite.rb +0 -9
@@ -1,114 +1,128 @@
1
- class Chronic::RepeaterTime < Chronic::Repeater #:nodoc:
2
- class Tick #:nodoc:
3
- attr_accessor :time
4
-
5
- def initialize(time, ambiguous = false)
6
- @time = time
7
- @ambiguous = ambiguous
8
- end
9
-
10
- def ambiguous?
11
- @ambiguous
12
- end
13
-
14
- def *(other)
15
- Tick.new(@time * other, @ambiguous)
16
- end
17
-
18
- def to_f
19
- @time.to_f
20
- end
21
-
22
- def to_s
23
- @time.to_s + (@ambiguous ? '?' : '')
1
+ module Chronic
2
+ class RepeaterTime < Repeater #:nodoc:
3
+ class Tick #:nodoc:
4
+ attr_accessor :time
5
+
6
+ def initialize(time, ambiguous = false)
7
+ @time = time
8
+ @ambiguous = ambiguous
9
+ end
10
+
11
+ def ambiguous?
12
+ @ambiguous
13
+ end
14
+
15
+ def *(other)
16
+ Tick.new(@time * other, @ambiguous)
17
+ end
18
+
19
+ def to_f
20
+ @time.to_f
21
+ end
22
+
23
+ def to_s
24
+ @time.to_s + (@ambiguous ? '?' : '')
25
+ end
26
+
24
27
  end
25
- end
26
-
27
- def initialize(time, options = {})
28
- t = time.gsub(/\:/, '')
29
- @type =
30
- if (1..2) === t.size
31
- Tick.new(t.to_i * 60 * 60, true)
32
- elsif t.size == 3
33
- Tick.new((t[0..0].to_i * 60 * 60) + (t[1..2].to_i * 60), true)
34
- elsif t.size == 4
35
- ambiguous = time =~ /:/ && t[0..0].to_i != 0 && t[0..1].to_i <= 12
36
- Tick.new(t[0..1].to_i * 60 * 60 + t[2..3].to_i * 60, ambiguous)
37
- elsif t.size == 5
38
- Tick.new(t[0..0].to_i * 60 * 60 + t[1..2].to_i * 60 + t[3..4].to_i, true)
39
- elsif t.size == 6
40
- ambiguous = time =~ /:/ && t[0..0].to_i != 0 && t[0..1].to_i <= 12
41
- Tick.new(t[0..1].to_i * 60 * 60 + t[2..3].to_i * 60 + t[4..5].to_i, ambiguous)
42
- else
43
- raise("Time cannot exceed six digits")
28
+
29
+ def initialize(time)
30
+ t = time.gsub(/\:/, '')
31
+
32
+ @type =
33
+ case t.size
34
+ when 1..2
35
+ hours = t.to_i
36
+ Tick.new((hours == 12 ? 0 : hours) * 60 * 60, true)
37
+ when 3
38
+ hours = t[0..0].to_i
39
+ ambiguous = hours > 0
40
+ Tick.new((hours * 60 * 60) + (t[1..2].to_i * 60), ambiguous)
41
+ when 4
42
+ ambiguous = time =~ /:/ && t[0..0].to_i != 0 && t[0..1].to_i <= 12
43
+ hours = t[0..1].to_i
44
+ hours == 12 ? Tick.new(0 * 60 * 60 + t[2..3].to_i * 60, ambiguous) : Tick.new(hours * 60 * 60 + t[2..3].to_i * 60, ambiguous)
45
+ when 5
46
+ Tick.new(t[0..0].to_i * 60 * 60 + t[1..2].to_i * 60 + t[3..4].to_i, true)
47
+ when 6
48
+ ambiguous = time =~ /:/ && t[0..0].to_i != 0 && t[0..1].to_i <= 12
49
+ hours = t[0..1].to_i
50
+ hours == 12 ? Tick.new(0 * 60 * 60 + t[2..3].to_i * 60 + t[4..5].to_i, ambiguous) : Tick.new(hours * 60 * 60 + t[2..3].to_i * 60 + t[4..5].to_i, ambiguous)
51
+ else
52
+ raise("Time cannot exceed six digits")
53
+ end
44
54
  end
45
- end
46
-
47
- # Return the next past or future Span for the time that this Repeater represents
48
- # pointer - Symbol representing which temporal direction to fetch the next day
49
- # must be either :past or :future
50
- def next(pointer)
51
- super
52
-
53
- half_day = 60 * 60 * 12
54
- full_day = 60 * 60 * 24
55
-
56
- first = false
57
-
58
- unless @current_time
59
- first = true
60
- midnight = Time.local(@now.year, @now.month, @now.day)
61
- yesterday_midnight = midnight - full_day
62
- tomorrow_midnight = midnight + full_day
63
-
64
- catch :done do
65
- if pointer == :future
66
- if @type.ambiguous?
67
- [midnight + @type, midnight + half_day + @type, tomorrow_midnight + @type].each do |t|
68
- (@current_time = t; throw :done) if t > @now
69
- end
70
- else
71
- [midnight + @type, tomorrow_midnight + @type].each do |t|
72
- (@current_time = t; throw :done) if t > @now
73
- end
74
- end
75
- else # pointer == :past
76
- if @type.ambiguous?
77
- [midnight + half_day + @type, midnight + @type, yesterday_midnight + @type * 2].each do |t|
78
- (@current_time = t; throw :done) if t < @now
55
+
56
+ # Return the next past or future Span for the time that this Repeater represents
57
+ # pointer - Symbol representing which temporal direction to fetch the next day
58
+ # must be either :past or :future
59
+ def next(pointer)
60
+ super
61
+
62
+ half_day = 60 * 60 * 12
63
+ full_day = 60 * 60 * 24
64
+
65
+ first = false
66
+
67
+ unless @current_time
68
+ first = true
69
+ midnight = Chronic.time_class.local(@now.year, @now.month, @now.day)
70
+
71
+ yesterday_midnight = midnight - full_day
72
+ tomorrow_midnight = midnight + full_day
73
+
74
+ offset_fix = midnight.gmt_offset - tomorrow_midnight.gmt_offset
75
+ tomorrow_midnight += offset_fix
76
+
77
+ catch :done do
78
+ if pointer == :future
79
+ if @type.ambiguous?
80
+ [midnight + @type.time + offset_fix, midnight + half_day + @type.time + offset_fix, tomorrow_midnight + @type.time].each do |t|
81
+ (@current_time = t; throw :done) if t >= @now
82
+ end
83
+ else
84
+ [midnight + @type.time + offset_fix, tomorrow_midnight + @type.time].each do |t|
85
+ (@current_time = t; throw :done) if t >= @now
86
+ end
79
87
  end
80
- else
81
- [midnight + @type, yesterday_midnight + @type].each do |t|
82
- (@current_time = t; throw :done) if t < @now
88
+ else # pointer == :past
89
+ if @type.ambiguous?
90
+ [midnight + half_day + @type.time + offset_fix, midnight + @type.time + offset_fix, yesterday_midnight + @type.time + half_day].each do |t|
91
+ (@current_time = t; throw :done) if t <= @now
92
+ end
93
+ else
94
+ [midnight + @type.time + offset_fix, yesterday_midnight + @type.time].each do |t|
95
+ (@current_time = t; throw :done) if t <= @now
96
+ end
83
97
  end
84
98
  end
85
99
  end
100
+
101
+ @current_time || raise("Current time cannot be nil at this point")
86
102
  end
87
-
88
- @current_time || raise("Current time cannot be nil at this point")
103
+
104
+ unless first
105
+ increment = @type.ambiguous? ? half_day : full_day
106
+ @current_time += pointer == :future ? increment : -increment
107
+ end
108
+
109
+ Span.new(@current_time, @current_time + width)
89
110
  end
90
-
91
- unless first
92
- increment = @type.ambiguous? ? half_day : full_day
93
- @current_time += pointer == :future ? increment : -increment
111
+
112
+ def this(context = :future)
113
+ super
114
+
115
+ context = :future if context == :none
116
+
117
+ self.next(context)
118
+ end
119
+
120
+ def width
121
+ 1
122
+ end
123
+
124
+ def to_s
125
+ super << '-time-' << @type.to_s
94
126
  end
95
-
96
- Chronic::Span.new(@current_time, @current_time + width)
97
- end
98
-
99
- def this(context = :future)
100
- super
101
-
102
- context = :future if context == :none
103
-
104
- self.next(context)
105
- end
106
-
107
- def width
108
- 1
109
- end
110
-
111
- def to_s
112
- super << '-time-' << @type.to_s
113
127
  end
114
128
  end
@@ -1,68 +1,74 @@
1
- class Chronic::RepeaterWeek < Chronic::Repeater #:nodoc:
2
- WEEK_SECONDS = 604800 # (7 * 24 * 60 * 60)
3
-
4
- def next(pointer)
5
- super
6
-
7
- if !@current_week_start
1
+ module Chronic
2
+ class RepeaterWeek < Repeater #:nodoc:
3
+ WEEK_SECONDS = 604800 # (7 * 24 * 60 * 60)
4
+
5
+ def initialize(type)
6
+ super
7
+ end
8
+
9
+ def next(pointer)
10
+ super
11
+
12
+ if !@current_week_start
13
+ case pointer
14
+ when :future
15
+ sunday_repeater = RepeaterDayName.new(:sunday)
16
+ sunday_repeater.start = @now
17
+ next_sunday_span = sunday_repeater.next(:future)
18
+ @current_week_start = next_sunday_span.begin
19
+ when :past
20
+ sunday_repeater = RepeaterDayName.new(:sunday)
21
+ sunday_repeater.start = (@now + RepeaterDay::DAY_SECONDS)
22
+ sunday_repeater.next(:past)
23
+ last_sunday_span = sunday_repeater.next(:past)
24
+ @current_week_start = last_sunday_span.begin
25
+ end
26
+ else
27
+ direction = pointer == :future ? 1 : -1
28
+ @current_week_start += direction * WEEK_SECONDS
29
+ end
30
+
31
+ Span.new(@current_week_start, @current_week_start + WEEK_SECONDS)
32
+ end
33
+
34
+ def this(pointer = :future)
35
+ super
36
+
8
37
  case pointer
9
38
  when :future
10
- sunday_repeater = Chronic::RepeaterDayName.new(:sunday)
39
+ this_week_start = Chronic.time_class.local(@now.year, @now.month, @now.day, @now.hour) + RepeaterHour::HOUR_SECONDS
40
+ sunday_repeater = RepeaterDayName.new(:sunday)
11
41
  sunday_repeater.start = @now
12
- next_sunday_span = sunday_repeater.next(:future)
13
- @current_week_start = next_sunday_span.begin
42
+ this_sunday_span = sunday_repeater.this(:future)
43
+ this_week_end = this_sunday_span.begin
44
+ Span.new(this_week_start, this_week_end)
14
45
  when :past
15
- sunday_repeater = Chronic::RepeaterDayName.new(:sunday)
16
- sunday_repeater.start = (@now + Chronic::RepeaterDay::DAY_SECONDS)
17
- sunday_repeater.next(:past)
46
+ this_week_end = Chronic.time_class.local(@now.year, @now.month, @now.day, @now.hour)
47
+ sunday_repeater = RepeaterDayName.new(:sunday)
48
+ sunday_repeater.start = @now
49
+ last_sunday_span = sunday_repeater.next(:past)
50
+ this_week_start = last_sunday_span.begin
51
+ Span.new(this_week_start, this_week_end)
52
+ when :none
53
+ sunday_repeater = RepeaterDayName.new(:sunday)
54
+ sunday_repeater.start = @now
18
55
  last_sunday_span = sunday_repeater.next(:past)
19
- @current_week_start = last_sunday_span.begin
56
+ this_week_start = last_sunday_span.begin
57
+ Span.new(this_week_start, this_week_start + WEEK_SECONDS)
20
58
  end
21
- else
59
+ end
60
+
61
+ def offset(span, amount, pointer)
22
62
  direction = pointer == :future ? 1 : -1
23
- @current_week_start += direction * WEEK_SECONDS
63
+ span + direction * amount * WEEK_SECONDS
24
64
  end
25
-
26
- Chronic::Span.new(@current_week_start, @current_week_start + WEEK_SECONDS)
27
- end
28
-
29
- def this(pointer = :future)
30
- super
31
-
32
- case pointer
33
- when :future
34
- this_week_start = Time.local(@now.year, @now.month, @now.day, @now.hour) + Chronic::RepeaterHour::HOUR_SECONDS
35
- sunday_repeater = Chronic::RepeaterDayName.new(:sunday)
36
- sunday_repeater.start = @now
37
- this_sunday_span = sunday_repeater.this(:future)
38
- this_week_end = this_sunday_span.begin
39
- Chronic::Span.new(this_week_start, this_week_end)
40
- when :past
41
- this_week_end = Time.local(@now.year, @now.month, @now.day, @now.hour)
42
- sunday_repeater = Chronic::RepeaterDayName.new(:sunday)
43
- sunday_repeater.start = @now
44
- last_sunday_span = sunday_repeater.next(:past)
45
- this_week_start = last_sunday_span.begin
46
- Chronic::Span.new(this_week_start, this_week_end)
47
- when :none
48
- sunday_repeater = Chronic::RepeaterDayName.new(:sunday)
49
- sunday_repeater.start = @now
50
- last_sunday_span = sunday_repeater.next(:past)
51
- this_week_start = last_sunday_span.begin
52
- Chronic::Span.new(this_week_start, this_week_start + WEEK_SECONDS)
65
+
66
+ def width
67
+ WEEK_SECONDS
68
+ end
69
+
70
+ def to_s
71
+ super << '-week'
53
72
  end
54
- end
55
-
56
- def offset(span, amount, pointer)
57
- direction = pointer == :future ? 1 : -1
58
- span + direction * amount * WEEK_SECONDS
59
- end
60
-
61
- def width
62
- WEEK_SECONDS
63
- end
64
-
65
- def to_s
66
- super << '-week'
67
73
  end
68
74
  end
@@ -0,0 +1,85 @@
1
+ module Chronic
2
+ class RepeaterWeekday < Repeater #:nodoc:
3
+ DAY_SECONDS = 86400 # (24 * 60 * 60)
4
+ DAYS = {
5
+ :sunday => 0,
6
+ :monday => 1,
7
+ :tuesday => 2,
8
+ :wednesday => 3,
9
+ :thursday => 4,
10
+ :friday => 5,
11
+ :saturday => 6
12
+ }
13
+
14
+ def initialize(type)
15
+ super
16
+ end
17
+
18
+ def next(pointer)
19
+ super
20
+
21
+ direction = pointer == :future ? 1 : -1
22
+
23
+ if !@current_weekday_start
24
+ @current_weekday_start = Chronic.construct(@now.year, @now.month, @now.day)
25
+ @current_weekday_start += direction * DAY_SECONDS
26
+
27
+ until is_weekday?(@current_weekday_start.wday)
28
+ @current_weekday_start += direction * DAY_SECONDS
29
+ end
30
+ else
31
+ loop do
32
+ @current_weekday_start += direction * DAY_SECONDS
33
+ break if is_weekday?(@current_weekday_start.wday)
34
+ end
35
+ end
36
+
37
+ Span.new(@current_weekday_start, @current_weekday_start + DAY_SECONDS)
38
+ end
39
+
40
+ def this(pointer = :future)
41
+ super
42
+
43
+ case pointer
44
+ when :past
45
+ self.next(:past)
46
+ when :future, :none
47
+ self.next(:future)
48
+ end
49
+ end
50
+
51
+ def offset(span, amount, pointer)
52
+ direction = pointer == :future ? 1 : -1
53
+
54
+ num_weekdays_passed = 0; offset = 0
55
+ until num_weekdays_passed == amount
56
+ offset += direction * DAY_SECONDS
57
+ num_weekdays_passed += 1 if is_weekday?((span.begin+offset).wday)
58
+ end
59
+
60
+ span + offset
61
+ end
62
+
63
+ def width
64
+ DAY_SECONDS
65
+ end
66
+
67
+ def to_s
68
+ super << '-weekday'
69
+ end
70
+
71
+ private
72
+
73
+ def is_weekend?(day)
74
+ day == symbol_to_number(:saturday) || day == symbol_to_number(:sunday)
75
+ end
76
+
77
+ def is_weekday?(day)
78
+ !is_weekend?(day)
79
+ end
80
+
81
+ def symbol_to_number(sym)
82
+ DAYS[sym] || raise("Invalid symbol specified")
83
+ end
84
+ end
85
+ end
@@ -1,11 +1,66 @@
1
- class Chronic::RepeaterWeekend < Chronic::Repeater #:nodoc:
2
- WEEKEND_SECONDS = 172_800 # (2 * 24 * 60 * 60)
3
-
4
- def width
5
- WEEKEND_SECONDS
6
- end
7
-
8
- def to_s
9
- super << '-weekend'
1
+ module Chronic
2
+ class RepeaterWeekend < Repeater #:nodoc:
3
+ WEEKEND_SECONDS = 172_800 # (2 * 24 * 60 * 60)
4
+
5
+ def initialize(type)
6
+ super
7
+ end
8
+
9
+ def next(pointer)
10
+ super
11
+
12
+ if !@current_week_start
13
+ case pointer
14
+ when :future
15
+ saturday_repeater = RepeaterDayName.new(:saturday)
16
+ saturday_repeater.start = @now
17
+ next_saturday_span = saturday_repeater.next(:future)
18
+ @current_week_start = next_saturday_span.begin
19
+ when :past
20
+ saturday_repeater = RepeaterDayName.new(:saturday)
21
+ saturday_repeater.start = (@now + RepeaterDay::DAY_SECONDS)
22
+ last_saturday_span = saturday_repeater.next(:past)
23
+ @current_week_start = last_saturday_span.begin
24
+ end
25
+ else
26
+ direction = pointer == :future ? 1 : -1
27
+ @current_week_start += direction * RepeaterWeek::WEEK_SECONDS
28
+ end
29
+
30
+ Span.new(@current_week_start, @current_week_start + WEEKEND_SECONDS)
31
+ end
32
+
33
+ def this(pointer = :future)
34
+ super
35
+
36
+ case pointer
37
+ when :future, :none
38
+ saturday_repeater = RepeaterDayName.new(:saturday)
39
+ saturday_repeater.start = @now
40
+ this_saturday_span = saturday_repeater.this(:future)
41
+ Span.new(this_saturday_span.begin, this_saturday_span.begin + WEEKEND_SECONDS)
42
+ when :past
43
+ saturday_repeater = RepeaterDayName.new(:saturday)
44
+ saturday_repeater.start = @now
45
+ last_saturday_span = saturday_repeater.this(:past)
46
+ Span.new(last_saturday_span.begin, last_saturday_span.begin + WEEKEND_SECONDS)
47
+ end
48
+ end
49
+
50
+ def offset(span, amount, pointer)
51
+ direction = pointer == :future ? 1 : -1
52
+ weekend = RepeaterWeekend.new(:weekend)
53
+ weekend.start = span.begin
54
+ start = weekend.next(pointer).begin + (amount - 1) * direction * RepeaterWeek::WEEK_SECONDS
55
+ Span.new(start, start + (span.end - span.begin))
56
+ end
57
+
58
+ def width
59
+ WEEKEND_SECONDS
60
+ end
61
+
62
+ def to_s
63
+ super << '-weekend'
64
+ end
10
65
  end
11
66
  end
@@ -1,58 +1,77 @@
1
- class Chronic::RepeaterYear < Chronic::Repeater #:nodoc:
2
-
3
- def next(pointer)
4
- super
5
-
6
- if !@current_year_start
1
+ module Chronic
2
+ class RepeaterYear < Repeater #:nodoc:
3
+ YEAR_SECONDS = 31536000 # 365 * 24 * 60 * 60
4
+
5
+ def initialize(type)
6
+ super
7
+ end
8
+
9
+ def next(pointer)
10
+ super
11
+
12
+ if !@current_year_start
13
+ case pointer
14
+ when :future
15
+ @current_year_start = Chronic.construct(@now.year + 1)
16
+ when :past
17
+ @current_year_start = Chronic.construct(@now.year - 1)
18
+ end
19
+ else
20
+ diff = pointer == :future ? 1 : -1
21
+ @current_year_start = Chronic.construct(@current_year_start.year + diff)
22
+ end
23
+
24
+ Span.new(@current_year_start, Chronic.construct(@current_year_start.year + 1))
25
+ end
26
+
27
+ def this(pointer = :future)
28
+ super
29
+
7
30
  case pointer
8
31
  when :future
9
- @current_year_start = Time.local(@now.year + 1)
32
+ this_year_start = Chronic.construct(@now.year, @now.month, @now.day + 1)
33
+ this_year_end = Chronic.construct(@now.year + 1, 1, 1)
10
34
  when :past
11
- @current_year_start = Time.local(@now.year - 1)
35
+ this_year_start = Chronic.construct(@now.year, 1, 1)
36
+ this_year_end = Chronic.construct(@now.year, @now.month, @now.day)
37
+ when :none
38
+ this_year_start = Chronic.construct(@now.year, 1, 1)
39
+ this_year_end = Chronic.construct(@now.year + 1, 1, 1)
40
+ end
41
+
42
+ Span.new(this_year_start, this_year_end)
43
+ end
44
+
45
+ def offset(span, amount, pointer)
46
+ direction = pointer == :future ? 1 : -1
47
+ new_begin = build_offset_time(span.begin, amount, direction)
48
+ new_end = build_offset_time(span.end, amount, direction)
49
+ Span.new(new_begin, new_end)
50
+ end
51
+
52
+ def width
53
+ YEAR_SECONDS
54
+ end
55
+
56
+ def to_s
57
+ super << '-year'
58
+ end
59
+
60
+ private
61
+
62
+ def build_offset_time(time, amount, direction)
63
+ year = time.year + (amount * direction)
64
+ days = month_days(year, time.month)
65
+ day = time.day > days ? days : time.day
66
+ Chronic.construct(year, time.month, day, time.hour, time.min, time.sec)
67
+ end
68
+
69
+ def month_days(year, month)
70
+ if Date.leap?(year)
71
+ RepeaterMonth::MONTH_DAYS_LEAP[month - 1]
72
+ else
73
+ RepeaterMonth::MONTH_DAYS[month - 1]
12
74
  end
13
- else
14
- diff = pointer == :future ? 1 : -1
15
- @current_year_start = Time.local(@current_year_start.year + diff)
16
75
  end
17
-
18
- Chronic::Span.new(@current_year_start, Time.local(@current_year_start.year + 1))
19
- end
20
-
21
- def this(pointer = :future)
22
- super
23
-
24
- case pointer
25
- when :future
26
- this_year_start = Time.local(@now.year, @now.month, @now.day) + Chronic::RepeaterDay::DAY_SECONDS
27
- this_year_end = Time.local(@now.year + 1, 1, 1)
28
- when :past
29
- this_year_start = Time.local(@now.year, 1, 1)
30
- this_year_end = Time.local(@now.year, @now.month, @now.day)
31
- when :none
32
- this_year_start = Time.local(@now.year, 1, 1)
33
- this_year_end = Time.local(@now.year + 1, 1, 1)
34
- end
35
-
36
- Chronic::Span.new(this_year_start, this_year_end)
37
- end
38
-
39
- def offset(span, amount, pointer)
40
- direction = pointer == :future ? 1 : -1
41
-
42
- sb = span.begin
43
- new_begin = Time.local(sb.year + (amount * direction), sb.month, sb.day, sb.hour, sb.min, sb.sec)
44
-
45
- se = span.end
46
- new_end = Time.local(se.year + (amount * direction), se.month, se.day, se.hour, se.min, se.sec)
47
-
48
- Chronic::Span.new(new_begin, new_end)
49
- end
50
-
51
- def width
52
- (365 * 24 * 60 * 60)
53
- end
54
-
55
- def to_s
56
- super << '-year'
57
76
  end
58
77
  end