atuin icon indicating copy to clipboard operation
atuin copied to clipboard

Add timezone configuration option & CLI overrides

Open cyqsimon opened this issue 6 months ago • 19 comments

When reviewing history (usually for the purpose of filling out a work log), I often find it helpful if the timestamps are displayed in the local timezone. This PR adds this feature.

Currently, the --tz option either accepts an offset from UTC in the form of <+|-><hour>[:<minute>[:<second>]], or the special value l/local to use the system's current timezones.

I also wanted to add support for named timezones using chrono_tz, but that seems to require pulling in chrono as well, which feels very redundant considering that we already depend on time. So I left that bit out for now.

Unresolved questions

  • [ ] Are you (maintainers) willing to add chrono as a dependency for named timezone support? Or are there alternative, independent crates to chrono_tz?
  • [x] Do you think we need tests for this? I feel like it's borderline "too simple to warrant testing", but I would be happy to add them too if you so desire.

cyqsimon avatar Jan 07 '24 13:01 cyqsimon

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
atuin-docs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jan 10, 2024 8:42am

vercel[bot] avatar Jan 07 '24 13:01 vercel[bot]

Generally looks good, thank you!

Are you (maintainers) willing to add chrono as a dependency for named timezone support? Or are there alternative, independent crates to chrono_tz?

If there are any other options, then I'd rather not. I'm not aware of any other crates, though time is not named particularly helpfully for googling things. If chrono is the only possible choice then that's ok though

Do you think we need tests for this? I feel like it's borderline "too simple to warrant testing", but I would be happy to add them too if you so desire.

Tests would be good, even if very bare. It would be nice to ensure this continues to work with any possible future changes too

Otherwise, would you be able to update the docs too please?

ellie avatar Jan 07 '24 17:01 ellie

So I tried to implement named timezones using chrono_tz but as we all know, trying is the first step to failure.

It turns out (unsurprisingly so) that time and chrono have complete different ways and syntices to handle timezones, and are barely interoperable. With enough effort I think I can get it to work, but the maintainability will surely be bad and frankly I think it's just not worth it.

I'll add tests and call it a day I guess. If ever in the future we decide to migrate to using chrono, I will be happy to add this retroactively.

cyqsimon avatar Jan 08 '24 12:01 cyqsimon

Hey! Just wondering if there's anything I can do to help this one move forwards? 🙏

ellie avatar Jan 23 '24 12:01 ellie

Hey! Just wondering if there's anything I can do to help this one move forwards? 🙏

Thanks for offering. Here's where I'm at:

As mentioned previously, the safety checks implemented by time while justified, is making acquiring the local timezone failure-prone on Unix systems, both in release and in test.

Currently, the specific problem is that cargo test runs the tests multithreaded by default, which makes time refuse to report the local timezone. I've been trying to find a way around it (without mandating the user run tests with -j1) but for now have come up empty-handed.

There's also the long-term concern that this is essentially a landmine if in the future we ever want to make atuin-history multithreaded for whatever reason. It's just annoying all-round.

cyqsimon avatar Jan 23 '24 13:01 cyqsimon

I've also explored the very hacky method of obtaining the local timezone using a shell command, something like this:

#[cfg(target_os = "linux")]
let offset = {
    let tz_raw = process::Command::new("date").arg("+%:::z").output()?.stdout;
    UtcOffset::parse(std::str::from_utf8(&tz_raw)?.trim(), OFFSET_FMT)?
};
#[cfg(not(target_os = "linux"))]
let offset = UtcOffset::current_local_offset()?;

Unfortunately, not even this is viable because unlike GNU date, POSIX date only supports printing named timezones.

I'm honestly dumbfounded that such a simple problem can cause so much trouble.

cyqsimon avatar Jan 23 '24 13:01 cyqsimon

I guess I'm just looking for ideas at this point. As a last resort we can get rid of local timezone support altogether, although it really is the last resort.

cyqsimon avatar Jan 23 '24 14:01 cyqsimon

I've also been unable to find anything that would be a reasonable workaround, and keep local timezone support in this way.

What might work is

  1. Add timezone config to Settings
  2. Read the local timezone right at the very beginning, before we potentially start any multithreaded runtimes.
  3. If the config file doesn't specify a timezone, override with the value we read at program start
  4. For tests, specify an offset - they have a different entry point, so will never try to read anything from the env

