Skip to content

Commit 5871fb1

Browse files
committedJul 29, 2024··
Merge branch 'ag/jiff'
2 parents ca5de4a + 9fd1090 commit 5871fb1

File tree

30 files changed

+576
-494
lines changed

30 files changed

+576
-494
lines changed
 

Diff for: ‎.github/workflows/msrv.yml

+3-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ jobs:
1919
- ubuntu-latest
2020
runs-on: ${{ matrix.os }}
2121
env:
22-
# dictated by `firefox` to support the `helix` editor, but now driven by the `time` crate. IMPORTANT: adjust etc/msrv-badge.svg as well
23-
rust_version: 1.67.0
22+
# dictated by `firefox` to support the `helix` editor, but now probably effectively be controlled by `jiff`, which also aligns with `regex`.
23+
# IMPORTANT: adjust etc/msrv-badge.svg as well
24+
rust_version: 1.70.0
2425
steps:
2526
- uses: actions/checkout@v4
2627
- uses: extractions/setup-just@v2

Diff for: ‎Cargo.lock

+45-22
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: ‎Cargo.toml

-2
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,12 @@ http-client-reqwest = ["gix/blocking-http-transport-reqwest-rust-tls"]
164164
## Use async client networking.
165165
gitoxide-core-async-client = ["gitoxide-core/async-client", "futures-lite"]
166166

167-
168167
[dependencies]
169168
anyhow = "1.0.42"
170169

171170
gitoxide-core = { version = "^0.39.1", path = "gitoxide-core" }
172171
gix-features = { version = "^0.38.2", path = "gix-features" }
173172
gix = { version = "^0.64.0", path = "gix", default-features = false }
174-
time = "0.3.23"
175173

176174
clap = { version = "4.1.1", features = ["derive", "cargo"] }
177175
clap_complete = "4.4.3"

Diff for: ‎etc/msrv-badge.svg

+21-1
Loading

Diff for: ‎gix-actor/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ doctest = false
1818
serde = ["dep:serde", "bstr/serde", "gix-date/serde"]
1919

2020
[dependencies]
21-
gix-date = { version = "^0.8.7", path = "../gix-date" }
21+
gix-date = { version = "^0.9.0", path = "../gix-date" }
2222
gix-utils = { version = "^0.1.11", path = "../gix-utils" }
2323

2424
thiserror = "1.0.38"

Diff for: ‎gix-archive/Cargo.toml

+4-4
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,18 @@ tar = ["dep:tar", "dep:gix-path"]
2121
tar_gz = ["tar", "dep:flate2"]
2222

2323
## Enable the `zip` archive format.
24-
zip = ["dep:zip", "dep:time"]
24+
zip = ["dep:zip"]
2525

2626

2727
[dependencies]
2828
gix-worktree-stream = { version = "^0.13.1", path = "../gix-worktree-stream" }
2929
gix-object = { version = "^0.42.3", path = "../gix-object" }
3030
gix-path = { version = "^0.10.9", path = "../gix-path", optional = true }
31-
gix-date = { version = "^0.8.7", path = "../gix-date" }
31+
gix-date = { version = "^0.9.0", path = "../gix-date" }
3232

3333
flate2 = { version = "1.0.26", optional = true }
34-
zip = { version = "2.1.0", optional = true, default-features = false, features = ["deflate", "time"] }
35-
time = { version = "0.3.23", optional = true, default-features = false, features = ["std"] }
34+
zip = { version = "2.1.0", optional = true, default-features = false, features = ["deflate"] }
35+
jiff = { version = "0.1.2", default-features = false, features = ["std"] }
3636

3737
thiserror = "1.0.26"
3838
bstr = { version = "1.5.0", default-features = false }

