Repository: eza-community/eza (language: rust)

Issue:
bug: No such local time in datetime/mod.rs
I am getting an error while listing some of my directories (`~/.config`, `/etc`, ) with gradient color scale for age:
```
thread 'main' panicked at 'No such local time', /cargo/registry/src/index.crates.io-6f17d22bba15001f/chrono-0.4.31/src/datetime/mod.rs:1418:38
```
I am not sure why it happens in these directories, and am not sure what info I can provide for you to reproduce this.
My `/etc` looks like this (356 entries):
```
❯ eza -l /etc --time-style full-iso -sold
drwxr-xr-x@    - root  2023-11-16 11:07:55.718581390 +0100 cups
.rw-r--r--@ 106k root  2023-11-16 09:12:27.991715092 +0100 ld.so.cache
drwxr-xr-x@    - root  2023-11-16 09:12:25.357698570 +0100 ld.so.conf.d
(...)
.rw-r--r--@  493 root  2021-04-16 17:32:39.000000000 +0100 logrotate.conf
.rw-r--r--@  938 root  2019-09-09 13:30:20.000000000 +0100 ts.conf
.rw-r--r--@ 1,8k root  2018-09-17 17:28:27.000000000 +0100 signond.conf
```

My `~/.config` (265 entries):
```
drwxr-xr-x@    - leepa 2023-11-16 11:39:47.277865133 +0100 rclone
drwxr-xr-x@    - leepa 2023-11-16 11:03:07.827403689 +0100 gcloud
.rw-------@  415 leepa 2023-11-16 10:54:44.666833735 +0100 kactivitymanagerdrc
(...)
.rw-------@   66 leepa 2021-11-26 11:22:55.553778717 +0100 akregatorrc
.rw-------@   74 leepa 2021-11-26 11:22:55.518780667 +0100 kmixrc
.rw-------@  105 leepa 2021-11-26 11:22:55.381788303 +0100 ktimezonedrc
```

Info
---
- The version of eza being used
```
❯ eza --version
eza - A modern, maintained replacement for ls
v0.15.3 [+git]
https://github.com/eza-community/eza
```
- The command-line arguments you are using
```
❯ eza -l --color-scale age /etc
```
- Your operating system and hardware platform
```
❯ inxi -S --no-host
System:
  Kernel: 6.5.11-300.fc39.x86_64 arch: x86_64 bits: 64 Desktop: KDE Plasma
    v: 5.27.9 Distro: Fedora release 39 (Thirty Nine)
```
- Backtrace:
```
❯ RUST_BACKTRACE=full eza -l --color-scale age /etc  
thread 'main' panicked at 'No such local time', /cargo/registry/src/index.crates.io-6f17d22bba15001f/chrono-0.4.31/src/datetime/mod.rs:1418:38
stack backtrace:
   0:     0x55f68fcc489c - <unknown>
   1:     0x55f68fc738ff - <unknown>
   2:     0x55f68fc9db94 - <unknown>
   3:     0x55f68fcc5f0f - <unknown>
   4:     0x55f68fcc5b0e - <unknown>
   5:     0x55f68fcc6b80 - <unknown>
   6:     0x55f68fcc6634 - <unknown>
   7:     0x55f68fcc65c6 - <unknown>
   8:     0x55f68fcc65b1 - <unknown>
   9:     0x55f68fc17ba2 - <unknown>
  10:     0x55f68fc71d3d - <unknown>
  11:     0x55f68fc3561e - <unknown>
  12:     0x55f68fc40b5c - <unknown>
  13:     0x55f68fc420d7 - <unknown>
  14:     0x55f68fc637bd - <unknown>
  15:     0x55f68fc6212c - <unknown>
  16:     0x55f68fc6157a - <unknown>
  17:     0x55f68fc5f01c - <unknown>
  18:     0x55f68fc1ea23 - <unknown>
  19:     0x55f68fc66d2d - <unknown>
  20:     0x7f6dec76b14a - __libc_start_call_main
  21:     0x7f6dec76b20b - __libc_start_main_impl
  22:     0x55f68fc1e009 - <unknown>
  23:                0x0 - <unknown>
```


