Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hour 24 to_s issue #142

Closed
glindstr opened this issue Nov 4, 2022 · 2 comments
Closed

Hour 24 to_s issue #142

glindstr opened this issue Nov 4, 2022 · 2 comments

Comments

@glindstr
Copy link

glindstr commented Nov 4, 2022

Not sure which module is responsible but there appears to be a bug when using Time with tzinfo and setting hour to 24.

# Time without tzinfo

puts Time.new(2022, 11, 6, 24, 0, 0)
# => 2022-11-07 00:00:00 -0600
puts Time.new(2022, 11, 6, 24, 0, 0).strftime("%Y-%m-%d %H:%M:%S %z")
# => 2022-11-07 00:00:00 -0600

# Time with tzinfo
tz = TZInfo::Timezone.get("America/Chicago")

puts Time.new(2022, 11, 6, 24, 0, 0, tzinfo=tz)
# => 2022-11-06 23:00:00 -0600      <== bug, off by one hour

puts Time.new(2022, 11, 6, 24, 0, 0, tzinfo=tz).strftime("%Y-%m-%d %H:%M:%S %z")
# => 2022-11-07 00:00:00 -0600

All the string outputs above should match (first two depends on your system timezone). The inconsistent issue appears to happen when using Time with hour = 24 and with tzinfo set.

ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x64-mingw-ucrt]
tzinfo (2.0.5, 2.0.4)
tzinfo-data (1.2022.1)

@philr
Copy link
Member

philr commented Nov 5, 2022

I think the issue lies with Ruby's Time class.

Time.new(2022, 11, 6, 24, 0, 0, tzinfo=tz) calls tz.local_to_utc(t), where t is a Time-like instance representing 2022-11-07 00:00:00 UTC (UTC is expected - the offset of this instance is ignored by TZInfo). For America/Chicago, local_to_utc returns a Time instance representing 2022-11-07 06:00:00 UTC. That's the correct result (Chicago is 6 hours behind UTC at that time).

I'm not too familiar with the internals of the Time class. Perhaps significantly, Time#to_s produces a result without any further calls to tz. Time#strftime calls tz.utc_to_local(t) where t is a Time-like instance representing 2022-11-07 06:00:00 UTC. For America/Chicago, utc_to_local returns a TZInfo::TimeWithOffset (a subclass of Time) instance representing 2022-11-07 00:00:00 -0600.

I've noticed that there's also a difference in whether Time.new increments the day and resets the hour:

t1 = Time.new(2022, 11, 6, 24, 0, 0)
[t1.year, t1.month, t1.day, t1.hour]
# => [2022, 11, 7, 0]  <== converted to hour 0 on the next day

tz = TZInfo::Timezone.get("America/Chicago")
t2 = Time.new(2022, 11, 6, 24, 0, 0, tzinfo=tz)
[t2.year, t2.month, t2.day, t2.hour]
# => [2022, 11, 6, 24]  <== values left as supplied

It's probably best to raise this on the Ruby Issue Tracking System.

@glindstr
Copy link
Author

glindstr commented Nov 5, 2022

Thank you for looking into this. I've added an issue #19106 to the ruby issue tracking system. I'll ask to reopen should it get kicked back this way.

@glindstr glindstr closed this as completed Nov 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants