Skip to content

Commit 6b6255c

Browse files
committed
makes high precision datetime casting functionality from v4.1.1 opt-in, and restores the previous default
1 parent b18f5b7 commit 6b6255c

File tree

3 files changed

+141
-10
lines changed

3 files changed

+141
-10
lines changed

lib/subroutine/type_caster.rb

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44
require 'time'
55
require 'bigdecimal'
66
require 'securerandom'
7+
require 'active_support/core_ext/date_time/acts_like'
8+
require 'active_support/core_ext/date_time/calculations'
79
require 'active_support/core_ext/object/acts_like'
810
require 'active_support/core_ext/object/blank'
911
require 'active_support/core_ext/object/try'
1012
require 'active_support/core_ext/array/wrap'
1113
require 'active_support/core_ext/time/acts_like'
14+
require 'active_support/core_ext/time/calculations'
1215

1316
module Subroutine
1417
module TypeCaster
@@ -117,13 +120,23 @@ def self.cast(value, options = {})
117120
::Date.parse(String(value))
118121
end
119122

120-
::Subroutine::TypeCaster.register :time, :timestamp, :datetime do |value, _options = {}|
123+
::Subroutine::TypeCaster.register :time, :timestamp, :datetime do |value, options = {}|
121124
next nil unless value.present?
122125

123-
if value.try(:acts_like?, :time)
124-
value
125-
else
126-
::Time.parse(String(value))
126+
if options[:precision] == :high
127+
if value.try(:acts_like?, :time)
128+
value.to_time
129+
else
130+
::Time.parse(String(value))
131+
end
132+
else # precision == :seconds
133+
time = if value.try(:acts_like?, :time)
134+
value.to_time
135+
else
136+
::Time.parse(String(value))
137+
end
138+
139+
time.change(usec: 0)
127140
end
128141
end
129142

test/subroutine/type_caster_test.rb

Lines changed: 122 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ def test_date_inputs
241241
assert_nil op.date_input
242242
end
243243

244-
def test_time_inputs
244+
def test_time_inputs__with_seconds_precision
245245
op.time_input = nil
246246
assert_nil op.time_input
247247

@@ -256,22 +256,139 @@ def test_time_inputs
256256
assert_equal 0, op.time_input.min
257257
assert_equal 0, op.time_input.sec
258258

259+
op.time_input = ::DateTime.new(2022, 12, 22)
260+
assert_equal ::Time, op.time_input.class
261+
refute_equal ::DateTime, op.time_input.class
262+
263+
assert_equal 0, op.time_input.utc_offset
264+
assert_equal 2022, op.time_input.year
265+
assert_equal 12, op.time_input.month
266+
assert_equal 22, op.time_input.day
267+
assert_equal 0, op.time_input.hour
268+
assert_equal 0, op.time_input.min
269+
assert_equal 0, op.time_input.sec
270+
259271
op.time_input = '2023-05-05T10:00:30.123456Z'
260272
assert_equal ::Time, op.time_input.class
261273
refute_equal ::DateTime, op.time_input.class
262274

275+
assert_equal 0, op.time_input.utc_offset
276+
assert_equal 2023, op.time_input.year
277+
assert_equal 5, op.time_input.month
278+
assert_equal 5, op.time_input.day
279+
assert_equal 10, op.time_input.hour
280+
assert_equal 0, op.time_input.min
281+
assert_equal 30, op.time_input.sec
282+
assert_equal 0, op.time_input.usec
283+
284+
op.time_input = '2023-05-05T10:00:30Z'
285+
assert_equal ::Time, op.time_input.class
286+
assert_equal 0, op.time_input.utc_offset
263287
assert_equal 2023, op.time_input.year
264288
assert_equal 5, op.time_input.month
265289
assert_equal 5, op.time_input.day
266290
assert_equal 10, op.time_input.hour
267291
assert_equal 0, op.time_input.min
268292
assert_equal 30, op.time_input.sec
269-
assert_equal 123456, op.time_input.usec
293+
assert_equal 0, op.time_input.usec
270294