Diff for: ‎gix-archive/src/write.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,22 @@ where
134134
{
135135
let mut ar = zip::write::ZipWriter::new(out);
136136
let mut buf = Vec::new();
137-
let mtime = time::OffsetDateTime::from_unix_timestamp(opts.modification_time)
137+
let zdt = jiff::Timestamp::from_second(opts.modification_time)
138138
.map_err(|err| Error::InvalidModificationTime(Box::new(err)))?
139-
.try_into()
140-
.map_err(|err| Error::InvalidModificationTime(Box::new(err)))?;
139+
.to_zoned(jiff::tz::TimeZone::UTC);
140+
let mtime = zip::DateTime::from_date_and_time(
141+
zdt.year()
142+
.try_into()
143+
.map_err(|err| Error::InvalidModificationTime(Box::new(err)))?,
144+
// These are all OK because month, day, hour, minute and second
145+
// are always positive.
146+
zdt.month().try_into().expect("non-negative"),
147+
zdt.day().try_into().expect("non-negative"),
148+
zdt.hour().try_into().expect("non-negative"),
149+
zdt.minute().try_into().expect("non-negative"),
150+
zdt.second().try_into().expect("non-negative"),
151+
)
152+
.map_err(|err| Error::InvalidModificationTime(Box::new(err)))?;
141153
while let Some(entry) = next_entry(stream)? {
142154
append_zip_entry(
143155
&mut ar,

Diff for: ‎gix-date/CHANGELOG.md

+340-287
Large diffs are not rendered by default.

Diff for: ‎gix-date/Cargo.toml

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
11
[package]
22
name = "gix-date"
3-
version = "0.8.7"
3+
version = "0.9.0"
44
repository = "https://github.com/Byron/gitoxide"
55
license = "MIT OR Apache-2.0"
66
description = "A crate of the gitoxide project parsing dates the way git does"
77
authors = ["Sebastian Thiel <sebastian.thiel@icloud.com>"]
88
edition = "2021"
99
include = ["src/**/*", "LICENSE-*"]
10-
rust-version = "1.65"
10+
rust-version = "1.70"
1111

1212
[lib]
1313
doctest = false
1414

1515
[features]
1616
## Data structures implement `serde::Serialize` and `serde::Deserialize`.
17-
serde= ["dep:serde", "bstr/serde"]
17+
serde = ["dep:serde", "bstr/serde"]
1818

1919
[dependencies]
20-
bstr = { version = "1.3.0", default-features = false, features = ["std"]}
21-
serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"]}
20+
bstr = { version = "1.3.0", default-features = false, features = ["std"] }
21+
serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"] }
2222
itoa = "1.0.1"
23-
time = { version = "0.3.23", default-features = false, features = ["local-offset", "formatting", "macros", "parsing"] }
23+
jiff = "0.1.1"
2424
thiserror = "1.0.32"
2525

2626
document-features = { version = "0.2.0", optional = true }
2727

2828
[dev-dependencies]
29-
gix-testtools = { path = "../tests/tools"}
29+
gix-testtools = { path = "../tests/tools" }
3030
once_cell = "1.12.0"
3131
gix-hash = { path = "../gix-hash" }
3232

Diff for: ‎gix-date/src/parse.rs

+65-38
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub enum Error {
1414
pub(crate) mod function {
1515
use std::{str::FromStr, time::SystemTime};
1616

17-
use time::{format_description::well_known, Date, OffsetDateTime};
17+
use jiff::{civil::Date, fmt::rfc2822, tz::TimeZone, Zoned};
1818

1919
use crate::{
2020
parse::{relative, Error},
@@ -32,27 +32,27 @@ pub(crate) mod function {
3232
return Ok(Time::new(42, 1800));
3333
}
3434

35-
Ok(if let Ok(val) = Date::parse(input, SHORT) {
36-
let val = val.with_hms(0, 0, 0).expect("date is in range").assume_utc();
37-
Time::new(val.unix_timestamp(), val.offset().whole_seconds())
38-
} else if let Ok(val) = OffsetDateTime::parse(input, &well_known::Rfc2822) {
39-
Time::new(val.unix_timestamp(), val.offset().whole_seconds())
40-
} else if let Ok(val) = OffsetDateTime::parse(input, ISO8601) {
41-
Time::new(val.unix_timestamp(), val.offset().whole_seconds())
42-
} else if let Ok(val) = OffsetDateTime::parse(input, ISO8601_STRICT) {
43-
Time::new(val.unix_timestamp(), val.offset().whole_seconds())
44-
} else if let Ok(val) = OffsetDateTime::parse(input, GITOXIDE) {
45-
Time::new(val.unix_timestamp(), val.offset().whole_seconds())
46-
} else if let Ok(val) = OffsetDateTime::parse(input, DEFAULT) {
47-
Time::new(val.unix_timestamp(), val.offset().whole_seconds())
35+
Ok(if let Ok(val) = Date::strptime(SHORT.0, input) {
36+
let val = val.to_zoned(TimeZone::UTC).expect("date is in range");
37+
Time::new(val.timestamp().as_second(), val.offset().seconds())
38+
} else if let Ok(val) = rfc2822_relaxed(input) {
39+
Time::new(val.timestamp().as_second(), val.offset().seconds())
40+
} else if let Ok(val) = strptime_relaxed(ISO8601.0, input) {
41+
Time::new(val.timestamp().as_second(), val.offset().seconds())
42+
} else if let Ok(val) = strptime_relaxed(ISO8601_STRICT.0, input) {
43+
Time::new(val.timestamp().as_second(), val.offset().seconds())
44+
} else if let Ok(val) = strptime_relaxed(GITOXIDE.0, input) {
45+
Time::new(val.timestamp().as_second(), val.offset().seconds())
46+
} else if let Ok(val) = strptime_relaxed(DEFAULT.0, input) {
47+
Time::new(val.timestamp().as_second(), val.offset().seconds())
4848
} else if let Ok(val) = SecondsSinceUnixEpoch::from_str(input) {
4949
// Format::Unix
5050
Time::new(val, 0)
5151
} else if let Some(val) = parse_raw(input) {
5252
// Format::Raw
5353
val
54-
} else if let Some(time) = relative::parse(input, now).transpose()? {
55-
Time::new(time.unix_timestamp(), time.offset().whole_seconds())
54+
} else if let Some(val) = relative::parse(input, now).transpose()? {
55+
Time::new(val.timestamp().as_second(), val.offset().seconds())
5656
} else {
5757
return Err(Error::InvalidDateString { input: input.into() });
5858
})
@@ -83,52 +83,79 @@ pub(crate) mod function {
8383
};
8484
Some(time)
8585
}
86+
87+
/// This is just like `Zoned::strptime`, but it allows parsing datetimes
88+
/// whose weekdays are inconsistent with the date. While the day-of-week
89+
/// still must be parsed, it is otherwise ignored. This seems to be
90+
/// consistent with how `git` behaves.
91+
fn strptime_relaxed(fmt: &str, input: &str) -> Result<Zoned, jiff::Error> {
92+
let mut tm = jiff::fmt::strtime::parse(fmt, input)?;
93+
tm.set_weekday(None);
94+
tm.to_zoned()
95+
}
96+
97+
/// This is just like strptime_relaxed, except for RFC 2822 parsing.
98+
/// Namely, it permits the weekday to be inconsistent with the date.
99+
fn rfc2822_relaxed(input: &str) -> Result<Zoned, jiff::Error> {
100+
static P: rfc2822::DateTimeParser = rfc2822::DateTimeParser::new().relaxed_weekday(true);
101+
P.parse_zoned(input)
102+
}
86103
}
87104

88105
mod relative {
89106
use std::{str::FromStr, time::SystemTime};
90107

91-
use time::{Duration, OffsetDateTime};
108+
use jiff::{tz::TimeZone, Span, Timestamp, Zoned};
92109

93110
use crate::parse::Error;
94111

95-
fn parse_inner(input: &str) -> Option<Duration> {
112+
fn parse_inner(input: &str) -> Option<Result<Span, Error>> {
96113
let mut split = input.split_whitespace();
97-
let multiplier = i64::from_str(split.next()?).ok()?;
114+
let units = i64::from_str(split.next()?).ok()?;
98115
let period = split.next()?;
99116
if split.next()? != "ago" {
100117
return None;
101118
}
102-
duration(period, multiplier)
119+
span(period, units)
103120
}
104121

105-
pub(crate) fn parse(input: &str, now: Option<SystemTime>) -> Option<Result<OffsetDateTime, Error>> {
106-
parse_inner(input).map(|offset| {
107-
let offset = std::time::Duration::from_secs(offset.whole_seconds().try_into()?);
122+
pub(crate) fn parse(input: &str, now: Option<SystemTime>) -> Option<Result<Zoned, Error>> {
123+
parse_inner(input).map(|result| {
124+
let span = result?;
125+
// This was an error case in a previous version of this code, where
126+
// it would fail when converting from a negative signed integer
127+
// to an unsigned integer. This preserves that failure case even
128+
// though the code below handles it okay.
129+
if span.is_negative() {
130+
return Err(Error::RelativeTimeConversion);
131+
}
108132
now.ok_or(Error::MissingCurrentTime).and_then(|now| {
109-
std::panic::catch_unwind(|| {
110-
now.checked_sub(offset)
111-
.expect("BUG: values can't be large enough to cause underflow")
112-
.into()
113-
})
114-
.map_err(|_| Error::RelativeTimeConversion)
133+
let ts = Timestamp::try_from(now).map_err(|_| Error::RelativeTimeConversion)?;
134+
// N.B. This matches the behavior of this code when it was
135+
// written with `time`, but we might consider using the system
136+
// time zone here. If we did, then it would implement "1 day
137+
// ago" correctly, even when it crosses DST transitions. Since
138+
// we're in the UTC time zone here, which has no DST, 1 day is
139+
// in practice always 24 hours. ---AG
140+
let zdt = ts.to_zoned(TimeZone::UTC);
141+
zdt.checked_sub(span).map_err(|_| Error::RelativeTimeConversion)
115142
})
116143
})
117144
}
118145

119-
fn duration(period: &str, multiplier: i64) -> Option<Duration> {
146+
fn span(period: &str, units: i64) -> Option<Result<Span, Error>> {
120147
let period = period.strip_suffix('s').unwrap_or(period);
121-
let seconds: i64 = match period {
122-
"second" => 1,
123-
"minute" => 60,
124-
"hour" => 60 * 60,
125-
"day" => 24 * 60 * 60,
126-
"week" => 7 * 24 * 60 * 60,
148+
let result = match period {
149+
"second" => Span::new().try_seconds(units),
150+
"minute" => Span::new().try_minutes(units),
151+
"hour" => Span::new().try_hours(units),
152+
"day" => Span::new().try_days(units),
153+
"week" => Span::new().try_weeks(units),
127154
// TODO months & years? YES
128155
// Ignore values you don't know, assume seconds then (so does git)
129156
_ => return None,
130157
};
131-
seconds.checked_mul(multiplier).map(Duration::seconds)
158+
Some(result.map_err(|_| Error::RelativeTimeConversion))
132159
}
133160

134161
#[cfg(test)]
@@ -137,7 +164,7 @@ mod relative {
137164

138165
#[test]
139166
fn two_weeks_ago() {
140-
assert_eq!(parse_inner("2 weeks ago"), Some(Duration::weeks(2)));
167+
assert_eq!(parse_inner("2 weeks ago").unwrap().unwrap(), Span::new().weeks(2));
141168
}
142169
}
143170
}

Diff for: ‎gix-date/src/time/format.rs

+22-55
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,59 @@
1-
use time::{format_description::FormatItem, macros::format_description};
2-
3-
use crate::{time::Format, Time};
1+
use crate::{
2+
time::{CustomFormat, Format},
3+
Time,
4+
};
45

56
/// E.g. `2018-12-24`
6-
pub const SHORT: &[FormatItem<'_>] = format_description!("[year]-[month]-[day]");
7+
pub const SHORT: CustomFormat = CustomFormat("%Y-%m-%d");
78

89
/// E.g. `Thu, 18 Aug 2022 12:45:06 +0800`
9-
pub const RFC2822: &[FormatItem<'_>] = format_description!(
10-
"[weekday repr:short], [day] [month repr:short] [year] [hour]:[minute]:[second] [offset_hour sign:mandatory][offset_minute]"
11-
);
10+
pub const RFC2822: CustomFormat = CustomFormat("%a, %d %b %Y %H:%M:%S %z");
1211

1312
/// E.g. `Thu, 8 Aug 2022 12:45:06 +0800`. This is output by `git log --pretty=%aD`.
14-
pub const GIT_RFC2822: &[FormatItem<'_>] = format_description!(
15-
"[weekday repr:short], \
16-
[day padding:none] \
17-
[month repr:short] \
18-
[year] \
19-
[hour]:[minute]:[second] \
20-
[offset_hour sign:mandatory][offset_minute]"
21-
);
13+
pub const GIT_RFC2822: CustomFormat = CustomFormat("%a, %-d %b %Y %H:%M:%S %z");
2214

2315
/// E.g. `2022-08-17 22:04:58 +0200`
24-
pub const ISO8601: &[FormatItem<'_>] =
25-
format_description!("[year]-[month]-[day] [hour]:[minute]:[second] [offset_hour sign:mandatory][offset_minute]");
16+
pub const ISO8601: CustomFormat = CustomFormat("%Y-%m-%d %H:%M:%S %z");
2617

2718
/// E.g. `2022-08-17T21:43:13+08:00`
28-
pub const ISO8601_STRICT: &[FormatItem<'_>] =
29-
format_description!("[year]-[month]-[day]T[hour]:[minute]:[second][offset_hour sign:mandatory]:[offset_minute]");
19+
pub const ISO8601_STRICT: CustomFormat = CustomFormat("%Y-%m-%dT%H:%M:%S%:z");
3020

3121
/// E.g. `123456789`
32-
pub const UNIX: Format<'static> = Format::Unix;
22+
pub const UNIX: Format = Format::Unix;
3323

3424
/// E.g. `1660874655 +0800`
35-
pub const RAW: Format<'static> = Format::Raw;
25+
pub const RAW: Format = Format::Raw;
3626

3727
/// E.g. `Thu Sep 04 2022 10:45:06 -0400`, like the git `DEFAULT`, but with the year and time fields swapped.
38-
pub const GITOXIDE: &[FormatItem<'_>] = format_description!(
39-
"[weekday repr:short] [month repr:short] [day] [year] [hour]:[minute]:[second] [offset_hour sign:mandatory][offset_minute]"
40-
);
28+
pub const GITOXIDE: CustomFormat = CustomFormat("%a %b %d %Y %H:%M:%S %z");
4129

4230
/// E.g. `Thu Sep 4 10:45:06 2022 -0400`. This is output by `git log --pretty=%ad`.
43-
pub const DEFAULT: &[FormatItem<'_>] = format_description!(
44-
"[weekday repr:short] \
45-
[month repr:short] \
46-
[day padding:none] \
47-
[hour]:[minute]:[second] \
48-
[year] \
49-
[offset_hour sign:mandatory][offset_minute]"
50-
);
51-
52-
mod format_impls {
53-
use time::format_description::FormatItem;
54-
55-
use crate::time::Format;
56-
57-
impl<'a> From<&'a [FormatItem<'a>]> for Format<'a> {
58-
fn from(f: &'a [FormatItem<'a>]) -> Self {
59-
Format::Custom(f)
60-
}
61-
}
62-
}
31+
pub const DEFAULT: CustomFormat = CustomFormat("%a %b %-d %H:%M:%S %Y %z");
6332

6433
/// Formatting
6534
impl Time {
6635
/// Format this instance according to the given `format`.
6736
///
68-
/// Use the [`format_description`](https://time-rs.github.io/book/api/format-description.html) macro to create and
69-
/// validate formats at compile time, courtesy of the [`time`] crate.
70-
pub fn format<'a>(&self, format: impl Into<Format<'a>>) -> String {
37+
/// Use [`Format::Unix`], [`Format::Raw`] or one of the custom formats
38+
/// defined in the [`format`](mod@crate::time::format) submodule.
39+
pub fn format(&self, format: impl Into<Format>) -> String {
7140
self.format_inner(format.into())
7241
}
7342

74-
fn format_inner(&self, format: Format<'_>) -> String {
43+
fn format_inner(&self, format: Format) -> String {
7544
match format {
76-
Format::Custom(format) => self
77-
.to_time()
78-
.format(&format)
79-
.expect("well-known format into memory never fails"),
45+
Format::Custom(CustomFormat(format)) => self.to_time().strftime(format).to_string(),
8046
Format::Unix => self.seconds.to_string(),
8147
Format::Raw => self.to_bstring().to_string(),
8248
}
8349
}
8450
}
8551

8652
impl Time {
87-
fn to_time(self) -> time::OffsetDateTime {
88-
time::OffsetDateTime::from_unix_timestamp(self.seconds)
53+
fn to_time(self) -> jiff::Zoned {
54+
let offset = jiff::tz::Offset::from_seconds(self.offset).expect("valid offset");
55+
jiff::Timestamp::from_second(self.seconds)
8956
.expect("always valid unix time")
90-
.to_offset(time::UtcOffset::from_whole_seconds(self.offset).expect("valid offset"))
57+
.to_zoned(offset.to_time_zone())
9158
}
9259
}

Diff for: ‎gix-date/src/time/init.rs

+5-23
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::ops::Sub;
2-
31
use crate::{time::Sign, OffsetInSeconds, SecondsSinceUnixEpoch, Time};
42

53
/// Instantiation
@@ -15,9 +13,7 @@ impl Time {
1513

1614
/// Return the current time without figuring out a timezone offset
1715
pub fn now_utc() -> Self {
18-
let seconds = time::OffsetDateTime::now_utc()
19-
.sub(std::time::SystemTime::UNIX_EPOCH)
20-
.whole_seconds();
16+
let seconds = jiff::Timestamp::now().as_second();
2117
Self {
2218
seconds,
2319
offset: 0,
@@ -27,28 +23,14 @@ impl Time {
2723

2824
/// Return the current local time, or `None` if the local time wasn't available.
2925
pub fn now_local() -> Option<Self> {
30-
let now = time::OffsetDateTime::now_utc();
31-
let seconds = now.sub(std::time::SystemTime::UNIX_EPOCH).whole_seconds();
32-
// TODO: make this work without cfg(unsound_local_offset), see
33-
// https://github.com/time-rs/time/issues/293#issuecomment-909158529
34-
let offset = time::UtcOffset::local_offset_at(now).ok()?.whole_seconds();
35-
Self {
36-
seconds,
37-
offset,
38-
sign: offset.into(),
39-
}
40-
.into()
26+
Some(Self::now_local_or_utc())
4127
}
4228

4329
/// Return the current local time, or the one at UTC if the local time wasn't available.
4430
pub fn now_local_or_utc() -> Self {
45-
let now = time::OffsetDateTime::now_utc();
46-
let seconds = now.sub(std::time::SystemTime::UNIX_EPOCH).whole_seconds();
47-
// TODO: make this work without cfg(unsound_local_offset), see
48-
// https://github.com/time-rs/time/issues/293#issuecomment-909158529
49-
let offset = time::UtcOffset::local_offset_at(now)
50-
.map(time::UtcOffset::whole_seconds)
51-
.unwrap_or(0);
31+
let zdt = jiff::Zoned::now();
32+
let seconds = zdt.timestamp().as_second();
33+
let offset = zdt.offset().seconds();
5234
Self {
5335
seconds,
5436
offset,

Diff for: ‎gix-date/src/time/mod.rs

+14-3
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,26 @@ pub enum Sign {
1919

2020
/// Various ways to describe a time format.
2121
#[derive(Debug, Clone, Copy)]
22-
pub enum Format<'a> {
23-
/// A custom format typically defined with the [`format_description`][time::format_description] macro.
24-
Custom(&'a [time::format_description::FormatItem<'a>]),
22+
pub enum Format {
23+
/// A custom format limited to what's in the
24+
/// [`format`](mod@crate::time::format) submodule.
25+
Custom(CustomFormat),
2526
/// The seconds since 1970, also known as unix epoch, like `1660874655`.
2627
Unix,
2728
/// The seconds since 1970, followed by the offset, like `1660874655 +0800`
2829
Raw,
2930
}
3031

32+
/// A custom format for printing and parsing time.
33+
#[derive(Clone, Copy, Debug)]
34+
pub struct CustomFormat(pub(crate) &'static str);
35+
36+
impl From<CustomFormat> for Format {
37+
fn from(custom_format: CustomFormat) -> Format {
38+
Format::Custom(custom_format)
39+
}
40+
}
41+
3142
///
3243
#[allow(clippy::empty_docs)]
3344
pub mod format;

Diff for: ‎gix-date/tests/time/format.rs

-9
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use gix_date::{
22
time::{format, Format, Sign},
33
Time,
44
};
5-
use time::macros::format_description;
65

76
#[test]
87
fn short() {
@@ -72,14 +71,6 @@ fn git_default() {
7271
)
7372
}
7473

75-
#[test]
76-
fn custom_compile_time() {
77-
assert_eq!(
78-
time().format(format_description!("[year]-[month]-[day] [hour]:[minute]:[second]")),
79-
"1973-11-30 00:03:09",
80-
);
81-
}
82-
8374
fn time() -> Time {
8475
Time {
8576
seconds: 123456789,

Diff for: ‎gix-date/tests/time/parse.rs

+13-6
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ mod relative {
146146
use std::time::SystemTime;
147147

148148
use gix_date::time::Sign;
149-
use time::{Duration, OffsetDateTime};
149+
use jiff::{ToSpan, Zoned};
150150

151151
#[test]
152152
fn large_offsets() {
@@ -173,12 +173,19 @@ mod relative {
173173
let two_weeks_ago = gix_date::parse("2 weeks ago", Some(now)).unwrap();
174174
assert_eq!(Sign::Plus, two_weeks_ago.sign);
175175
assert_eq!(0, two_weeks_ago.offset);
176-
let expected = OffsetDateTime::from(now).saturating_sub(Duration::weeks(2));
177-
// account for the loss of precision when creating `Time` with seconds
178-
let expected = expected.replace_nanosecond(0).unwrap();
176+
let expected = Zoned::try_from(now)
177+
.unwrap()
178+
// account for the loss of precision when creating `Time` with seconds
179+
.round(
180+
jiff::ZonedRound::new()
181+
.smallest(jiff::Unit::Second)
182+
.mode(jiff::RoundMode::Trunc),
183+
)
184+
.unwrap()
185+
.saturating_sub(2.weeks());
179186
assert_eq!(
180-
OffsetDateTime::from_unix_timestamp(two_weeks_ago.seconds).unwrap(),
181-
expected,
187+
jiff::Timestamp::from_second(two_weeks_ago.seconds).unwrap(),
188+
expected.timestamp(),
182189
"relative times differ"
183190
);
184191
}

Diff for: ‎gix-mailmap/Cargo.toml

+5-5
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,19 @@ doctest = false
1414

1515
[features]
1616
## Data structures implement `serde::Serialize` and `serde::Deserialize`.
17-
serde= ["dep:serde", "bstr/serde", "gix-actor/serde"]
17+
serde = ["dep:serde", "bstr/serde", "gix-actor/serde"]
1818

1919
[dependencies]
2020
gix-actor = { version = "^0.31.5", path = "../gix-actor" }
21-
gix-date = { version = "^0.8.7", path = "../gix-date" }
22-
bstr = { version = "1.3.0", default-features = false, features = ["std", "unicode"]}
21+
gix-date = { version = "^0.9.0", path = "../gix-date" }
22+
bstr = { version = "1.3.0", default-features = false, features = ["std", "unicode"] }
2323
thiserror = "1.0.38"
24-
serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"]}
24+
serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"] }
2525

2626
document-features = { version = "0.2.0", optional = true }
2727

2828
[dev-dependencies]
29-
gix-testtools = { path = "../tests/tools"}
29+
gix-testtools = { path = "../tests/tools" }
3030

3131
[package.metadata.docs.rs]
3232
all-features = true

Diff for: ‎gix-negotiate/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ test = false
1616
[dependencies]
1717
gix-hash = { version = "^0.14.2", path = "../gix-hash" }
1818
gix-object = { version = "^0.42.3", path = "../gix-object" }
19-
gix-date = { version = "^0.8.7", path = "../gix-date" }
19+
gix-date = { version = "^0.9.0", path = "../gix-date" }
2020
gix-commitgraph = { version = "^0.24.3", path = "../gix-commitgraph" }
2121
gix-revwalk = { version = "^0.13.2", path = "../gix-revwalk" }
2222
thiserror = "1.0.40"

Diff for: ‎gix-object/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ gix-features = { version = "^0.38.2", path = "../gix-features", features = [
4141
gix-hash = { version = "^0.14.2", path = "../gix-hash" }
4242
gix-validate = { version = "^0.8.5", path = "../gix-validate" }
4343
gix-actor = { version = "^0.31.4", path = "../gix-actor" }
44-
gix-date = { version = "^0.8.7", path = "../gix-date" }
44+
gix-date = { version = "^0.9.0", path = "../gix-date" }
4545
gix-utils = { version = "^0.1.11", path = "../gix-utils" }
4646

4747
itoa = "1.0.1"

Diff for: ‎gix-odb/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ serde = ["dep:serde", "gix-hash/serde", "gix-object/serde", "gix-pack/serde"]
2020
[dependencies]
2121
gix-features = { version = "^0.38.2", path = "../gix-features", features = ["rustsha1", "walkdir", "zlib", "crc32"] }
2222
gix-hash = { version = "^0.14.2", path = "../gix-hash" }
23-
gix-date = { version = "^0.8.7", path = "../gix-date" }
23+
gix-date = { version = "^0.9.0", path = "../gix-date" }
2424
gix-path = { version = "^0.10.9", path = "../gix-path" }
2525
gix-quote = { version = "^0.4.12", path = "../gix-quote" }
2626
gix-object = { version = "^0.42.3", path = "../gix-object" }

Diff for: ‎gix-protocol/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ gix-features = { version = "^0.38.2", path = "../gix-features", features = [
5050
] }
5151
gix-transport = { version = "^0.42.2", path = "../gix-transport" }
5252
gix-hash = { version = "^0.14.2", path = "../gix-hash" }
53-
gix-date = { version = "^0.8.7", path = "../gix-date" }
53+
gix-date = { version = "^0.9.0", path = "../gix-date" }
5454
gix-credentials = { version = "^0.24.4", path = "../gix-credentials" }
5555
gix-utils = { version = "^0.1.12", path = "../gix-utils" }
5656

Diff for: ‎gix-ref/Cargo.toml

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ test = true
1919
serde = ["dep:serde", "gix-hash/serde", "gix-actor/serde", "gix-object/serde"]
2020

2121
[dependencies]
22-
gix-features = { version = "^0.38.2", path = "../gix-features", features = ["walkdir"]}
22+
gix-features = { version = "^0.38.2", path = "../gix-features", features = ["walkdir"] }
2323
gix-fs = { version = "^0.11.2", path = "../gix-fs" }
2424
gix-path = { version = "^0.10.9", path = "../gix-path" }
2525
gix-hash = { version = "^0.14.2", path = "../gix-hash" }
@@ -32,7 +32,7 @@ gix-tempfile = { version = "^14.0.0", default-features = false, path = "../gix-t
3232

3333
thiserror = "1.0.34"
3434
winnow = { version = "0.6.0", features = ["simd"] }
35-
serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"]}
35+
serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"] }
3636

3737
# packed refs
3838
memmap2 = "0.9.0"
@@ -41,7 +41,7 @@ document-features = { version = "0.2.1", optional = true }
4141

4242
[dev-dependencies]
4343
gix-testtools = { path = "../tests/tools" }
44-
gix-date = { version = "^0.8.7", path = "../gix-date" }
44+
gix-date = { version = "^0.9.0", path = "../gix-date" }
4545

4646
[package.metadata.docs.rs]
4747
features = ["document-features", "serde"]

Diff for: ‎gix-revision/Cargo.toml

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,17 @@ default = ["describe"]
1919
describe = ["dep:gix-trace", "dep:gix-hashtable"]
2020

2121
## Data structures implement `serde::Serialize` and `serde::Deserialize`.
22-
serde = [ "dep:serde", "gix-hash/serde", "gix-object/serde" ]
22+
serde = ["dep:serde", "gix-hash/serde", "gix-object/serde"]
2323

2424
[dependencies]
2525
gix-hash = { version = "^0.14.2", path = "../gix-hash" }
2626
gix-object = { version = "^0.42.3", path = "../gix-object" }
27-
gix-date = { version = "^0.8.7", path = "../gix-date" }
27+
gix-date = { version = "^0.9.0", path = "../gix-date" }
2828
gix-hashtable = { version = "^0.5.2", path = "../gix-hashtable", optional = true }
2929
gix-revwalk = { version = "^0.13.2", path = "../gix-revwalk" }
3030
gix-trace = { version = "^0.1.8", path = "../gix-trace", optional = true }
3131

32-
bstr = { version = "1.3.0", default-features = false, features = ["std"]}
32+
bstr = { version = "1.3.0", default-features = false, features = ["std"] }
3333
thiserror = "1.0.26"
3434
serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"] }
3535
document-features = { version = "0.2.1", optional = true }

Diff for: ‎gix-revwalk/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ doctest = false
1515
[dependencies]
1616
gix-hash = { version = "^0.14.2", path = "../gix-hash" }
1717
gix-object = { version = "^0.42.3", path = "../gix-object" }
18-
gix-date = { version = "^0.8.7", path = "../gix-date" }
18+
gix-date = { version = "^0.9.0", path = "../gix-date" }
1919
gix-hashtable = { version = "^0.5.2", path = "../gix-hashtable" }
2020
gix-commitgraph = { version = "^0.24.3", path = "../gix-commitgraph" }
2121

Diff for: ‎gix-traverse/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ doctest = false
1616
[dependencies]
1717
gix-hash = { version = "^0.14.2", path = "../gix-hash" }
1818
gix-object = { version = "^0.42.3", path = "../gix-object" }
19-
gix-date = { version = "^0.8.7", path = "../gix-date" }
19+
gix-date = { version = "^0.9.0", path = "../gix-date" }
2020
gix-hashtable = { version = "^0.5.2", path = "../gix-hashtable" }
2121
gix-revwalk = { version = "^0.13.2", path = "../gix-revwalk" }
2222
gix-commitgraph = { version = "^0.24.3", path = "../gix-commitgraph" }

Diff for: ‎gix/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ gix-tempfile = { version = "^14.0.0", path = "../gix-tempfile", default-features
306306
gix-lock = { version = "^14.0.0", path = "../gix-lock" }
307307
gix-validate = { version = "^0.8.5", path = "../gix-validate" }
308308
gix-sec = { version = "^0.10.7", path = "../gix-sec" }
309-
gix-date = { version = "^0.8.7", path = "../gix-date" }
309+
gix-date = { version = "^0.9.0", path = "../gix-date" }
310310
gix-refspec = { version = "^0.23.1", path = "../gix-refspec" }
311311
gix-filter = { version = "^0.11.3", path = "../gix-filter", optional = true }
312312
gix-dir = { version = "^0.6.0", path = "../gix-dir", optional = true }

Diff for: ‎src/plumbing/main.rs

-5
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,6 @@ pub mod async_util {
5454

5555
pub fn main() -> Result<()> {
5656
let args: Args = Args::parse_from(gix::env::args_os());
57-
#[allow(unsafe_code)]
58-
unsafe {
59-
// SAFETY: we don't manipulate the environment from any thread
60-
time::util::local_offset::set_soundness(time::util::local_offset::Soundness::Unsound);
61-
}
6257
let thread_limit = args.threads;
6358
let verbose = args.verbose;
6459
let format = args.format;

Diff for: ‎src/porcelain/main.rs

-5
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@ use crate::porcelain::options::{Args, Subcommands};
1212

1313
pub fn main() -> Result<()> {
1414
let args: Args = Args::parse_from(gix::env::args_os());
15-
#[allow(unsafe_code)]
16-
unsafe {
17-
// SAFETY: we don't manipulate the environment from any thread
18-
time::util::local_offset::set_soundness(time::util::local_offset::Soundness::Unsound);
19-
}
2015
let should_interrupt = Arc::new(AtomicBool::new(false));
2116
#[allow(unsafe_code)]
2217
unsafe {

Diff for: ‎tests/snapshots/panic-behaviour/expected-failure

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
thread 'main' panicked at src/porcelain/main.rs:45:42:
1+
thread 'main' panicked at src/porcelain/main.rs:40:42:
22
something went very wrong
33
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
thread 'main' panicked at src/porcelain/main.rs:45:42:
1+
thread 'main' panicked at src/porcelain/main.rs:40:42:
22
something went very wrong
33
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
44

Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[?1049h[?25lthread '<unnamed>' panicked at src/porcelain/main.rs:45:42:
1+
[?1049h[?25lthread '<unnamed>' panicked at src/porcelain/main.rs:40:42:
22
something went very wrong
33
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
44
[?25h[?1049l

0 commit comments

Comments
 (0)
Please sign in to comment.