diff --git a/Cargo.lock b/Cargo.lock index 8397192b3f0..8e2c70d60ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -314,6 +314,28 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "chrono-tz" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59ae0466b83e838b81a54256c39d5d7c20b9d7daa10510a242d9b75abd5936e" +dependencies = [ + "chrono", + "chrono-tz-build", + "phf", +] + +[[package]] +name = "chrono-tz-build" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "433e39f13c9a060046954e0592a8d0a4bcb1040125cbf91cb8ee58964cfb350f" +dependencies = [ + "parse-zoneinfo", + "phf", + "phf_codegen", +] + [[package]] name = "clang-sys" version = "1.4.0" @@ -1155,16 +1177,16 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.53" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "winapi", + "windows-core", ] [[package]] @@ -1657,6 +1679,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "parse-zoneinfo" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41" +dependencies = [ + "regex", +] + [[package]] name = "parse_datetime" version = "0.6.0" @@ -2655,7 +2686,9 @@ name = "uu_date" version = "0.0.28" dependencies = [ "chrono", + "chrono-tz", "clap", + "iana-time-zone", "libc", "parse_datetime", "uucore", diff --git a/Cargo.toml b/Cargo.toml index 79e6dff4018..044f0b7f51d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -276,6 +276,8 @@ chrono = { version = "0.4.38", default-features = false, features = [ "alloc", "clock", ] } +chrono-tz = "0.8.3" +iana-time-zone = "0.1.57" clap = { version = "4.5", features = ["wrap_help", "cargo"] } clap_complete = "4.4" clap_mangen = "0.2" diff --git a/src/uu/date/Cargo.toml b/src/uu/date/Cargo.toml index a99f284713a..f9af720d3f9 100644 --- a/src/uu/date/Cargo.toml +++ b/src/uu/date/Cargo.toml @@ -22,6 +22,8 @@ chrono = { workspace = true } clap = { workspace = true } uucore = { workspace = true } parse_datetime = { workspace = true } +chrono-tz = { workspace = true } +iana-time-zone = { workspace = true } [target.'cfg(unix)'.dependencies] libc = { workspace = true } diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index 766e79bd497..e3270c2d270 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -6,10 +6,12 @@ // spell-checker:ignore (chrono) Datelike Timelike ; (format) DATEFILE MMDDhhmm ; (vars) datetime datetimes use chrono::format::{Item, StrftimeItems}; -use chrono::{DateTime, FixedOffset, Local, Offset, TimeDelta, Utc}; +use chrono::{DateTime, FixedOffset, Local, Offset, TimeDelta, TimeZone, Utc}; #[cfg(windows)] use chrono::{Datelike, Timelike}; +use chrono_tz::{OffsetName, Tz}; use clap::{crate_version, Arg, ArgAction, Command}; +use iana_time_zone::get_timezone; #[cfg(all(unix, not(target_os = "macos"), not(target_os = "redox")))] use libc::{clock_settime, timespec, CLOCK_REALTIME}; use std::fs::File; @@ -272,8 +274,15 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { for date in dates { match date { Ok(date) => { + // TODO - Revisit when chrono 0.5 is released. https://github.com/chronotope/chrono/issues/970 + let tz_str = get_timezone().unwrap_or("Etc/UTC".to_string()); + let tz: Tz = tz_str.parse().unwrap(); + let offset = tz.offset_from_utc_date(&Utc::now().date_naive()); + let tz_abbreviation = offset.abbreviation(); // GNU `date` uses `%N` for nano seconds, however crate::chrono uses `%f` - let format_string = &format_string.replace("%N", "%f"); + let format_string = &format_string + .replace("%N", "%f") + .replace("%Z", tz_abbreviation); // Refuse to pass this string to chrono as it is crashing in this crate if format_string.contains("%#z") { return Err(USimpleError::new( @@ -403,7 +412,7 @@ fn make_format_string(settings: &Settings) -> &str { Rfc3339Format::Ns => "%F %T.%f%:z", }, Format::Custom(ref fmt) => fmt, - Format::Default => "%c", + Format::Default => "%a %b %e %X %Z %Y", } } diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index 553414af853..c5c0bf7cfc9 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -462,6 +462,7 @@ fn test_date_parse_from_format() { } #[test] +#[cfg(not(target_os = "macos"))] fn test_date_from_stdin() { new_ucmd!() .arg("-f") @@ -473,8 +474,27 @@ fn test_date_from_stdin() { ) .succeeds() .stdout_is( - "Mon Mar 27 08:30:00 2023\n\ - Sat Apr 1 12:00:00 2023\n\ - Sat Apr 15 18:30:00 2023\n", + "Mon Mar 27 08:30:00 UTC 2023\n\ + Sat Apr 1 12:00:00 UTC 2023\n\ + Sat Apr 15 18:30:00 UTC 2023\n", + ); +} + +#[test] +#[cfg(target_os = "macos")] +fn test_date_from_stdin() { + new_ucmd!() + .arg("-f") + .arg("-") + .pipe_in( + "2023-03-27 08:30:00\n\ + 2023-04-01 12:00:00\n\ + 2023-04-15 18:30:00\n", + ) + .succeeds() + .stdout_is( + "Mon Mar 27 08:30:00 GMT 2023\n\ + Sat Apr 1 12:00:00 GMT 2023\n\ + Sat Apr 15 18:30:00 GMT 2023\n", ); }