mirror of
https://github.com/chronotope/chrono.git
synced 2025-09-29 22:11:59 +00:00
GNU coreutils date
-like time zone formatting (#759)
Co-authored-by: Eric Sheppard <key2@eric.sheppard.cloud>
This commit is contained in:
parent
a383abf30e
commit
5f5410163b
@ -49,6 +49,7 @@ Versions with only mechanical changes will be omitted from the following list.
|
|||||||
* Add compatibility with rfc2822 comments (#733)
|
* Add compatibility with rfc2822 comments (#733)
|
||||||
* Make `js-sys` and `wasm-bindgen` enabled by default when target is `wasm32-unknown-unknown` for ease of API discovery
|
* Make `js-sys` and `wasm-bindgen` enabled by default when target is `wasm32-unknown-unknown` for ease of API discovery
|
||||||
* Add the `Months` struct and associated `Add` and `Sub` impls
|
* Add the `Months` struct and associated `Add` and `Sub` impls
|
||||||
|
* Add `GNU` `coreutils` `date`-like time zone formatting
|
||||||
|
|
||||||
## 0.4.19
|
## 0.4.19
|
||||||
|
|
||||||
@ -774,4 +775,3 @@ and replaced by 0.2.25 very shortly. Duh.)
|
|||||||
## 0.1.0 (2014-11-20)
|
## 0.1.0 (2014-11-20)
|
||||||
|
|
||||||
The initial version that was available to `crates.io`.
|
The initial version that was available to `crates.io`.
|
||||||
|
|
||||||
|
@ -224,6 +224,18 @@ pub enum Fixed {
|
|||||||
/// The offset is limited from `-24:00` to `+24:00`,
|
/// The offset is limited from `-24:00` to `+24:00`,
|
||||||
/// which is the same as [`FixedOffset`](../offset/struct.FixedOffset.html)'s range.
|
/// which is the same as [`FixedOffset`](../offset/struct.FixedOffset.html)'s range.
|
||||||
TimezoneOffsetColon,
|
TimezoneOffsetColon,
|
||||||
|
/// Offset from the local time to UTC with seconds (`+09:00:00` or `-04:00:00` or `+00:00:00`).
|
||||||
|
///
|
||||||
|
/// In the parser, the colon can be omitted and/or surrounded with any amount of whitespace.
|
||||||
|
/// The offset is limited from `-24:00:00` to `+24:00:00`,
|
||||||
|
/// which is the same as [`FixedOffset`](../offset/struct.FixedOffset.html)'s range.
|
||||||
|
TimezoneOffsetDoubleColon,
|
||||||
|
/// Offset from the local time to UTC without minutes (`+09` or `-04` or `+00`).
|
||||||
|
///
|
||||||
|
/// In the parser, the colon can be omitted and/or surrounded with any amount of whitespace.
|
||||||
|
/// The offset is limited from `-24` to `+24`,
|
||||||
|
/// which is the same as [`FixedOffset`](../offset/struct.FixedOffset.html)'s range.
|
||||||
|
TimezoneOffsetTripleColon,
|
||||||
/// Offset from the local time to UTC (`+09:00` or `-04:00` or `Z`).
|
/// Offset from the local time to UTC (`+09:00` or `-04:00` or `Z`).
|
||||||
///
|
///
|
||||||
/// In the parser, the colon can be omitted and/or surrounded with any amount of whitespace,
|
/// In the parser, the colon can be omitted and/or surrounded with any amount of whitespace,
|
||||||
@ -274,6 +286,15 @@ enum InternalInternal {
|
|||||||
Nanosecond9NoDot,
|
Nanosecond9NoDot,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
enum Colons {
|
||||||
|
None,
|
||||||
|
Single,
|
||||||
|
Double,
|
||||||
|
Triple,
|
||||||
|
}
|
||||||
|
|
||||||
/// A single formatting item. This is used for both formatting and parsing.
|
/// A single formatting item. This is used for both formatting and parsing.
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum Item<'a> {
|
pub enum Item<'a> {
|
||||||
@ -557,15 +578,32 @@ fn format_inner<'a>(
|
|||||||
result: &mut String,
|
result: &mut String,
|
||||||
off: FixedOffset,
|
off: FixedOffset,
|
||||||
allow_zulu: bool,
|
allow_zulu: bool,
|
||||||
use_colon: bool,
|
colon_type: Colons,
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
let off = off.local_minus_utc();
|
let off = off.local_minus_utc();
|
||||||
if !allow_zulu || off != 0 {
|
if !allow_zulu || off != 0 {
|
||||||
let (sign, off) = if off < 0 { ('-', -off) } else { ('+', off) };
|
let (sign, off) = if off < 0 { ('-', -off) } else { ('+', off) };
|
||||||
if use_colon {
|
|
||||||
write!(result, "{}{:02}:{:02}", sign, off / 3600, off / 60 % 60)
|
match colon_type {
|
||||||
} else {
|
Colons::None => {
|
||||||
write!(result, "{}{:02}{:02}", sign, off / 3600, off / 60 % 60)
|
write!(result, "{}{:02}{:02}", sign, off / 3600, off / 60 % 60)
|
||||||
|
}
|
||||||
|
Colons::Single => {
|
||||||
|
write!(result, "{}{:02}:{:02}", sign, off / 3600, off / 60 % 60)
|
||||||
|
}
|
||||||
|
Colons::Double => {
|
||||||
|
write!(
|
||||||
|
result,
|
||||||
|
"{}{:02}:{:02}:{:02}",
|
||||||
|
sign,
|
||||||
|
off / 3600,
|
||||||
|
off / 60 % 60,
|
||||||
|
off % 60
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Colons::Triple => {
|
||||||
|
write!(result, "{}{:02}", sign, off / 3600)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result.push('Z');
|
result.push('Z');
|
||||||
@ -650,17 +688,19 @@ fn format_inner<'a>(
|
|||||||
result.push_str(name);
|
result.push_str(name);
|
||||||
Ok(())
|
Ok(())
|
||||||
}),
|
}),
|
||||||
TimezoneOffsetColon => {
|
TimezoneOffsetColon => off
|
||||||
off.map(|&(_, off)| write_local_minus_utc(result, off, false, true))
|
.map(|&(_, off)| write_local_minus_utc(result, off, false, Colons::Single)),
|
||||||
}
|
TimezoneOffsetDoubleColon => off
|
||||||
TimezoneOffsetColonZ => {
|
.map(|&(_, off)| write_local_minus_utc(result, off, false, Colons::Double)),
|
||||||
off.map(|&(_, off)| write_local_minus_utc(result, off, true, true))
|
TimezoneOffsetTripleColon => off
|
||||||
}
|
.map(|&(_, off)| write_local_minus_utc(result, off, false, Colons::Triple)),
|
||||||
|
TimezoneOffsetColonZ => off
|
||||||
|
.map(|&(_, off)| write_local_minus_utc(result, off, true, Colons::Single)),
|
||||||
TimezoneOffset => {
|
TimezoneOffset => {
|
||||||
off.map(|&(_, off)| write_local_minus_utc(result, off, false, false))
|
off.map(|&(_, off)| write_local_minus_utc(result, off, false, Colons::None))
|
||||||
}
|
}
|
||||||
TimezoneOffsetZ => {
|
TimezoneOffsetZ => {
|
||||||
off.map(|&(_, off)| write_local_minus_utc(result, off, true, false))
|
off.map(|&(_, off)| write_local_minus_utc(result, off, true, Colons::None))
|
||||||
}
|
}
|
||||||
Internal(InternalFixed { val: InternalInternal::TimezoneOffsetPermissive }) => {
|
Internal(InternalFixed { val: InternalInternal::TimezoneOffsetPermissive }) => {
|
||||||
panic!("Do not try to write %#z it is undefined")
|
panic!("Do not try to write %#z it is undefined")
|
||||||
@ -681,7 +721,7 @@ fn format_inner<'a>(
|
|||||||
t.minute(),
|
t.minute(),
|
||||||
sec
|
sec
|
||||||
)?;
|
)?;
|
||||||
Some(write_local_minus_utc(result, off, false, false))
|
Some(write_local_minus_utc(result, off, false, Colons::None))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -693,7 +733,7 @@ fn format_inner<'a>(
|
|||||||
// reuse `Debug` impls which already print ISO 8601 format.
|
// reuse `Debug` impls which already print ISO 8601 format.
|
||||||
// this is faster in this way.
|
// this is faster in this way.
|
||||||
write!(result, "{:?}T{:?}", d, t)?;
|
write!(result, "{:?}T{:?}", d, t)?;
|
||||||
Some(write_local_minus_utc(result, off, false, true))
|
Some(write_local_minus_utc(result, off, false, Colons::Single))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -420,7 +420,10 @@ where
|
|||||||
try_consume!(scan::timezone_name_skip(s));
|
try_consume!(scan::timezone_name_skip(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
&TimezoneOffsetColon | &TimezoneOffset => {
|
&TimezoneOffsetColon
|
||||||
|
| &TimezoneOffsetDoubleColon
|
||||||
|
| &TimezoneOffsetTripleColon
|
||||||
|
| &TimezoneOffset => {
|
||||||
let offset = try_consume!(scan::timezone_offset(
|
let offset = try_consume!(scan::timezone_offset(
|
||||||
s.trim_left(),
|
s.trim_left(),
|
||||||
scan::colon_or_space
|
scan::colon_or_space
|
||||||
|
@ -71,6 +71,8 @@ The following specifiers are available both to formatting and parsing.
|
|||||||
| `%Z` | `ACST` | Local time zone name. Skips all non-whitespace characters during parsing. [^8] |
|
| `%Z` | `ACST` | Local time zone name. Skips all non-whitespace characters during parsing. [^8] |
|
||||||
| `%z` | `+0930` | Offset from the local time to UTC (with UTC being `+0000`). |
|
| `%z` | `+0930` | Offset from the local time to UTC (with UTC being `+0000`). |
|
||||||
| `%:z` | `+09:30` | Same as `%z` but with a colon. |
|
| `%:z` | `+09:30` | Same as `%z` but with a colon. |
|
||||||
|
|`%::z`|`+09:30:00`| Offset from the local time to UTC with seconds. |
|
||||||
|
|`%:::z`| `+09` | Offset from the local time to UTC without minutes. |
|
||||||
| `%#z` | `+09` | *Parsing only:* Same as `%z` but allows minutes to be missing or present. |
|
| `%#z` | `+09` | *Parsing only:* Same as `%z` but allows minutes to be missing or present. |
|
||||||
| | | |
|
| | | |
|
||||||
| | | **DATE & TIME SPECIFIERS:** |
|
| | | **DATE & TIME SPECIFIERS:** |
|
||||||
@ -404,10 +406,20 @@ impl<'a> Iterator for StrftimeItems<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
'+' => fix!(RFC3339),
|
'+' => fix!(RFC3339),
|
||||||
':' => match next!() {
|
':' => {
|
||||||
'z' => fix!(TimezoneOffsetColon),
|
if self.remainder.starts_with("::z") {
|
||||||
_ => Item::Error,
|
self.remainder = &self.remainder[3..];
|
||||||
},
|
fix!(TimezoneOffsetTripleColon)
|
||||||
|
} else if self.remainder.starts_with(":z") {
|
||||||
|
self.remainder = &self.remainder[2..];
|
||||||
|
fix!(TimezoneOffsetDoubleColon)
|
||||||
|
} else if self.remainder.starts_with('z') {
|
||||||
|
self.remainder = &self.remainder[1..];
|
||||||
|
fix!(TimezoneOffsetColon)
|
||||||
|
} else {
|
||||||
|
Item::Error
|
||||||
|
}
|
||||||
|
}
|
||||||
'.' => match next!() {
|
'.' => match next!() {
|
||||||
'3' => match next!() {
|
'3' => match next!() {
|
||||||
'f' => fix!(Nanosecond3),
|
'f' => fix!(Nanosecond3),
|
||||||
@ -596,6 +608,8 @@ fn test_strftime_docs() {
|
|||||||
//assert_eq!(dt.format("%Z").to_string(), "ACST");
|
//assert_eq!(dt.format("%Z").to_string(), "ACST");
|
||||||
assert_eq!(dt.format("%z").to_string(), "+0930");
|
assert_eq!(dt.format("%z").to_string(), "+0930");
|
||||||
assert_eq!(dt.format("%:z").to_string(), "+09:30");
|
assert_eq!(dt.format("%:z").to_string(), "+09:30");
|
||||||
|
assert_eq!(dt.format("%::z").to_string(), "+09:30:00");
|
||||||
|
assert_eq!(dt.format("%:::z").to_string(), "+09");
|
||||||
|
|
||||||
// date & time specifiers
|
// date & time specifiers
|
||||||
assert_eq!(dt.format("%c").to_string(), "Sun Jul 8 00:34:60 2001");
|
assert_eq!(dt.format("%c").to_string(), "Sun Jul 8 00:34:60 2001");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user