Unified · Split
| @@ -1,6 +1,8 @@ | ||
| 1 | 1 | #[derive(thiserror::Error, Debug)] |
| 2 | 2 | #[allow(missing_docs)] |
| 3 | 3 | pub enum Error { |
| 4 | + #[error("Cannot represent times before UNIX epoch at timestamp {timestamp}")] | |
| 5 | + TooEarly { timestamp: i64 }, | |
| 4 | 6 | #[error("Date string can not be parsed")] |
| 5 | 7 | InvalidDateString, |
| 6 | 8 | #[error("Dates past 2038 can not be represented.")] |
| @@ -44,12 +46,21 @@ pub(crate) mod function { · 37 unmodified lines | ||
| 44 | 46 | // Format::Raw |
| 45 | 47 | val |
| 46 | 48 | } else if let Some(time) = relative::parse(input, now).transpose()? { |
| 47 | − Time::new(time.unix_timestamp().try_into()?, time.offset().whole_seconds()) | |
| 49 | + Time::new(timestamp(time)?, time.offset().whole_seconds()) | |
| 48 | 50 | } else { |
| 49 | 51 | return Err(Error::InvalidDateString); |
| 50 | 52 | }) |
| 51 | 53 | } |
| 52 | 54 | |
| 55 | + fn timestamp(date: OffsetDateTime) -> Result<u32, Error> { | |
| 56 | + let timestamp = date.unix_timestamp(); | |
| 57 | + if timestamp < 0 { | |
| 58 | + Err(Error::TooEarly { timestamp }) | |
| 59 | + } else { | |
| 60 | + Ok(timestamp.try_into()?) | |
| 61 | + } | |
| 62 | + } | |
| 63 | + | |
| 53 | 64 | fn parse_raw(input: &str) -> Option<Time> { |
| 54 | 65 | let mut split = input.split_whitespace(); |
| 55 | 66 | let seconds_since_unix_epoch: u32 = split.next()?.parse().ok()?; |
| @@ -89,6 +89,7 @@ fn invalid_dates_can_be_produced_without_current_time() { · 88 unmodified lines | ||
| 89 | 89 | } |
| 90 | 90 | |
| 91 | 91 | mod relative { |
| 92 | + use git_date::parse::Error; | |
| 92 | 93 | use git_date::time::Sign; |
| 93 | 94 | use std::time::SystemTime; |
| 94 | 95 | use time::{Duration, OffsetDateTime}; |
| @@ -101,10 +102,16 @@ mod relative { · 6 unmodified lines | ||
| 101 | 102 | |
| 102 | 103 | #[test] |
| 103 | 104 | #[should_panic] // TODO: fix |
| 104 | − fn large_ffsets_can_panic_elsewhere() { | |
| 105 | + fn large_offsets_can_panic_elsewhere() { | |
| 105 | 106 | git_date::parse("9999999999 weeks ago", Some(std::time::UNIX_EPOCH)).ok(); |
| 106 | 107 | } |
| 107 | 108 | |
| 109 | + #[test] | |
| 110 | + fn offset_leading_to_before_unix_epoch_cannot_be_represented() { | |
| 111 | + let err = git_date::parse("1 second ago", Some(std::time::UNIX_EPOCH)).unwrap_err(); | |
| 112 | + assert!(matches!(err, Error::TooEarly{timestamp} if timestamp == -1)); | |
| 113 | + } | |
| 114 | + | |
| 108 | 115 | #[test] |
| 109 | 116 | fn various() { |
| 110 | 117 | let now = Some(SystemTime::now()); |