Bug #19293
openThe new Time.new(String) API is nice... but we still need a stricter version of this
Description
The Ruby 3.2 style Time.new(String)
API works very well so far, but since the original Time.new(Integer, Integer, Integer...)
API actually accepts String objects as its arguments, there's one ambiguous case as follows:
Time.new('20230123') #=> 20230123-01-01 00:00:00 +0900
Then the problem that I'm facing is that we cannot tell if Time.new
would parse the given String as ISO8601-ish or just a year, and in order to avoid this ambiguity, we still need to somehow parse the String beforehand in our application side (like we're doing this way in Ruby on Rails https://github.com/rails/rails/blob/c49b8270/activemodel/lib/active_model/type/helpers/time_value.rb#L64-L70), then dispatch to the new Time.new
only when the String is validated to be conforming the ISO format. Otherwise, if we just optimistically pass in given Strings to Time.new
, we'll occasionally get a Time object with an unintended buggy value.
Therefore, it unfortunately seems that my feature request on #16005 still continues... I have to keep proposing that we need either of the following:
-
A trustworthy version of ISO8601 parser method perhaps with another name than
.new
that accepts strict ISO8601-ish String only (but with the T delimiter, I still don't know what the proper name of this format is). -
Change
Time.new(Integer-ish, Integer-ish, Integer-ish...)
not to accept Integer-ish Strings but to accept only Integers. But I can imagine that this direction is very unlikely acceptable, due to the incompatibility.
Files
Updated by nobu (Nobuyoshi Nakada) 5 months ago
- File time_benchmark.rb time_benchmark.rb added
Kernel#Integer
may be easier (and probably faster) than the Regexp.
Time.new(string) unless Integer(string, exception: false)
Benchmark.
$ ruby time_benchmark.rb
Warming up --------------------------------------
active_model 33.895k i/100ms
time 78.272k i/100ms
Calculating -------------------------------------
active_model 365.327k (± 0.9%) i/s - 1.830M in 5.010500s
time 943.682k (± 1.0%) i/s - 4.775M in 5.060040s
BTW, fast_string_to_time
seems having a bug on the negative offset calculation.
Updated by byroot (Jean Boussier) 5 months ago
A trustworthy version of ISO8601 parser method perhaps with another name than .new that accepts strict ISO8601-ish String only
Can we improve Time.iso8601
?
Alternatively we could introduce a method based on https://www.rfc-editor.org/rfc/rfc3339. RFC 3339 is pretty much the date and time part of ISO8601 but publicly documented.
Updated by Eregon (Benoit Daloze) 5 months ago
I think a new method is cleaner. Or maybe reusing Time.iso8601
.
It feels a hack for Time.new two wildly different things based on the number of arguments and as shown here it's ambiguous.
I had the same concerns when Time.new started supporting this, so "told you so" feeling here.
Updated by mame (Yusuke Endoh) 5 months ago
Discussed at the dev meeting. @naruse (Yui NARUSE) said "Time.new("2023")
is 1.9.2 feature. We can’t deprecate on 3.2.1. Need to continue the discussion for Ruby 3.3."
BTW Ruby 3.2.0 accidentally allows Time.new("2023-01")
, Time.new("2023-01-01")
, and Time.new(" \n\n 2023-01-01 00:00:00 \n\n ")
. All of these are considered a bug, so will be prohibited (fixed) in Ruby 3.2.1.