Discussion / hints:
From digging through the `chrono` code, it's because there's a `LocalResult` of type `None` created, and the comment for that says:
```
/// Given local time representation is invalid.
/// This can occur when, for example, the positive timezone transition.
```
I don't really know what that means, however.

@tleepa Would you be happy compiling a debug version and running the command with RUST_BACKTRACE again? i.e. clone the `eza` repository then `cd` into it and run `cargo build`, then `RUST_BACKTRACE=full target/debug/eza -l --color-scale age /etc`
Debug:
```
❯ RUST_BACKTRACE=full ./Downloads/eza -l --color-scale age /etc      
thread 'main' panicked at /home/leepa/.cargo/registry/src/index.crates.io-6f17d22bba15001f/chrono-0.4.31/src/datetime/mod.rs:1418:38:
No such local time
stack backtrace:
   0:     0x5643518e913c - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::hb3291a57fade45e0
   1:     0x56435191002c - core::fmt::write::hfdd5aaf5eb3de157
   2:     0x5643518e628d - std::io::Write::write_fmt::ha5af58e43aa46d70
   3:     0x5643518e8f24 - std::sys_common::backtrace::print::h0b08a90a15e49bcf
   4:     0x5643518ea5d3 - std::panicking::default_hook::{{closure}}::h7dc2bac5c0aaae86
   5:     0x5643518ea2ec - std::panicking::default_hook::h0560519392c08460
   6:     0x5643518eab59 - std::panicking::rust_panic_with_hook::h4774589ac7e41b5c
   7:     0x5643518eaa11 - std::panicking::begin_panic_handler::{{closure}}::h1106262a85badff0
   8:     0x5643518e9666 - std::sys_common::backtrace::__rust_end_short_backtrace::h1fec32bba27becfa
   9:     0x5643518ea7a2 - rust_begin_unwind
  10:     0x564351692b03 - core::panicking::panic_fmt::hede3e62893827817
  11:     0x56435188c3b8 - chrono::offset::LocalResult<T>::unwrap::ha58b4d73ca569ab2
                               at /home/leepa/.cargo/registry/src/index.crates.io-6f17d22bba15001f/chrono-0.4.31/src/offset/mod.rs:197:34
  12:     0x56435189f2e9 - <chrono::datetime::DateTime<chrono::offset::utc::Utc> as core::convert::From<std::time::SystemTime>>::from::h9def31ec73565bcf
                               at /home/leepa/.cargo/registry/src/index.crates.io-6f17d22bba15001f/chrono-0.4.31/src/datetime/mod.rs:1418:9
  13:     0x5643516b3a72 - eza::fs::file::File::created_time::{{closure}}::ha81daaefe2776284
                               at /home/leepa/Repos/Public/eza/src/fs/file.rs:752:23
  14:     0x5643516ac863 - core::result::Result<T,E>::map::h108816145af21113
                               at /builddir/build/BUILD/rustc-1.73.0-src/library/core/src/result.rs:746:25
  15:     0x5643516dbfc2 - eza::fs::file::File::created_time::h97ec3e3e1cd105d2
                               at /home/leepa/Repos/Public/eza/src/fs/file.rs:750:9
  16:     0x5643516ba960 - eza::output::color_scale::update_information_recursively::h19c440059ffbb706
                               at /home/leepa/Repos/Public/eza/src/output/color_scale.rs:116:17
  17:     0x5643516ba551 - eza::output::color_scale::ColorScaleInformation::from_color_scale::hf584a8548ba88cdf
                               at /home/leepa/Repos/Public/eza/src/output/color_scale.rs:57:13
  18:     0x5643516ff6a4 - eza::output::details::Render::render::ha544ee4ecc97b7e2
                               at /home/leepa/Repos/Public/eza/src/output/details.rs:168:32
  19:     0x5643516c9a4f - eza::Exa::print_files::hdc8c6c57f67dd48c
                               at /home/leepa/Repos/Public/eza/src/main.rs:420:17
  20:     0x5643516c898c - eza::Exa::print_dirs::h02643105116164db
                               at /home/leepa/Repos/Public/eza/src/main.rs:357:13
  21:     0x5643516c7581 - eza::Exa::run::hc96fc848c75cb5dc
                               at /home/leepa/Repos/Public/eza/src/main.rs:274:9
  22:     0x5643516c5ef2 - eza::main::h89869d841fb220d2
                               at /home/leepa/Repos/Public/eza/src/main.rs:89:19
  23:     0x56435170bffb - core::ops::function::FnOnce::call_once::hf56bfc70306ef65f
                               at /builddir/build/BUILD/rustc-1.73.0-src/library/core/src/ops/function.rs:250:5
  24:     0x5643516e7a0e - std::sys_common::backtrace::__rust_begin_short_backtrace::h1cc4bd966d0add1e
                               at /builddir/build/BUILD/rustc-1.73.0-src/library/std/src/sys_common/backtrace.rs:154:18
  25:     0x564351696b21 - std::rt::lang_start::{{closure}}::hcfed4e7c54272ebb
                               at /builddir/build/BUILD/rustc-1.73.0-src/library/std/src/rt.rs:166:18
  26:     0x5643518e1e2b - std::rt::lang_start_internal::h70f1b381b1939be6
  27:     0x564351696afa - std::rt::lang_start::he7e25a3147277438
                               at /builddir/build/BUILD/rustc-1.73.0-src/library/std/src/rt.rs:165:17
  28:     0x5643516c9eee - main
  29:     0x7f01a7cd314a - __libc_start_call_main
  30:     0x7f01a7cd320b - __libc_start_main_impl
  31:     0x5643516932b5 - _start
  32:                0x0 - <unknown>
```
Thanks, so the problematic code in `eza` is in `file.rs` line 752:

