Skip to content

Commit

Permalink
Add FromStr for FixedOffset (#1157)
Browse files Browse the repository at this point in the history
Co-authored-by: Yuxuan Shui <yshuiv7@gmail.com>
  • Loading branch information
mcronce and yshui committed Jun 29, 2023
1 parent ea9398e commit 1a3c43a
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 4 deletions.
4 changes: 2 additions & 2 deletions src/format/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ impl Error for ParseError {
}

// to be used in this module and submodules
const OUT_OF_RANGE: ParseError = ParseError(ParseErrorKind::OutOfRange);
pub(crate) const OUT_OF_RANGE: ParseError = ParseError(ParseErrorKind::OutOfRange);
const IMPOSSIBLE: ParseError = ParseError(ParseErrorKind::Impossible);
const NOT_ENOUGH: ParseError = ParseError(ParseErrorKind::NotEnough);
const INVALID: ParseError = ParseError(ParseErrorKind::Invalid);
Expand Down Expand Up @@ -838,7 +838,7 @@ mod parsed;

// due to the size of parsing routines, they are in separate modules.
mod parse;
mod scan;
pub(crate) mod scan;

pub mod strftime;

Expand Down
4 changes: 2 additions & 2 deletions src/format/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,15 +197,15 @@ pub(super) fn space(s: &str) -> ParseResult<&str> {
}

/// Consumes any number (including zero) of colon or spaces.
pub(super) fn colon_or_space(s: &str) -> ParseResult<&str> {
pub(crate) fn colon_or_space(s: &str) -> ParseResult<&str> {
Ok(s.trim_start_matches(|c: char| c == ':' || c.is_whitespace()))
}

/// Tries to parse `[-+]\d\d` continued by `\d\d`. Return an offset in seconds if possible.
///
/// The additional `colon` may be used to parse a mandatory or optional `:`
/// between hours and minutes, and should return either a new suffix or `Err` when parsing fails.
pub(super) fn timezone_offset<F>(s: &str, consume_colon: F) -> ParseResult<(&str, i32)>
pub(crate) fn timezone_offset<F>(s: &str, consume_colon: F) -> ParseResult<(&str, i32)>
where
F: FnMut(&str) -> ParseResult<&str>,
{
Expand Down
24 changes: 24 additions & 0 deletions src/offset/fixed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@

use core::fmt;
use core::ops::{Add, Sub};
use core::str::FromStr;

#[cfg(feature = "rkyv")]
use rkyv::{Archive, Deserialize, Serialize};

use super::{LocalResult, Offset, TimeZone};
use crate::format::scan;
use crate::format::OUT_OF_RANGE;
use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime};
use crate::oldtime::Duration as OldDuration;
use crate::DateTime;
use crate::ParseError;
use crate::Timelike;

/// The time zone with fixed offset, from UTC-23:59:59 to UTC+23:59:59.
Expand Down Expand Up @@ -113,6 +117,15 @@ impl FixedOffset {
}
}

/// Parsing a `str` into a `FixedOffset` uses the format [`%z`](crate::format::strftime).
impl FromStr for FixedOffset {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (_, offset) = scan::timezone_offset(s, scan::colon_or_space)?;
Self::east_opt(offset).ok_or(OUT_OF_RANGE)
}
}

impl TimeZone for FixedOffset {
type Offset = FixedOffset;

Expand Down Expand Up @@ -246,6 +259,7 @@ impl<Tz: TimeZone> Sub<FixedOffset> for DateTime<Tz> {
mod tests {
use super::FixedOffset;
use crate::offset::TimeZone;
use std::str::FromStr;

#[test]
fn test_date_extreme_offset() {
Expand Down Expand Up @@ -292,4 +306,14 @@ mod tests {
"2012-03-04T05:06:07-23:59:59".to_string()
);
}

#[test]
fn test_parse_offset() {
let offset = FixedOffset::from_str("-0500").unwrap();
assert_eq!(offset.local_minus_utc, -5 * 3600);
let offset = FixedOffset::from_str("-08:00").unwrap();
assert_eq!(offset.local_minus_utc, -8 * 3600);
let offset = FixedOffset::from_str("+06:30").unwrap();
assert_eq!(offset.local_minus_utc, (6 * 3600) + 1800);
}
}

0 comments on commit 1a3c43a

Please sign in to comment.