floraison / fugit

time tools (cron, parsing, durations, ...) for Ruby, rufus-scheduler, and flor
MIT License
384 stars 34 forks source link

Incorrect next_time for cron that is supposed to run every 3 hours for America/New_York #89

Closed shayonj closed 1 year ago

shayonj commented 1 year ago

Issue description

next_time in correct for cron that is suppose to run every 3 hours.

How to reproduce

The simplest piece of code that reproduces the issue, for example:

Time.now.utc
=> 2023-10-03 18:17:37.566578 UTC

Fugit::Cron.parse("0 */1 * * * America/New_York").next_time.to_utc_time
=> 2023-10-03 19:00:00 UTC

pry(main)> Fugit::Cron.parse("0 */2 * * * America/New_York").next_time.to_utc_time
=> 2023-10-03 20:00:00 UTC

pry(main)> Fugit::Cron.parse("0 */3 * * * America/New_York").next_time.to_utc_time
=> 2023-10-03 19:00:00 UTC

Error and error backtrace (if any)

None

Additional context

I would have expected it to be the same as without the time zone

Fugit::Cron.parse("0 */1 * * *").next_time.to_utc_time
=> 2023-10-03 19:00:00 UTC

 pry(main)> Fugit::Cron.parse("0 */2 * * *").next_time.to_utc_time
=> 2023-10-03 20:00:00 UTC

pry(main)> Fugit::Cron.parse("0 */3 * * *").next_time.to_utc_time
=> 2023-10-03 21:00:00 UTC

Add any other context about the problem here.

jmettraux commented 1 year ago

Hello,

I guess your machine TZ is set to "UTC".

require 'fugit'

#ENV['TZ'] = 'America/New_York'
ENV['TZ'] = 'UTC'

#Time.now.utc
#=> 2023-10-03 18:17:37.566578 UTC
  #
t = Fugit.parse('2023-10-03 18:17:37 UTC').to_local_time
#t = Time.now

p t.to_s

puts "---"

[ 1, 2, 3 ].each do |n|
  s = "0 */#{n} * * *"
  t1 = Fugit::Cron.parse(s).next_time(t)
  t1t = t1.translate(ENV['TZ']).to_s
  t1u = t1.to_utc_time
  p [ s, t1.to_s, '>>>', t1t, t1u ]
end

puts "---"

[ 1, 2, 3 ].each do |n|
  s = "0 */#{n} * * * America/New_York"
  t1 = Fugit::Cron.parse(s).next_time(t)
  t1t = t1.translate('America/New_York').to_s
  t1u = t1.to_utc_time
  p [ s, t1.to_s, '>>>', t1t, t1u ]
end

Gives on my machine:

"2023-10-04 03:17:37 +0900"
---
"2023-10-03 18:17:37 +0000"
---
["0 */1 * * *", "2023-10-03 19:00:00 Z", ">>>", "2023-10-03 19:00:00 Z", 2023-10-03 19:00:00 UTC]
["0 */2 * * *", "2023-10-03 20:00:00 Z", ">>>", "2023-10-03 20:00:00 Z", 2023-10-03 20:00:00 UTC]
["0 */3 * * *", "2023-10-03 21:00:00 Z", ">>>", "2023-10-03 21:00:00 Z", 2023-10-03 21:00:00 UTC]
---
["0 */1 * * * America/New_York", "2023-10-03 19:00:00 Z", ">>>", "2023-10-03 15:00:00 -0400", 2023-10-03 19:00:00 UTC]
["0 */2 * * * America/New_York", "2023-10-03 20:00:00 Z", ">>>", "2023-10-03 16:00:00 -0400", 2023-10-03 20:00:00 UTC]
["0 */3 * * * America/New_York", "2023-10-03 19:00:00 Z", ">>>", "2023-10-03 15:00:00 -0400", 2023-10-03 19:00:00 UTC]

The time that matters is the one following ">>>". 19 is a multiple of 1, 20 is a multiple of 2, 21 is a multiple of 3. The America/New_York sees 15 as a multiple of 1, 16 as a multiple of 2, and 15 as a multiple of 3, then you translate to UTC.

When you give a time zone to fugit, it computes in the time zone you give, not in the default timezone.

Best regards.

shayonj commented 12 months ago

ah! thank you for clarifying. I have ENV["TZ"] to nil, but I guess the usage of timezone wasn't correct here. I can confirm the right results now. Thanks

Fugit::Cron.parse("0 */3 * * *").next_time(t).translate('America/New_York').to_utc_time
=> 2023-10-03 21:00:00 UTC
jmettraux commented 12 months ago

You're welcome!