floraison / fugit

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

Issue parsing 0/1 compared to * or */1 #79

Closed JosephHalter closed 1 year ago

JosephHalter commented 1 year ago

Issue description

These cron strings are supposed to be equivalent:

the human readable expression is At 30 minutes past the hour for each.

However when combined with a timezone, it seems like they aren't equivalent anymore, at least for Fugit:

# (current time is 2022-09-20 09:00:00 +0000)

> Fugit.do_parse("0 * * * * Asia/Tokyo").next_time.to_s
=> "2022-09-20 10:00:00 +0000"
> Fugit.do_parse("0 */1 * * * Asia/Tokyo").next_time.to_s
=> "2022-09-20 10:00:00 +0000"
> Fugit.do_parse("0 0/1 * * * Asia/Tokyo").next_time.to_s
=> "2022-09-20 15:00:00 +0000"

I'm not sure if this is this the expected behaviour, I expected the result of next_time to be the same.

jmettraux commented 1 year ago

Hello,

for comparison:

then in the UTC timezone:


require 'fugit'

ENV['TZ'] = 'UTC'

t0 = Time.parse('2022-09-20 09:00:00 +0000')

#> Fugit.do_parse("0 * * * * Asia/Tokyo").next_time.to_s
#=> "2022-09-20 10:00:00 +0000"

p Fugit.do_parse('0 * * * *').next_time(t0).to_s
p Fugit.do_parse('0 * * * *').next_time(t0).utc.to_s
  # ==> "2022-09-20 10:00:00 Z"
  # ==> "2022-09-20 10:00:00 UTC"
p Fugit.do_parse('0 * * * * Asia/Tokyo').next_time(t0).to_s
p Fugit.do_parse('0 * * * * Asia/Tokyo').next_time(t0).utc.to_s
  # ==> "2022-09-20 10:00:00 Z"
  # ==> "2022-09-20 10:00:00 UTC"

#> Fugit.do_parse("0 */1 * * * Asia/Tokyo").next_time.to_s
#=> "2022-09-20 10:00:00 +0000"

p Fugit.do_parse('0 */1 * * *').next_time(t0).to_s
p Fugit.do_parse('0 */1 * * *').next_time(t0).utc.to_s
  # ==> "2022-09-20 10:00:00 Z"
  # ==> "2022-09-20 10:00:00 UTC"
p Fugit.do_parse('0 */1 * * * Asia/Tokyo').next_time(t0).to_s
p Fugit.do_parse('0 */1 * * * Asia/Tokyo').next_time(t0).utc.to_s
  # ==> "2022-09-20 10:00:00 Z"
  # ==> "2022-09-20 10:00:00 UTC"

#> Fugit.do_parse("0 0/1 * * * Asia/Tokyo").next_time.to_s
#=> "2022-09-20 15:00:00 +0000"

p Fugit.do_parse('0 0/1 * * *').next_time(t0).to_s
p Fugit.do_parse('0 0/1 * * *').next_time(t0).utc.to_s
  # ==> "2022-09-21 00:00:00 Z"
  # ==> "2022-09-21 00:00:00 UTC"
p Fugit.do_parse('0 0/1 * * * Asia/Tokyo').next_time(t0).to_s
p Fugit.do_parse('0 0/1 * * * Asia/Tokyo').next_time(t0).utc.to_s
  # ==> "2022-09-20 15:00:00 Z"
  # ==> "2022-09-20 15:00:00 UTC"

and in the Tokyo timezone:


require 'fugit'

ENV['TZ'] = 'Asia/Tokyo'

t0 = Time.parse('2022-09-20 09:00:00 +0000')

#> Fugit.do_parse("0 * * * * Asia/Tokyo").next_time.to_s
#=> "2022-09-20 10:00:00 +0000"

p Fugit.do_parse('0 * * * *').next_time(t0).to_s
p Fugit.do_parse('0 * * * *').next_time(t0).utc.to_s
  # ==> "2022-09-20 19:00:00 +0900"
  # ==> "2022-09-20 10:00:00 UTC"
p Fugit.do_parse('0 * * * * Asia/Tokyo').next_time(t0).to_s
p Fugit.do_parse('0 * * * * Asia/Tokyo').next_time(t0).utc.to_s
  # ==> "2022-09-20 19:00:00 +0900"
  # ==> "2022-09-20 10:00:00 UTC"

#> Fugit.do_parse("0 */1 * * * Asia/Tokyo").next_time.to_s
#=> "2022-09-20 10:00:00 +0000"

p Fugit.do_parse('0 */1 * * *').next_time(t0).to_s
p Fugit.do_parse('0 */1 * * *').next_time(t0).utc.to_s
  # ==> "2022-09-20 19:00:00 +0900"
  # ==> "2022-09-20 10:00:00 UTC"
p Fugit.do_parse('0 */1 * * * Asia/Tokyo').next_time(t0).to_s
p Fugit.do_parse('0 */1 * * * Asia/Tokyo').next_time(t0).utc.to_s
  # ==> "2022-09-20 19:00:00 +0900"
  # ==> "2022-09-20 10:00:00 UTC"

#> Fugit.do_parse("0 0/1 * * * Asia/Tokyo").next_time.to_s
#=> "2022-09-20 15:00:00 +0000"

p Fugit.do_parse('0 0/1 * * *').next_time(t0).to_s
p Fugit.do_parse('0 0/1 * * *').next_time(t0).utc.to_s
  # ==> "2022-09-21 00:00:00 +0900"
  # ==> "2022-09-20 15:00:00 UTC"
p Fugit.do_parse('0 0/1 * * * Asia/Tokyo').next_time(t0).to_s
p Fugit.do_parse('0 0/1 * * * Asia/Tokyo').next_time(t0).utc.to_s
  # ==> "2022-09-21 00:00:00 +0900"
  # ==> "2022-09-20 15:00:00 UTC"

However when combined with a timezone, it seems like they aren't equivalent anymore, at least for Fugit:

How so? In the two batch of tests I ran above, fugit gives equivalent results with and without a timezone given in the cron string.

jmettraux commented 1 year ago

this is probably what you are trying to hint at, I see the problem, but it is not linked to the timezone.

require 'fugit'

p Fugit.do_parse('0 * * * *').hours            # ==> nil
p Fugit.do_parse('0 * * * * Asia/Tokyo').hours # ==> nil
p Fugit.do_parse('0 /1 * * *').hours            # ==> nil
p Fugit.do_parse('0 /1 * * * Asia/Tokyo').hours # ==> nil
p Fugit.do_parse('0 0/1 * * *').hours            # ==> [ 0 ]
p Fugit.do_parse('0 0/1 * * * Asia/Tokyo').hours # ==> [ 0 ]

# nil indicates that the cron should trigger at every hour
# [ 0 ] indicates that the cron should trigger at hour 0
JosephHalter commented 1 year ago

I see the problem, but it is not linked to the timezone [...]

You're correct indeed. Thank you for the very quick fix, I'll update the gem to the new version as soon as you release it 👍

jmettraux commented 1 year ago

Just released fugit 1.7.1 https://rubygems.org/gems/fugit/versions/1.7.1

Thanks a lot!