Skip to content

Commit fda4e40

Browse files
committed
fix!: make Time::to_zoned() fallible and add Time::format_or_raw().
After all, the timezone can be invalid, which makes the conversion (and formatting) fail. The `format_or_raw()` method brings back an infallible version.
1 parent 2184037 commit fda4e40

File tree

3 files changed

+60
-43
lines changed

3 files changed

+60
-43
lines changed

gix-date/src/time/format.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,25 +36,31 @@ impl Time {
3636
///
3737
/// Use [`Format::Unix`], [`Format::Raw`] or one of the custom formats
3838
/// defined in the [`format`](mod@crate::time::format) submodule.
39-
pub fn format(&self, format: impl Into<Format>) -> String {
39+
///
40+
/// Note that this can fail if the timezone isn't valid and the format requires a conversion to [`jiff::Zoned`].
41+
pub fn format(&self, format: impl Into<Format>) -> Result<String, jiff::Error> {
4042
self.format_inner(format.into())
4143
}
4244

43-
fn format_inner(&self, format: Format) -> String {
44-
match format {
45-
Format::Custom(CustomFormat(format)) => self.to_zoned().strftime(format).to_string(),
45+
/// Like [`Self::format()`], but on time conversion error, produce the [RAW] format instead to make it
46+
/// infallible.
47+
pub fn format_or_raw(&self, format: impl Into<Format>) -> String {
48+
self.format_inner(format.into()).unwrap_or_else(|_| self.to_string())
49+
}
50+
51+
fn format_inner(&self, format: Format) -> Result<String, jiff::Error> {
52+
Ok(match format {
53+
Format::Custom(CustomFormat(format)) => self.to_zoned()?.strftime(format).to_string(),
4654
Format::Unix => self.seconds.to_string(),
4755
Format::Raw => self.to_string(),
48-
}
56+
})
4957
}
5058
}
5159

5260
impl Time {
5361
/// Produce a `Zoned` time for complex time computations and limitless formatting.
54-
pub fn to_zoned(self) -> jiff::Zoned {
55-
let offset = jiff::tz::Offset::from_seconds(self.offset).expect("valid offset");
56-
jiff::Timestamp::from_second(self.seconds)
57-
.expect("always valid unix time")
58-
.to_zoned(offset.to_time_zone())
62+
pub fn to_zoned(self) -> Result<jiff::Zoned, jiff::Error> {
63+
let offset = jiff::tz::Offset::from_seconds(self.offset)?;
64+
Ok(jiff::Timestamp::from_second(self.seconds)?.to_zoned(offset.to_time_zone()))
5965
}
6066
}

gix-date/tests/time/baseline.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,17 @@ fn parse_compare_format() {
6666
"{pattern:?} disagrees with baseline seconds since epoch: {actual:?}"
6767
);
6868
if let Some(format_name) = format_name {
69-
let reformatted = t.format(match format_name.as_str() {
70-
"RFC2822" => Format::Custom(format::RFC2822),
71-
"ISO8601" => Format::Custom(format::ISO8601),
72-
"ISO8601_STRICT" => Format::Custom(format::ISO8601_STRICT),
73-
"GITOXIDE" => Format::Custom(format::GITOXIDE),
74-
"UNIX" => Format::Unix,
75-
"RAW" => Format::Raw,
76-
unknown => unreachable!("All formats should be well-known and implemented: {unknown:?}"),
77-
});
69+
let reformatted = t
70+
.format(match format_name.as_str() {
71+
"RFC2822" => Format::Custom(format::RFC2822),
72+
"ISO8601" => Format::Custom(format::ISO8601),
73+
"ISO8601_STRICT" => Format::Custom(format::ISO8601_STRICT),
74+
"GITOXIDE" => Format::Custom(format::GITOXIDE),
75+
"UNIX" => Format::Unix,
76+
"RAW" => Format::Raw,
77+
unknown => unreachable!("All formats should be well-known and implemented: {unknown:?}"),
78+
})
79+
.expect("valid input time");
7880
assert_eq!(
7981
reformatted, *pattern,
8082
"{reformatted:?} disagrees with baseline pattern: {pattern:?}"

gix-date/tests/time/format.rs

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,21 @@ use gix_date::{
44
};
55

66
#[test]
7-
fn short() {
8-
assert_eq!(time().format(format::SHORT), "1973-11-30");
7+
fn short() -> gix_testtools::Result {
8+
assert_eq!(time().format(format::SHORT)?, "1973-11-30");
9+
Ok(())
910
}
1011

1112
#[test]
12-
fn unix() {
13+
fn unix() -> gix_testtools::Result {
1314
let expected = "123456789";
14-
assert_eq!(time().format(Format::Unix), expected);
15-
assert_eq!(time().format(format::UNIX), expected);
15+
assert_eq!(time().format(Format::Unix)?, expected);
16+
assert_eq!(time().format(format::UNIX)?, expected);
17+
Ok(())
1618
}
1719

1820
#[test]
19-
fn raw() {
21+
fn raw() -> gix_testtools::Result {
2022
for (time, expected) in [
2123
(time(), "123456789 +0230"),
2224
(
@@ -27,58 +29,65 @@ fn raw() {
2729
"1112911993 +0100",
2830
),
2931
] {
30-
assert_eq!(time.format(Format::Raw), expected);
31-
assert_eq!(time.format(format::RAW), expected);
32+
assert_eq!(time.format(Format::Raw)?, expected);
33+
assert_eq!(time.format(format::RAW)?, expected);
3234
}
35+
Ok(())
3336
}
3437

3538
#[test]
36-
fn iso8601() {
37-
assert_eq!(time().format(format::ISO8601), "1973-11-30 00:03:09 +0230");
39+
fn iso8601() -> gix_testtools::Result {
40+
assert_eq!(time().format(format::ISO8601)?, "1973-11-30 00:03:09 +0230");
41+
Ok(())
3842
}
3943

4044
#[test]
41-
fn iso8601_strict() {
42-
assert_eq!(time().format(format::ISO8601_STRICT), "1973-11-30T00:03:09+02:30");
45+
fn iso8601_strict() -> gix_testtools::Result {
46+
assert_eq!(time().format(format::ISO8601_STRICT)?, "1973-11-30T00:03:09+02:30");
47+
Ok(())
4348
}
4449

4550
#[test]
46-
fn rfc2822() {
47-
assert_eq!(time().format(format::RFC2822), "Fri, 30 Nov 1973 00:03:09 +0230");
48-
assert_eq!(time_dec1().format(format::RFC2822), "Sat, 01 Dec 1973 00:03:09 +0230");
51+
fn rfc2822() -> gix_testtools::Result {
52+
assert_eq!(time().format(format::RFC2822)?, "Fri, 30 Nov 1973 00:03:09 +0230");
53+
assert_eq!(time_dec1().format(format::RFC2822)?, "Sat, 01 Dec 1973 00:03:09 +0230");
54+
Ok(())
4955
}
5056

5157
#[test]
52-
fn git_rfc2822() {
53-
assert_eq!(time().format(format::GIT_RFC2822), "Fri, 30 Nov 1973 00:03:09 +0230");
58+
fn git_rfc2822() -> gix_testtools::Result {
59+
assert_eq!(time().format(format::GIT_RFC2822)?, "Fri, 30 Nov 1973 00:03:09 +0230");
5460
assert_eq!(
55-
time_dec1().format(format::GIT_RFC2822),
61+
time_dec1().format(format::GIT_RFC2822)?,
5662
"Sat, 1 Dec 1973 00:03:09 +0230"
5763
);
64+
Ok(())
5865
}
5966

6067
#[test]
61-
fn default() {
68+
fn default() -> gix_testtools::Result {
6269
assert_eq!(
63-
time().format(gix_date::time::format::GITOXIDE),
70+
time().format(gix_date::time::format::GITOXIDE)?,
6471
"Fri Nov 30 1973 00:03:09 +0230"
6572
);
6673
assert_eq!(
67-
time_dec1().format(gix_date::time::format::GITOXIDE),
74+
time_dec1().format(gix_date::time::format::GITOXIDE)?,
6875
"Sat Dec 01 1973 00:03:09 +0230"
6976
);
77+
Ok(())
7078
}
7179

7280
#[test]
73-
fn git_default() {
81+
fn git_default() -> gix_testtools::Result {
7482
assert_eq!(
75-
time().format(gix_date::time::format::DEFAULT),
83+
time().format(gix_date::time::format::DEFAULT)?,
7684
"Fri Nov 30 00:03:09 1973 +0230"
7785
);
7886
assert_eq!(
79-
time_dec1().format(gix_date::time::format::DEFAULT),
87+
time_dec1().format(gix_date::time::format::DEFAULT)?,
8088
"Sat Dec 1 00:03:09 1973 +0230"
8189
);
90+
Ok(())
8291
}
8392

8493
fn time() -> Time {

0 commit comments

Comments
 (0)