Skip to content

Commit 1a43970

Browse files
committed
use implementation from chrono#883 for begin-of-day
1 parent 276ad28 commit 1a43970

File tree

6 files changed

+52
-35
lines changed

6 files changed

+52
-35
lines changed

risuto-api/src/lib.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,30 @@ pub fn validate_time(s: &Time) -> Result<(), Error> {
5454
Ok(())
5555
}
5656
}
57+
58+
// See https://github.com/chronotope/chrono/issues/948
59+
pub fn midnight_on<Tz>(date: chrono::NaiveDate, tz: &Tz) -> chrono::DateTime<Tz>
60+
where
61+
Tz: Clone + std::fmt::Debug + chrono::TimeZone,
62+
{
63+
let base = chrono::NaiveTime::MIN;
64+
for multiple in 0..=24 {
65+
let start_time = base + chrono::Duration::minutes(multiple * 15);
66+
match date.and_time(start_time).and_local_timezone(tz.clone()) {
67+
chrono::LocalResult::None => continue,
68+
chrono::LocalResult::Single(dt) => return dt,
69+
chrono::LocalResult::Ambiguous(dt1, dt2) => {
70+
if dt1.naive_utc() < dt2.naive_utc() {
71+
return dt1;
72+
} else {
73+
return dt2;
74+
}
75+
}
76+
}
77+
}
78+
79+
panic!(
80+
"Unable to calculate start time for date {} and time zone {:?}",
81+
date, tz
82+
)
83+
}

risuto-api/src/query.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ impl TimeQuery {
4242
.map(|d| chrono::naive::Days::new(d as u64))
4343
.and_then(|offset| date.checked_sub_days(offset)),
4444
};
45-
date.and_then(|d| d.and_hms_opt(0, 0, 0))
46-
.and_then(|d| d.and_local_timezone(*timezone).single())
45+
date.map(|d| crate::midnight_on(d, timezone))
4746
.map(|d| d.with_timezone(&chrono::Utc))
4847
.ok_or(Error::IntegerOutOfRange(*day_offset))
4948
}

risuto-client/src/query.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
};
77

88
use pest::{iterators::Pairs, pratt_parser::PrattParser, Parser as PestParser};
9-
use risuto_api::Error;
9+
use risuto_api::{midnight_on, Error};
1010

1111
pub trait QueryExt {
1212
fn from_search(db: &DbDump, tz: &chrono_tz::Tz, search: &str) -> Query;
@@ -292,13 +292,12 @@ fn parse_date_cmp(
292292
let timequery = match timequery.as_rule() {
293293
Rule::abstimeq => TimeQuery::Absolute(
294294
// TODO: for safety, see (currently open) https://github.com/chronotope/chrono/pull/927
295-
chrono::NaiveDate::parse_from_str(timequery.as_str(), "%Y-%m-%d")
296-
.expect("parsing date cmp with ill-formed absolute date")
297-
.and_hms_opt(0, 0, 0)
298-
.expect("failed adding hms 000 to date")
299-
.and_local_timezone(tz.clone())
300-
.unwrap()
301-
.with_timezone(&chrono::Utc),
295+
midnight_on(
296+
chrono::NaiveDate::parse_from_str(timequery.as_str(), "%Y-%m-%d")
297+
.expect("parsing date cmp with ill-formed absolute date"),
298+
tz,
299+
)
300+
.with_timezone(&chrono::Utc),
302301
),
303302
Rule::reltimeq => {
304303
let mut reader = timequery.into_inner();
@@ -341,7 +340,10 @@ fn parse_date_cmp(
341340
}
342341
}
343342

344-
fn start_of_next_day(tz: &impl chrono::TimeZone, day: TimeQuery) -> TimeQuery {
343+
fn start_of_next_day<Tz>(tz: &Tz, day: TimeQuery) -> TimeQuery
344+
where
345+
Tz: Clone + std::fmt::Debug + chrono::TimeZone,
346+
{
345347
match day {
346348
TimeQuery::DayRelative {
347349
timezone,
@@ -351,15 +353,13 @@ fn start_of_next_day(tz: &impl chrono::TimeZone, day: TimeQuery) -> TimeQuery {
351353
day_offset: day_offset + 1,
352354
},
353355
TimeQuery::Absolute(t) => TimeQuery::Absolute(
354-
// TODO: for safety, see (currently open) https://github.com/chronotope/chrono/pull/927
355-
t.date_naive()
356-
.succ_opt()
357-
.expect("failed figuring out a date for day+1")
358-
.and_hms_opt(0, 0, 0)
359-
.expect("failed setting hms to 000")
360-
.and_local_timezone(tz.clone())
361-
.unwrap()
362-
.with_timezone(&chrono::Utc),
356+
midnight_on(
357+
t.date_naive()
358+
.succ_opt()
359+
.expect("failed figuring out a date for day+1"),
360+
tz,
361+
)
362+
.with_timezone(&chrono::Utc),
363363
),
364364
}
365365
}

risuto-server/src/query.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use risuto_api::{Query, Time, TimeQuery, Uuid};
1+
use risuto_api::{midnight_on, Query, Time, TimeQuery, Uuid};
22

33
use crate::error::Error;
44

@@ -129,11 +129,7 @@ fn timeq_to_bind(q: &TimeQuery) -> Result<Bind, Error> {
129129
.checked_sub_days(chrono::naive::Days::new((-day_offset) as u64))
130130
.ok_or_else(|| Error::integer_out_of_range(*day_offset))?,
131131
};
132-
date.and_hms_opt(0, 0, 0)
133-
.expect("naive_date and hms 000 failed")
134-
.and_local_timezone(timezone.clone())
135-
.unwrap()
136-
.with_timezone(&chrono::Utc)
132+
midnight_on(date, timezone).with_timezone(&chrono::Utc)
137133
}
138134
}))
139135
}

risuto-web/src/ui/task_list_item.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -237,15 +237,10 @@ fn timeset_button(p: &TimesetButtonProps) -> Html {
237237
let timeset_label = current_date
238238
.and_then(|d| {
239239
let remaining = d.signed_duration_since(chrono::Utc::now());
240-
// TODO: for safety, see (currently open) https://github.com/chronotope/chrono/pull/927
241-
let since_beginning_of_day = d.signed_duration_since(
242-
chrono::Utc::now()
243-
.date_naive()
244-
.and_hms_opt(0, 0, 0)
245-
.expect("failed figuring out the start of day")
246-
.and_local_timezone(util::local_tz())
247-
.unwrap(),
248-
);
240+
let since_beginning_of_day = d.signed_duration_since(midnight_on(
241+
chrono::Utc::now().date_naive(),
242+
util::local_tz(),
243+
));
249244
match remaining {
250245
r if r > chrono::Duration::days(365) => Some(format!("{}", d.year())),
251246
r if r > chrono::Duration::days(1) => Some(format!("{}/{}", d.month(), d.day())),

0 commit comments

Comments
 (0)