```rust
  self.metadata
     .created()
     .map(|st| DateTime::<Utc>::from(st).naive_utc())
     .ok()
```

It's having trouble taking the created date of a file and converting it to a `DateTime<Utc>`. Do any of your files have missing or obviously incorrect created times if you list them with `ls`?
Found the culprit:
```
❯ /usr/bin/ls -ltr --time=birth /etc
(...)
drwxr-xr-x. 1 root  lp        572 8288116693531715368 cups

❯ /usr/bin/ls -ltr --time=birth ~/.config
drwxr-xr-x. 1 leepa leepa   288 -7992805835218996915  gcloud
(...)
```

So, I guess, I need to recreate those files to get rid of the problem :)
Thank you for helping finding these abominations :)
If you're seeing things like this in more than one place it suggests you might have some kind of file system or memory corruption - I'd give the disks and memory a check.

Either way, `eza` shouldn't crash so I'll try to fix that problem.
This bug seems to be back? I noticed it happening on Arch and confirmed with a debug build of eza from main branch.
```
$ RUST_BACKTRACE=1 target/debug/eza -l --color-scale=all file
thread 'main' panicked at 'No such local time', /home/zea/.config/cargo/registry/src/index.crates.io-6f17d22bba15001f/chrono-0.4.34/src/datetime/mod.rs:1633:38
stack backtrace:
   0: rust_begin_unwind
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/panicking.rs:578:5
   1: core::panicking::panic_fmt
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/panicking.rs:67:14
   2: chrono::offset::LocalResult<T>::unwrap
             at /home/zea/.config/cargo/registry/src/index.crates.io-6f17d22bba15001f/chrono-0.4.34/src/offset/mod.rs:197:34
   3: <chrono::datetime::DateTime<chrono::offset::utc::Utc> as core::convert::From<std::time::SystemTime>>::from
             at /home/zea/.config/cargo/registry/src/index.crates.io-6f17d22bba15001f/chrono-0.4.34/src/datetime/mod.rs:1633:9
   4: eza::fs::file::File::modified_time::{{closure}}
             at ./src/fs/file.rs:729:23
   5: core::result::Result<T,E>::map
             at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/result.rs:759:25
   6: eza::fs::file::File::modified_time
             at ./src/fs/file.rs:727:9
   7: eza::output::color_scale::update_information_recursively
             at ./src/output/color_scale.rs:122:17
```