Doesn't quite achieve everything we'd like to, but is 80% of the way there I think.

ellie avatar Jan 23 '24 18:01 ellie

also, thank you for looking into this so much, ik it's been more than expected

ellie avatar Jan 23 '24 18:01 ellie

This pull request has been mentioned on Atuin Community. There might be relevant details there:

https://forum.atuin.sh/t/feedback-on-the-inspector/89/2

atuin-bot avatar Jan 24 '24 19:01 atuin-bot

  1. Read the local timezone right at the very beginning, before we potentially start any multithreaded runtimes.

This is already the case, which is why the feature works but the test fails. I can add some comments in relevant places to remind future maintainers of this requirement.

  1. Add timezone config to Settings
  2. If the config file doesn't specify a timezone, override with the value we read at program start

From my POV I don't really see a reason to make a global config for this. But maybe that's just because I'm tunnel-visioned on this single feature while you have a broader view of the whole project. Can you please clarify what other components of atuin plan to make use of this config (if indeed this is the case)?

  1. For tests, specify an offset - they have a different entry point, so will never try to read anything from the env

This test already exists as can_parse_offset_timezone_spec. So is it okay if I just get rid of can_parse_local_timezone_spec?

cyqsimon avatar Jan 25 '24 05:01 cyqsimon

This is already the case, which is why the feature works but the test fails. I can add some comments in relevant places to remind future maintainers of this requirement.

I think if we keep the timezone-reading separate to everything else, we don't need to call it in the tests - if it's going to be this difficult, anyway.

Can you please clarify what other components of atuin plan to make use of this config (if indeed this is the case)?

I'm being asked about timezones a lot right now, essentially for any area that displays time. In the TUI, in the stats, etc. A global config means we can resolve that everywhere.

ellie avatar Jan 25 '24 14:01 ellie

This pull request has been mentioned on Atuin Community. There might be relevant details there:

https://forum.atuin.sh/t/can-i-use-local-timezone-for-my-history/101/2

atuin-bot avatar Jan 25 '24 14:01 atuin-bot

I'm working on adding timezone as an option in settings, but saw that there is already the field local_tz. Apparently this was added about the same time as this PR (#1477).

Currently it's marked with #[serde(skip)]. I'm thinking, maybe I should just promote this (with a rename to timezone perhaps) to a full configuration option and use it. What do you think?

Edit: I thought I might as well just do it now and change it if necessary. Please take a look at the code, thanks.


Edit 2: I only realised this after the change, but this unification is a breaking change. This is because previously atuin stats uses local timezone exclusively, while atuin history uses UTC exclusively. By uniting them under one configuration option (which admittedly, is more consistent, and probably is what we want to do anyway), one of them has to break. I would like to know your opinion on this.

cyqsimon avatar Jan 26 '24 02:01 cyqsimon

Rebased.

cyqsimon avatar Jan 26 '24 03:01 cyqsimon

I'm working on adding timezone as an option in settings, but saw that there is already the field local_tz. Apparently this was added about the same time as this PR (https://github.com/atuinsh/atuin/pull/1477).

Ahhh I'm sorry I totally blanked on that 😭

Currently it's marked with #[serde(skip)]. I'm thinking, maybe I should just promote this (with a rename to timezone perhaps) to a full configuration option and use it. What do you think?

Seems reasonable

By uniting them under one configuration option (which admittedly, is more consistent, and probably is what we want to do anyway), one of them has to break. I would like to know your opinion on this.

I think for general guidance on timezones, we should follow

  1. Always always store UTC
  2. Display either in the locally fetched timezone, or the configured timezone

ellie avatar Jan 26 '24 17:01 ellie

couple of minor comments, but looks great - thank you!

ellie avatar Jan 26 '24 18:01 ellie

Only a few conflicts left and I'll get it merged!

ellie avatar Jan 30 '24 13:01 ellie

Rebased.

cyqsimon avatar Jan 30 '24 15:01 cyqsimon

I was convinced I'd merged this, sorry!

ellie avatar Feb 06 '24 15:02 ellie

Thank you! Really happy to get this in 🙏

ellie avatar Feb 06 '24 15:02 ellie