File: time_extensions.rb

package info (click to toggle)
ruby-timecop 0.9.10-1.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 280 kB
  • sloc: ruby: 1,950; makefile: 17
file content (225 lines) | stat: -rw-r--r-- 6,927 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
require 'time'
require 'date'

class Time #:nodoc:
  class << self
    def mock_time
      mocked_time_stack_item = Timecop.top_stack_item
      mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.time(self)
    end

    alias_method :now_without_mock_time, :now

    def now_with_mock_time
      mock_time || now_without_mock_time
    end

    alias_method :now, :now_with_mock_time

    alias_method :new_without_mock_time, :new

    def new_with_mock_time(*args)
      args.size <= 0 ? now : new_without_mock_time(*args)
    end

    ruby2_keywords :new_with_mock_time if Module.private_method_defined?(:ruby2_keywords)

    alias_method :new, :new_with_mock_time
  end
end

class Date #:nodoc:
  class << self
    def mock_date
      mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.date(self)
    end

    alias_method :today_without_mock_date, :today

    def today_with_mock_date
      mock_date || today_without_mock_date
    end

    alias_method :today, :today_with_mock_date

    alias_method :strptime_without_mock_date, :strptime

    def strptime_with_mock_date(str = '-4712-01-01', fmt = '%F', start = Date::ITALY)
      #If date is not valid the following line raises
      Date.strptime_without_mock_date(str, fmt, start)

      d = Date._strptime(str, fmt)
      now = Time.now.to_date
      year = d[:year] || d[:cwyear] || now.year
      mon = d[:mon] || now.mon
      if d.keys == [:year]
        Date.new(year, 1, 1, start)
      elsif d[:mday]
        Date.new(year, mon, d[:mday], start)
      elsif d[:yday]
        Date.new(year, 1, 1, start).next_day(d[:yday] - 1)
      elsif d[:cwyear] || d[:cweek] || d[:wnum0] || d[:wnum1] || d[:wday] || d[:cwday]
        week = d[:cweek] || d[:wnum1] || d[:wnum0] || now.strftime('%W').to_i
        if d[:wnum0] #Week of year where week starts on sunday
          if d[:cwday] #monday based day of week
            Date.strptime_without_mock_date("#{year} #{week} #{d[:cwday]}", '%Y %U %u', start)
          else
            Date.strptime_without_mock_date("#{year} #{week} #{d[:wday] || 0}", '%Y %U %w', start)
          end
        else #Week of year where week starts on monday
          if d[:wday] #sunday based day of week
            Date.strptime_without_mock_date("#{year} #{week} #{d[:wday]}", '%Y %W %w', start)
          else
            Date.strptime_without_mock_date("#{year} #{week} #{d[:cwday] || 1}", '%Y %W %u', start)
          end
        end
      elsif d[:seconds]
        Time.at(d[:seconds]).to_date
      else
        Date.new(year, mon, 1, start)
      end
    end

    alias_method :strptime, :strptime_with_mock_date

    def parse_with_mock_date(*args)
      parsed_date = parse_without_mock_date(*args)
      return parsed_date unless mocked_time_stack_item
      date_hash = Date._parse(*args)

      case
      when date_hash[:year] && date_hash[:mon]
        parsed_date
      when date_hash[:mon] && date_hash[:mday]
        Date.new(mocked_time_stack_item.year, date_hash[:mon], date_hash[:mday])
      when date_hash[:mday]
        Date.new(mocked_time_stack_item.year, mocked_time_stack_item.month, date_hash[:mday])
      when date_hash[:wday]
        closest_wday(date_hash[:wday])
      else
        parsed_date + mocked_time_stack_item.travel_offset_days
      end
    end

    alias_method :parse_without_mock_date, :parse
    alias_method :parse, :parse_with_mock_date

    def mocked_time_stack_item
      Timecop.top_stack_item
    end

    def closest_wday(wday)
      today = Date.today
      result = today - today.wday
      result += 1 until wday == result.wday
      result
    end
  end
end

class DateTime #:nodoc:
  class << self
    def mock_time
      mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.datetime(self)
    end

    def now_with_mock_time
      mock_time || now_without_mock_time
    end

    alias_method :now_without_mock_time, :now

    alias_method :now, :now_with_mock_time

    def parse_with_mock_date(*args)
      parsed_date = parse_without_mock_date(*args)
      return parsed_date unless mocked_time_stack_item
      date_hash = DateTime._parse(*args)

      case
      when date_hash[:year] && date_hash[:mon]
        parsed_date
      when date_hash[:mon] && date_hash[:mday]
        DateTime.new(mocked_time_stack_item.year, date_hash[:mon], date_hash[:mday])
      when date_hash[:mday]
        DateTime.new(mocked_time_stack_item.year, mocked_time_stack_item.month, date_hash[:mday])
      when date_hash[:wday] && date_hash[:hour] && date_hash[:min]
        closest_date = Date.closest_wday(date_hash[:wday]).to_datetime

        DateTime.new(
          closest_date.year, closest_date.month, closest_date.day,
          date_hash[:hour], date_hash[:min]
        )
      when date_hash[:wday]
        Date.closest_wday(date_hash[:wday]).to_datetime
      when date_hash[:hour] && date_hash[:min] && date_hash[:sec]
        DateTime.new(mocked_time_stack_item.year, mocked_time_stack_item.month, mocked_time_stack_item.day, date_hash[:hour], date_hash[:min], date_hash[:sec])
      else
        parsed_date + mocked_time_stack_item.travel_offset_days
      end
    end

    alias_method :parse_without_mock_date, :parse
    alias_method :parse, :parse_with_mock_date

    def mocked_time_stack_item
      Timecop.top_stack_item
    end
  end
end

if RUBY_VERSION >= '2.1.0'
  module Process #:nodoc:
    class << self
      alias_method :clock_gettime_without_mock, :clock_gettime

      def clock_gettime_mock_time(clock_id, unit = :float_second)
        mock_time = case clock_id
                    when Process::CLOCK_MONOTONIC
                      mock_time_monotonic
                    when Process::CLOCK_REALTIME
                      mock_time_realtime
                    end

        return clock_gettime_without_mock(clock_id, unit) unless Timecop.mock_process_clock? && mock_time

        divisor = case unit
                  when :float_second
                    1_000_000_000.0
                  when :second
                    1_000_000_000
                  when :float_millisecond
                    1_000_000.0
                  when :millisecond
                    1_000_000
                  when :float_microsecond
                    1000.0
                  when :microsecond
                    1000
                  when :nanosecond
                    1
                  end

        (mock_time / divisor)
      end

      alias_method :clock_gettime, :clock_gettime_mock_time

      private

      def mock_time_monotonic
        mocked_time_stack_item = Timecop.top_stack_item
        mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.monotonic
      end

      def mock_time_realtime
        mocked_time_stack_item = Timecop.top_stack_item

        return nil if mocked_time_stack_item.nil?

        t = mocked_time_stack_item.time
        t.to_i * 1_000_000_000 + t.nsec
      end
    end
  end
end