fugit icon indicating copy to clipboard operation
fugit copied to clipboard

Fugit.parse('now') result is incorrectly offset in Rails if ENV['TZ'] is unset

Open metkat opened this issue 7 months ago • 5 comments

Issue description

If ENV['TZ'] is unset, Fugit.parse('now') seems to incorrectly offset by the timezone offset from Time.zone.

How to reproduce

> Time.zone.now
=> Sat, 28 Jun 2025 22:45:09.571476714 PDT -07:00

> Fugit.parse('now').to_t
=> 2025-06-29 12:45:59 +0000
> Fugit.parse('now').to_s
=> "2025-06-29 05:46:12 -0700"

# issue seems to be Fugit, not EtOrbi:
> EtOrbi.now.to_s
=> "2025-06-28 22:49:22 -0700"
> EtOrbi.now.to_t
=> 2025-06-29 05:49:28 1252695/2097152 +0000

> ENV['TZ'] = "America/Los_Angeles"
=> "America/Los_Angeles"
> Fugit.parse('now').to_t
=> 2025-06-28 22:52:41 -0700
> Fugit.parse('now').to_s
=> "2025-06-28 22:52:45 -0700"

Expected behaviour

I would expect the initial Fugit.parse('now') command outputs (before setting ENV['TZ']) to match the EtOrbi.now outputs.

Context

> EtOrbi.platform_info
=> "(etz:\"America/Los_Angeles\",tnz:\"PDT\",tziv:\"2.0.6\",tzidv:nil,rv:\"3.2.8\",rp:\"aarch64-linux\",
win:false,rorv:\"7.2.2.1\",astz:[ActiveSupport::TimeZone, \"America/Los_Angeles\"],
eov:\"1.2.11\",eotnz:#<TZInfo::DataTimezone: America/Los_Angeles>,
eotnfz:\"-0700\",eotlzn:\"America/Los_Angeles\",eotnfZ:\"PDT\",debian:\"America/Los_Angeles\",
centos:nil,osx:\"Etc/UTC\")"```

metkat avatar Jun 29 '25 06:06 metkat

@metkat, hello. Could I please have the output of EtOrbi.platform_info before ENV['TZ'] is set?

The output of EtOrbi.now.to_s and EtOrbi.now_to_t after ENV['TZ'] gets set would be appreciated as well.

jmettraux avatar Jun 29 '25 07:06 jmettraux

I just realized that I never implemented any parsing of "now" in Fugit. Fugit.parse('now') works for you probably because you have the Chronic gem in your gem list. Et-Orbi, by default, uses Chronic if present.

You can disable this by doing EtOrbi.chronic_enabled = false.

I realize that it'd probably be better if I implement Fugit.parse('now') in Fugit itself, because without Chronic, Fugit.parse('now') returns nil.

Is there anything else I should now about your context?

jmettraux avatar Jun 29 '25 08:06 jmettraux

Oh! Yes re Chronic, I was in the process of migrating from Chronic to Fugitive.

Here's the output of EtOrbi.platform_info pre ENV['TZ'] being set, then EtOrbi.now.to_s and EtOrbi.now_to_t after setting it.

> ENV['TZ']
=> nil
> EtOrbi.platform_info
=> "(etz:nil,tnz:\"UTC\",tziv:\"2.0.6\",tzidv:nil,rv:\"3.2.8\",rp:\"aarch64-linux\",win:false,rorv:\"7.2.2.1\",astz:[ActiveSupport::TimeZone, \"America/Los_Angeles\"],eov:\"1.2.11\",eotnz:#<TZInfo::DataTimezone: America/Los_Angeles>,eotnfz:\"-0700\",eotlzn:\"America/Los_Angeles\",eotnfZ:\"PDT\",debian:\"America/Los_Angeles\",centos:nil,osx:\"Etc/UTC\")"
> EtOrbi.now.to_s
=> "2025-06-29 08:26:21 -0700"
> EtOrbi.now.to_t
=> 2025-06-29 15:26:41 202427/262144 +0000
>  ENV['TZ'] = "America/Los_Angeles"
=> "America/Los_Angeles"
> EtOrbi.now.to_s
=> "2025-06-29 08:27:34 -0700"
> EtOrbi.now.to_t
=> 2025-06-29 08:27:38 1737483/2097152 -0700

One thing about my context that I'd noticed and wasn't sure if it was related is that inspecting Time.zone shows an instance variable of @utc_offset=nil. Calling Time.zone.utc_offset does return an appropriate value though. Time.zone.now and Time.zone.now.utc return correctly (with ENV['TZ'] set or unset). Time.zone.now.localtime is impacted by ENV['TZ'] being set which is different than I would expect, but still returns correctly-offset values:

> Time.zone
=> #<ActiveSupport::TimeZone:0x0000ffff899ea960 @name="Pacific Time (US & Canada)", @tzinfo=#<TZInfo::DataTimezone: America/Los_Angeles>, @utc_offset=nil>
> Time.zone.utc_offset
=> -28800
> Time.zone.now
=> Sun, 29 Jun 2025 08:35:34.344551834 PDT -07:00
> Time.zone.now.utc
=> 2025-06-29 15:35:38.341972377 UTC
> Time.zone.now.localtime
=> 2025-06-29 15:36:52.996070801 +0000
> ENV['TZ'] = "America/Los_Angeles"
=> "America/Los_Angeles"
> Time.zone.now.localtime
=> 2025-06-29 08:37:25.54584101 -0700

metkat avatar Jun 29 '25 15:06 metkat

Thanks for the extra information.

If you move away from Chronic, Fugit.parse('now') will yield nil. I am not sure how I can help you then.

How are you planning to use Fugit (I guess that is what you mean by "Fugitive") ?

jmettraux avatar Jun 29 '25 23:06 jmettraux

Yup! Thanks autocorrect 🙄

I saw that both Solid Queue and GoodJob (as alternatives to Sidekiq) use Fugit. I figured I could swap it in for Chronic rather than adding yet more dependencies to a couple projects. The main application in this case is natural-language parsing of user entered datetimes in custom CMS's (where 'now' is used pretty frequently). Sounds like I'd be better off adding rather than swapping though. Thank you!

metkat avatar Jun 29 '25 23:06 metkat