floraison / fugit

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

Skips four hour increment with UTC on some occasions #43

Closed honglooker closed 3 years ago

honglooker commented 3 years ago

Issue description

Hi, thanks for making this library, it's been really useful.

We're running into an issue with this cron: 0 8-19/4 * * *. We basically want it to run every day from 8am to 7pm with a 4-hour increment, which boils down to 8am, 12pm, and 4pm.

We're having issues when we set the timezone to America/New_York, but have the system time in UTC. If we query for the next time at 8am, fugit yields 20:00 UTC (4pm EST) when we expect 16:00 UTC (12pm EST). It seems to skip a 4-hour block when requesting next right on the edge.

How to reproduce

Gemfile

source 'https://rubygems.org'

platforms :jruby do
  gem 'activesupport', '4.2.11.1'
  gem 'fugit', '1.3.6'
end

utc_repro.rb

require 'active_support/time'
require 'fugit'

cron = Fugit.parse('0 8-19/4 * * *')
# note that Time.parse only cares about sys tz, so this is 12:00 UTC <=> 08:00 EST
puts Time.use_zone('America/New_York') { cron.next_time(Time.parse('2020-09-11 12:00:00')).to_local_time }
  1. set computer timezone to UTC
  2. bundle install
  3. ruby utc_repro.rb

Error

Running ruby utc_repro.rb yields 2020-09-11 20:00:00 UTC when we would expect 2020-09-11 16:00:00 UTC.

Context

We're using jruby 9.2.13.0, but MRI should yield the same results.

Lastly, if we update the time and add a few minutes (e.g. try 12:10 UTC), we get the expected time: puts Time.use_zone('America/New_York') { cron.next_time(Time.parse('2020-09-11 12:10:00')).to_local_time } yields 2020-09-11 16:00:00 UTC.

Feel free to let me know if anything is unclear, happy to clarify.

jmettraux commented 3 years ago

Hello @honglooker,

thanks for the detailed error report, I'll be looking into it soon.

We basically want it to run every day from 8am to 7pm with a 4-hour increment, which boils down to 8am, 12pm, and 4pm.

As a workaround, would the simplified "0 8,12,16 * * * America/New_York" work for you?

jmettraux commented 3 years ago

Notes, in passing:

ENV['TZ'] = 'UTC'

p Time.now
  # 2020-09-15 02:47:23 +0000
p (Time.zone rescue "no Time.zone method")
  # "no Time.zone method"

require 'active_support/time'

p Time.now
  # 2020-09-15 02:47:24 +0000
p Time.zone
  # nil

Time.use_zone('America/New_York') do

  p Time.now
    # 2020-09-15 02:47:24 +0000
  p Time.zone
    # #<ActiveSupport::TimeZone:0x4f2544b0
    #   @name="America/New_York",
    #   @utc_offset=nil, @tzinfo=#<TZInfo::TimezoneProxy: America/New_York>>

  p Time.parse('2020-09-11 12:00:00')
    # 2020-09-11 12:00:00 +0000
  p Time.parse('2020-09-11 12:00:00').zone
    # "UTC"
  p Time.zone.parse('2020-09-11 12:00:00')
    # Fri, 11 Sep 2020 12:00:00 EDT -04:00
  p Time.zone.parse('2020-09-11 12:00:00').zone
    # "EDT"
end
jmettraux commented 3 years ago

@honglooker what version of the et-orbi gem are you using?

honglooker commented 3 years ago

Hey, thanks for the update.

I tried

cron = Fugit.parse('0 8,12,16 * * *')
puts Time.use_zone('America/New_York') { cron.next_time(Time.parse('2020-09-11 12:00:00')).to_local_time }

but it still seems to yield: 2020-09-11 20:00:00 UTC.

My version of et-orbi is .. hmm. I see two lines in the lockfile:

et-orbi (1.2.4)          
       tzinfo    
fugit (1.3.6)                                   
       et-orbi (~> 1.1, >= 1.1.8)
       raabro (~> 1.3)

I want to say 1.2.4 but I am not 100% sure.

jmettraux commented 3 years ago

@honglooker it's 1.2.4 indeed, thanks a lot!

honglooker commented 3 years ago

No prob! :)

jmettraux commented 3 years ago

@honglooker

what does

uname -a
bundle exec ruby -v
bundle exec ruby -e "p ENV['TZ']"
bundle exec ruby -r et-orbi -e "EtOrbi._make_info"

yield in your environment?

