chrono icon indicating copy to clipboard operation
chrono copied to clipboard

DateTime::format("%Y-%m-%dT%H:%M:%S%.6fZ") does not work correctly for dates before the epoch.

Open rxc-amzn opened this issue 3 months ago • 1 comments

repro:

use chrono::{DateTime, TimeZone, Utc};

  // Should be 1969-12-31T23:59:59.999999Z
println!("{}", DateTime::from_timestamp_micros(-1).format("%Y-%m-%dT%H:%M:%S%.6fZ"));

Actual vs Expected Results:

Microseconds: -1
  Actual result:   1970-01-01T00:00:00.000001Z  // WRONG: +1us after epoch
  Expected result: 1969-12-31T23:59:59.999999Z  // RIGHT: -1us before epoch

Microseconds: -999999
  Actual result:   1970-01-01T00:00:00.999999Z  // WRONG: +999ms after epoch
  Expected result: 1969-12-31T23:59:59.000001Z  // RIGHT: -999ms before epoch

rxc-amzn avatar Sep 29 '25 12:09 rxc-amzn

The following test passes for me:

diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs
index 67bee104..7a09fc5f 100644
--- a/src/datetime/tests.rs
+++ b/src/datetime/tests.rs
@@ -1910,3 +1910,21 @@ fn nano_roundrip() {
         assert_eq!(nanos, nanos2);
     }
 }
+
+/// Tests for https://github.com/chronotope/chrono/issues/1743
+#[test]
+fn negative_micros() {
+    fn micros_to_string(micros: i64) -> String {
+        DateTime::from_timestamp_micros(micros)
+            .unwrap()
+            .format("%Y-%m-%dT%H:%M:%S%.6fZ")
+            .to_string()
+    }
+
+    println!("micros: -1");
+    assert_eq!(micros_to_string(-1), "1969-12-31T23:59:59.999999Z");
+    println!("micros: -999_999");
+    assert_eq!(micros_to_string(-999_999), "1969-12-31T23:59:59.000001Z");
+    println!("micros: -1_000_000");
+    assert_eq!(micros_to_string(-1_000_000), "1969-12-31T23:59:59.000000Z");
+}

So, not sure how to reproduce your problem?

djc avatar Oct 15 '25 13:10 djc