You can run `touch --date=999999-01-01 a` to generate that file. Strangely it works with 5 9s but 6 is the limit. Also, through binary search, 262142 seems to be the largest year that doesn't cause a crash, which looks suspiciously close to 2^18.
ruh-roh >_>
It looks like I fixed this for `btime` (birth time) in #671 because it was causing issues, but not `ctime` (created time), `atime` (accessed time) or `mtime` (modified time). The fix should be the same for those three. I'll do it when I get around to it, or someone else can if they'd like to jump in!

https://github.com/eza-community/eza/blob/665c1cb013f2ee2478a5d5cf132aefc17384925d/src/fs/file.rs#L772-L775 vs. https://github.com/eza-community/eza/blob/665c1cb013f2ee2478a5d5cf132aefc17384925d/src/fs/file.rs#L758-L761 and (not sure why this one's different at first glance) https://github.com/eza-community/eza/blob/665c1cb013f2ee2478a5d5cf132aefc17384925d/src/fs/file.rs#L742 and https://github.com/eza-community/eza/blob/665c1cb013f2ee2478a5d5cf132aefc17384925d/src/fs/file.rs#L727-L730
I copied your solution to the others (except ctime since `std::fs::Metadata` doesn't expose that, which is why it's different) but I'm still getting the crash, and looking closer it *is* in btime on the file that prompted me to come here! It seems chrono's `From<SystemTime> for DateTime<Utc>` has an unwrap.

However, `NaiveDateTime::from_timestamp*` return `None` on an error, so maybe it's best to do something more similar to what `changed_time()` is doing. Doing this ugly `Duration` unpacking and repacking via `NaiveDateTime::from_timestamp_opt` no longer crashes for me.

Fix patch:
diff --git a/src/fs/file.rs b/src/fs/file.rs
index ba2703d91..b89d10cef 100644
--- a/src/fs/file.rs
+++ b/src/fs/file.rs
@@ -13,6 +13,7 @@ use std::str;
 #[cfg(unix)]
 use std::sync::Mutex;
 use std::sync::OnceLock;
+use std::time::SystemTime;
 
 use chrono::prelude::*;
 
@@ -716,6 +717,20 @@ impl<'dir> File<'dir> {
         }
     }
 
+    /// Converts a `SystemTime` to a `NaiveDateTime` without panicking.
+    ///
+    /// Fixes #655 and #667 in `Self::modified_time`, `Self::accessed_time` and
+    /// `Self::created_time`.
+    fn systemtime_to_naivedatetime(st: SystemTime) -> Option<NaiveDateTime> {
+        let duration = st.duration_since(SystemTime::UNIX_EPOCH).ok()?;
+
+        // FIXME: NaiveDateTime::from_timestamp_opt is deprecated since chrono 0.4.35
+        NaiveDateTime::from_timestamp_opt(
+            duration.as_secs().try_into().ok()?,
+            (duration.as_nanos() % 1_000_000_000).try_into().ok()?,
+        )
+    }
+
     /// This file’s last modified timestamp, if available on this platform.
     pub fn modified_time(&self) -> Option<NaiveDateTime> {
         if self.is_link() && self.deref_links {
@@ -726,8 +741,8 @@ impl<'dir> File<'dir> {
         }
         self.metadata
             .modified()
-            .map(|st| DateTime::<Utc>::from(st).naive_utc())
             .ok()
+            .and_then(Self::systemtime_to_naivedatetime)
     }
 
     /// This file’s last changed timestamp, if available on this platform.
@@ -757,8 +772,8 @@ impl<'dir> File<'dir> {
         }
         self.metadata
             .accessed()
-            .map(|st| DateTime::<Utc>::from(st).naive_utc())
             .ok()
+            .and_then(Self::systemtime_to_naivedatetime)
     }
 
     /// This file’s created timestamp, if available on this platform.
@@ -769,10 +784,10 @@ impl<'dir> File<'dir> {
                 _ => None,
             };
         }
-        match self.metadata.created() {
-            Ok(btime) => Some(DateTime::<Utc>::from(btime).naive_utc()),
-            Err(_) => None,
-        }
+        self.metadata
+            .created()
+            .ok()
+            .and_then(Self::systemtime_to_naivedatetime)
     }
 
     /// This file’s ‘type’.


Test patch: