Skip to content

Commit 72f1c79

Browse files
authored
raise DateNotExact error for millisecond timestamps (#67)
* raise `DateNotExact` error for millisecond timestamps * adjust variable names
1 parent 9bbeebb commit 72f1c79

File tree

3 files changed

+18
-13
lines changed

3 files changed

+18
-13
lines changed

src/date.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -206,13 +206,10 @@ impl Date {
206206
/// assert_eq!(d.to_string(), "2022-06-07");
207207
/// ```
208208
pub fn from_timestamp(timestamp: i64, require_exact: bool) -> Result<Self, ParseError> {
209-
let (timestamp_second, _) = Self::timestamp_watershed(timestamp)?;
210-
let d = Self::from_timestamp_calc(timestamp_second)?;
211-
if require_exact {
212-
let time_second = timestamp_second.rem_euclid(86_400);
213-
if time_second != 0 {
214-
return Err(ParseError::DateNotExact);
215-
}
209+
let (seconds, microseconds) = Self::timestamp_watershed(timestamp)?;
210+
let (d, remaining_seconds) = Self::from_timestamp_calc(seconds)?;
211+
if require_exact && (remaining_seconds != 0 || microseconds != 0) {
212+
return Err(ParseError::DateNotExact);
216213
}
217214
Ok(d)
218215
}
@@ -287,7 +284,7 @@ impl Date {
287284
Ok((seconds, microseconds as u32))
288285
}
289286

290-
pub(crate) fn from_timestamp_calc(timestamp_second: i64) -> Result<Self, ParseError> {
287+
pub(crate) fn from_timestamp_calc(timestamp_second: i64) -> Result<(Self, u32), ParseError> {
291288
if timestamp_second < UNIX_1600 {
292289
return Err(ParseError::DateTooSmall);
293290
}
@@ -312,7 +309,7 @@ impl Date {
312309
true => leap_year_month_day(ordinal_day),
313310
false => common_year_month_day(ordinal_day),
314311
};
315-
Ok(Self { year, month, day })
312+
Ok((Self { year, month, day }, (timestamp_second.rem_euclid(86_400)) as u32))
316313
}
317314

318315
/// Parse a date from bytes, no check is performed for extract characters at the end of the string

src/datetime.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -400,9 +400,7 @@ impl DateTime {
400400
.ok_or(ParseError::TimeTooLarge)?;
401401
total_microsecond %= 1_000_000;
402402
}
403-
let date = Date::from_timestamp_calc(second)?;
404-
// rem_euclid since if `timestamp_second = -100`, we want `time_second = 86300` (e.g. `86400 - 100`)
405-
let time_second = second.rem_euclid(86_400) as u32;
403+
let (date, time_second) = Date::from_timestamp_calc(second)?;
406404
Ok(Self {
407405
date,
408406
time: Time::from_timestamp_with_config(time_second, total_microsecond, config)?,

tests/main.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ fn date_comparison() {
230230
}
231231

232232
#[test]
233-
fn date_timestamp() {
233+
fn date_timestamp_exact() {
234234
let d = Date::from_timestamp(1_654_560_000, true).unwrap();
235235
assert_eq!(d.to_string(), "2022-06-07");
236236
assert_eq!(d.timestamp(), 1_654_560_000);
@@ -239,6 +239,16 @@ fn date_timestamp() {
239239
Ok(d) => panic!("unexpectedly valid, {d}"),
240240
Err(e) => assert_eq!(e, ParseError::DateNotExact),
241241
}
242+
243+
// milliseconds
244+
let d = Date::from_timestamp(1_654_560_000_000, true).unwrap();
245+
assert_eq!(d.to_string(), "2022-06-07");
246+
assert_eq!(d.timestamp(), 1_654_560_000);
247+
248+
match Date::from_timestamp(1_654_560_000_001, true) {
249+
Ok(d) => panic!("unexpectedly valid, {d}"),
250+
Err(e) => assert_eq!(e, ParseError::DateNotExact),
251+
}
242252
}
243253

244254
macro_rules! date_from_timestamp {

0 commit comments

Comments
 (0)