Project

General

Profile

Actions

Bug #21301

open

Invalid Dates Accepted When Using "UTC" in Time.new

Added by mame (Yusuke Endoh) 4 days ago. Updated 2 days ago.

Status:
Open
Assignee:
-
Target version:
-
[ruby-core:121801]

Description

2025-04-31 does not exist, but, when creating a time object with the "UTC" zone, the value is accepted without error:

Time.new(2025, 4, 31, 0, 0, 0, "UTC") #=> expected: 2025-05-01 00:00:00 UTC
                                      #=> actual:   2025-04-31 00:00:00 UTC

In contrast, using the "+00:00" time zone works as expected and rolls the date over to 2025-05-01:

Time.new(2025, 4, 31, 0, 0, 0, "+00:00") # => 2025-05-01 00:00:00 +0000

Note that 2025-04-30T24:00:00Z is correctly rolled over to 2025-05-01T00:00:00Z.
And 2025-04-31T24:00:00Z is rolled over to 2025-04-01!

Time.new(2025, 4, 30, 24, 0, 0, "UTC") #=> 2025-05-01 00:00:00 UTC # OK
Time.new(2025, 4, 31, 24, 0, 0, "UTC") #=> 2025-04-01 00:00:00 UTC # What?

Updated by mame (Yusuke Endoh) 3 days ago

Thanks. Actually, the same issue also occurs with a value of 60 for seconds:

Time.new(2025, 1, 1, 0, 0, 60, "UTC")    #=> 2025-01-01 00:00:60 UTC   # invalid
Time.new(2025, 1, 1, 0, 0, 60, "+00:00") #=> 2025-01-01 00:01:00 +0000

Note that 60 seconds can be valid in the case of a leap second.

Time.new(2016, 12, 31, 23, 59, 60, "UTC")    #=> 2016-12-31 23:59:60 UTC   # can be valid
Time.new(2016, 12, 31, 23, 59, 60, "+00:00") #=> 2016-12-31 23:59:60 +0000

2016-12-31 23:59:60 UTC is valid if the system has leap second data.

Updated by dodecadaniel (Daniel Colson) 2 days ago ยท Edited

Ah yeah, rolling over seconds seems trickier. I think the time with the offset doesn't have to deal with all that because it doesn't set the vtm struct right away. Instead, it only sets the timew (a kind of timestamp) and then calculates the vtm later as needed based on the timew. The vtm -> timew -> vtm round trip is enough to normalize everything (that uses timegmw and gmtimew, which are leap-second aware, etc.).

The UTC time tries to put together and set the vtm struct directly upfront and then sets tobj->vtm.tm_got = 1. Changing tm_got from 1 to 0 is enough to get the UTC code behaving like the offset code, but I assume there's some cost to that. Possibly worth it for better accuracy though? I can explore that more if it seems worthwhile. It'd save us from needing to do vtm_day_wraparound too.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0