271-
time = Time.at(1678741605.123456)
295+
op.time_input = '2024-11-11T16:42:23.246+0100'
296+
assert_equal ::Time, op.time_input.class
297+
assert_equal 3600, op.time_input.utc_offset
298+
assert_equal 2024, op.time_input.year
299+
assert_equal 11, op.time_input.month
300+
assert_equal 11, op.time_input.day
301+
assert_equal 16, op.time_input.hour
302+
assert_equal 42, op.time_input.min
303+
assert_equal 23, op.time_input.sec
304+
assert_equal 0, op.time_input.usec
305+
306+
time = Time.at(1678741605.123456).utc
272307
op.time_input = time
273-
assert_equal time, op.time_input
274-
assert_equal time.object_id, op.time_input.object_id
308+
refute_equal time, op.time_input
309+
refute_equal time.object_id, op.time_input.object_id
310+
assert_equal 2023, op.time_input.year
311+
assert_equal 3, op.time_input.month
312+
assert_equal 13, op.time_input.day
313+
assert_equal 21, op.time_input.hour
314+
assert_equal 6, op.time_input.min
315+
assert_equal 45, op.time_input.sec
316+
assert_equal 0, op.time_input.usec
317+
end
318+
319+
def test_time_inputs__with_high_precision
320+
op.precise_time_input = nil
321+
assert_nil op.precise_time_input
322+
323+
op.precise_time_input = '2022-12-22'
324+
assert_equal ::Time, op.precise_time_input.class
325+
refute_equal ::DateTime, op.precise_time_input.class
326+
327+
assert_equal 2022, op.precise_time_input.year
328+
assert_equal 12, op.precise_time_input.month
329+
assert_equal 22, op.precise_time_input.day
330+
assert_equal 0, op.precise_time_input.hour
331+
assert_equal 0, op.precise_time_input.min
332+
assert_equal 0, op.precise_time_input.sec
333+
334+
op.precise_time_input = ::DateTime.new(2022, 12, 22)
335+
assert_equal ::Time, op.precise_time_input.class
336+
refute_equal ::DateTime, op.precise_time_input.class
337+
338+
assert_equal 0, op.precise_time_input.utc_offset
339+
assert_equal 2022, op.precise_time_input.year
340+
assert_equal 12, op.precise_time_input.month
341+
assert_equal 22, op.precise_time_input.day
342+
assert_equal 0, op.precise_time_input.hour
343+
assert_equal 0, op.precise_time_input.min
344+
assert_equal 0, op.precise_time_input.sec
345+
346+
op.precise_time_input = '2023-05-05T10:00:30.123456Z'
347+
assert_equal ::Time, op.precise_time_input.class
348+
refute_equal ::DateTime, op.precise_time_input.class
349+
350+
assert_equal 0, op.precise_time_input.utc_offset
351+
assert_equal 2023, op.precise_time_input.year
352+
assert_equal 5, op.precise_time_input.month
353+
assert_equal 5, op.precise_time_input.day
354+
assert_equal 10, op.precise_time_input.hour
355+
assert_equal 0, op.precise_time_input.min
356+
assert_equal 30, op.precise_time_input.sec
357+
assert_equal 123456, op.precise_time_input.usec
358+
359+
op.precise_time_input = '2023-05-05T10:00:30Z'
360+
assert_equal ::Time, op.precise_time_input.class
361+
assert_equal 0, op.precise_time_input.utc_offset
362+
assert_equal 2023, op.precise_time_input.year
363+
assert_equal 5, op.precise_time_input.month
364+
assert_equal 5, op.precise_time_input.day
365+
assert_equal 10, op.precise_time_input.hour
366+
assert_equal 0, op.precise_time_input.min
367+
assert_equal 30, op.precise_time_input.sec
368+
assert_equal 0, op.precise_time_input.usec
369+
370+
op.precise_time_input = '2024-11-11T16:42:23.246+0100'
371+
assert_equal ::Time, op.precise_time_input.class
372+
assert_equal 3600, op.precise_time_input.utc_offset
373+
assert_equal 2024, op.precise_time_input.year
374+
assert_equal 11, op.precise_time_input.month
375+
assert_equal 11, op.precise_time_input.day
376+
assert_equal 16, op.precise_time_input.hour
377+
assert_equal 42, op.precise_time_input.min
378+
assert_equal 23, op.precise_time_input.sec
379+
assert_equal 246000, op.precise_time_input.usec
380+
381+
time = Time.at(1678741605.123456).utc
382+
op.precise_time_input = time
383+
assert_equal time, op.precise_time_input
384+
assert_equal time.object_id, op.precise_time_input.object_id
385+
assert_equal 2023, op.precise_time_input.year
386+
assert_equal 3, op.precise_time_input.month
387+
assert_equal 13, op.precise_time_input.day
388+
assert_equal 21, op.precise_time_input.hour
389+
assert_equal 6, op.precise_time_input.min
390+
assert_equal 45, op.precise_time_input.sec
391+
assert_equal 123456, op.precise_time_input.usec
275392
end
276393

277394
def test_iso_date_inputs

test/support/ops.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ class TypeCastOp < ::Subroutine::Op
177177
boolean :boolean_input
178178
date :date_input
179179
time :time_input, default: -> { Time.now }
180+
time :precise_time_input, precision: :high
180181
iso_date :iso_date_input
181182
iso_time :iso_time_input
182183
object :object_input

0 commit comments

Comments
 (0)