Skip to content

Commit e45775c

Browse files
committed
Support Time.now with :in keyword argument
1 parent 69ec93e commit e45775c

File tree

7 files changed

+42
-18
lines changed

7 files changed

+42
-18
lines changed

spec/ruby/core/time/now_spec.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@
3030
time.zone.should == nil
3131
end
3232

33+
it "returns a Time with UTC offset specified as a single letter military timezone" do
34+
Time.now(in: "W").utc_offset.should == 3600 * -10
35+
end
36+
3337
it "could be a timezone object" do
3438
zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo")
3539
time = Time.now(in: zone)

spec/ruby/core/time/utc_spec.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,22 @@
2121
Time.new(2022, 1, 1, 0, 0, 0, "UTC").utc?.should == true
2222
Time.now.localtime("UTC").utc?.should == true
2323
Time.at(Time.now, in: 'UTC').utc?.should == true
24+
25+
ruby_version_is "3.1" do
26+
Time.new(2022, 1, 1, 0, 0, 0, in: "UTC").utc?.should == true
27+
Time.now(in: "UTC").utc?.should == true
28+
end
2429
end
2530

2631
it "does treat time with Z offset as UTC" do
2732
Time.new(2022, 1, 1, 0, 0, 0, "Z").utc?.should == true
2833
Time.now.localtime("Z").utc?.should == true
2934
Time.at(Time.now, in: 'Z').utc?.should == true
35+
36+
ruby_version_is "3.1" do
37+
Time.new(2022, 1, 1, 0, 0, 0, in: "Z").utc?.should == true
38+
Time.now(in: "Z").utc?.should == true
39+
end
3040
end
3141

3242
ruby_version_is "3.1" do

spec/ruby/core/time/zone_spec.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,17 @@
7474
Time.now.localtime("-00:00").zone.should == "UTC"
7575
Time.at(Time.now, in: '-00:00').zone.should == "UTC"
7676
end
77+
78+
ruby_version_is "3.1" do
79+
Time.new(2022, 1, 1, 0, 0, 0, in: "UTC").zone.should == "UTC"
80+
Time.new(2022, 1, 1, 0, 0, 0, in: "Z").zone.should == "UTC"
81+
82+
Time.now(in: 'UTC').zone.should == "UTC"
83+
Time.now(in: 'Z').zone.should == "UTC"
84+
85+
Time.at(Time.now, in: 'UTC').zone.should == "UTC"
86+
Time.at(Time.now, in: 'Z').zone.should == "UTC"
87+
end
7788
end
7889

7990
platform_is_not :aix, :windows do

spec/tags/core/time/now_tags.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
1-
fails:Time.now :in keyword argument could be UTC offset as a String in '+HH:MM or '-HH:MM' format
2-
fails:Time.now :in keyword argument could be UTC offset as a number of seconds
31
fails:Time.now :in keyword argument could be a timezone object

src/main/java/org/truffleruby/core/time/TimeNodes.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,8 @@ private ZonedDateTime inUTC(ZonedDateTime dateTime) {
197197

198198
}
199199

200-
@CoreMethod(names = "now", constructor = true)
201-
public abstract static class TimeNowNode extends CoreMethodArrayArgumentsNode {
200+
@Primitive(name = "time_now")
201+
public abstract static class TimeNowNode extends PrimitiveArrayArgumentsNode {
202202

203203
@Child private GetTimeZoneNode getTimeZoneNode = GetTimeZoneNodeGen.create();
204204
@Child private TruffleString.FromJavaStringNode fromJavaStringNode = TruffleString.FromJavaStringNode.create();

src/main/ruby/truffleruby/core/time.rb

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -475,10 +475,6 @@ def new(year=undefined, month=nil, day=nil, hour=nil, minute=nil, second=nil, ut
475475
utc_offset ? self.now.getlocal(utc_offset) : self.now
476476
elsif Primitive.nil? utc_offset
477477
compose(:local, year, month, day, hour, minute, second)
478-
elsif utc_offset.instance_of?(String) && !utc_offset.encoding.ascii_compatible?
479-
raise ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: ' + utc_offset.inspect
480-
elsif utc_offset.instance_of?(String) && !valid_utc_offset_string?(utc_offset)
481-
raise ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: ' + utc_offset
482478
elsif utc_offset == :std
483479
compose(:local, second, minute, hour, day, month, year, nil, nil, false, nil)
484480
elsif utc_offset == :dst
@@ -493,19 +489,24 @@ def new(year=undefined, month=nil, day=nil, hour=nil, minute=nil, second=nil, ut
493489
end
494490
end
495491

496-
def valid_utc_offset_string?(utc_offset)
497-
utc_offset == 'UTC' \
498-
|| (utc_offset.size == 1 && ('A'..'Z') === utc_offset && utc_offset != 'J') \
499-
|| (utc_offset =~ /\A[+-](\d{2})(?::(\d{2})(?::(\d{2}))?)?\z/ && $1.to_i < 24 && $2.to_i < 60 && $3.to_i < 60) \
500-
|| (utc_offset =~ /\A[+-](\d{2})(?:(\d{2})(?:(\d{2}))?)?\z/ && $1.to_i < 24 && $2.to_i < 60 && $3.to_i < 60) # without ":" separators
501-
end
502-
private :valid_utc_offset_string?
503-
504492
def utc_offset_in_utc?(utc_offset)
505493
utc_offset == 'UTC' || utc_offset == 'Z' || utc_offset == '-00:00'
506494
end
507495
private :utc_offset_in_utc?
508496

497+
def now(**options)
498+
time_now = Primitive.time_now(self)
499+
in_timezone = options[:in]
500+
501+
if in_timezone
502+
utc_offset = Truffle::Type.coerce_to_utc_offset(in_timezone)
503+
is_utc = utc_offset_in_utc?(in_timezone)
504+
is_utc ? Primitive.time_utctime(time_now) : Primitive.time_localtime(time_now, utc_offset)
505+
else
506+
time_now
507+
end
508+
end
509+
509510
def local(*args)
510511
compose(:local, *args)
511512
end

src/main/ruby/truffleruby/core/type.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -495,10 +495,10 @@ def self.coerce_string_to_utc_offset(offset)
495495
else
496496
offset = (offset.ord - 'N'.ord + 1) * -3600 # ("N"..Y) => -1, -2, ...
497497
end
498-
elsif offset.match(/\A(\+|-)(\d\d)(?::(\d\d)(?::(\d\d))?)?\z/) # with ":" separators
498+
elsif offset.match(/\A(\+|-)(\d\d)(?::(\d\d)(?::(\d\d))?)?\z/) && $1.to_i < 24 && $2.to_i < 60 && $3.to_i < 60 # with ":" separators
499499
offset = $2.to_i*60*60 + $3.to_i*60 + $4.to_i
500500
offset = -offset if $1.ord == 45
501-
elsif offset.match(/\A(\+|-)(\d\d)(?:(\d\d)(?:(\d\d))?)?\z/) # without ":" separators
501+
elsif offset.match(/\A(\+|-)(\d\d)(?:(\d\d)(?:(\d\d))?)?\z/) && $1.to_i < 24 && $2.to_i < 60 && $3.to_i < 60 # without ":" separators
502502
offset = $2.to_i*60*60 + $3.to_i*60 + $4.to_i
503503
offset = -offset if $1.ord == 45
504504
else

0 commit comments

Comments
 (0)