(It's supposed to look like

Darwin pollux.local 17.7.0 Darwin Kernel Version 17.7.0: Thu Dec 20 21:47:19 PST
 2018;
  root:xnu-4570.71.22~1/RELEASE_X86_64 x86_64
ruby 2.3.7p456 (2018-03-28 revision 63024) [x86_64-darwin17]
(secs:1553304485.185308,utc~:"2019-03-23 01:28:05.18530797958374023",ltz~:"JST")
(etz:nil,tnz:"JST",tziv:"2.0.0",tzidv:"1.2018.9",rv:"2.3.7",rp:"x86_64-darwin17"
,win:false,
  rorv:nil,astz:nil,eov:"1.1.7",eotnz:#<TZInfo::TimezoneProxy: Asia/Tokyo>,eotnf
z:"+0900",
  eotlzn:"Asia/Tokyo",eotnfZ:"JST",debian:nil,centos:nil,osx:"zoneinfo/Asia/Toky
o")

)

Thanks in advance.

honglooker commented 3 years ago

uname -a

Darwin [REDACTED] x86_64

bundle exec ruby -v

jruby 9.1.17.0 (2.3.3) 2018-04-20 d8b1ff9 Java HotSpot(TM) 64-Bit Server VM 25.221-b11 on 1.8.0_221-b11 +jit [darwin-x86_64]

Note: Looks like jruby for this utc_repro.rb instance is a version behind what I expected. Does not change outcome

bundle exec ruby -e "p ENV['TZ']"

nil

Note: nil because I manually set timezone via system settings

bundle exec ruby -r et-orbi -e "EtOrbi._make_info"

Gem::LoadError: You have already activated tzinfo 2.0.2, but your Gemfile requires tzinfo 1.2.7. Prepending `bundle exec` to your command may solve this.
  check_for_activated_spec! at [...]jruby-9.1.17.0/lib/ruby/gems/shared/gems/bundler-2.0.2/lib/bundler/runtime.rb:319
    block in setup at [...]jruby-9.1.17.0/lib/ruby/gems/shared/gems/bundler-2.0.2/lib/bundler/runtime.rb:31
      each at org/jruby/RubyArray.java:1735
      each at [...]jruby-9.1.17.0/lib/ruby/gems/shared/gems/bundler-2.0.2/lib/bundler/spec_set.rb:148
        map at org/jruby/RubyEnumerable.java:830
      setup at [...]jruby-9.1.17.0/lib/ruby/gems/shared/gems/bundler-2.0.2/lib/bundler/runtime.rb:26
      setup at [...]jruby-9.1.17.0/lib/ruby/gems/shared/gems/bundler-2.0.2/lib/bundler.rb:107
      <main> at [...]jruby-9.1.17.0/lib/ruby/gems/shared/gems/bundler-2.0.2/lib/bundler/setup.rb:10
      require at org/jruby/RubyKernel.java:956
      require at [...]jruby-9.1.17.0/lib/ruby/stdlib/rubygems/core_ext/kernel_require.rb:55

Note: interesting failure here. Surprised to see a stacktrace. Maybe because my repro gemfile does not explicitly import EtOrbi? Should be there as a dependency...

Let me know if you need anything else from me. Thanks again for taking a look!

honglooker commented 3 years ago

Got it. Had to bundle clean --force:

(secs:1600196163.6663709,utc~:"2020-09-15 18:56:03.6663708686828613",ltz~:"UTC")
(etz:nil,tnz:"UTC",tziv:"1.2.7",tzidv:nil,rv:"2.3.3",rp:"java",win:false,rorv:nil,astz:nil,eov:"1.2.4",eotnz:#<TZInfo::DataTimezone: UTC>,eotnfz:"Z",eotlzn:"UTC",eotnfZ:"UTC",debian:nil,centos:nil,osx:"UTC")

Thanks again!

jmettraux commented 3 years ago

@honglooker wrote:

Note: nil because I manually set timezone via system settings

Thanks, I wanted to double check that it wasn't set on top of the system settings. EtOrbi and Fugit do follow TZ over other zone indicators.

honglooker commented 3 years ago

Gotcha, thanks for clarifying.

jmettraux commented 3 years ago

I think that's the cause of the skip: https://github.com/floraison/fugit/blob/master/lib/fugit/cron.rb#L254-L258

I'll investigate further during my next break.

jmettraux commented 3 years ago

@honglooker Hello, I think the fix above solves your issue. If you could verify on your side and let me know. Thanks in advance!

honglooker commented 3 years ago

Hey, thanks for the quick fix! I gave it a try:

...
Using fugit 1.3.9 from git://github.com/floraison/fugit (at master@6792de1)
...
❯ bundle exec ruby utc_repro.rb
2020-09-11 16:00:00 UTC

I'm getting 16:00, which is 12:00 eastern time -- it works. Thank you for the fast turnaround time!

jmettraux commented 3 years ago

OK, thanks again, I'll release 1.3.9 soon and then close the issue. I'm happy you circled this one.

honglooker commented 3 years ago

Great, thank you!

jmettraux commented 3 years ago

Fugit 1.3.9 is available.

Thanks a lot!

honglooker commented 3 years ago

Perfect, much appreciated!