use std::io::Read;
#[cfg(feature = "use-serde")]
use serde::{Deserialize, Serialize};
use time::{format_description::well_known::Iso8601, OffsetDateTime, PrimitiveDateTime, UtcOffset};
use crate::errors::GpxResult;
use crate::parser::{string, Context};
#[derive(Debug, Clone, Copy, Eq, Ord, PartialOrd, PartialEq, Hash)]
#[cfg_attr(feature = "use-serde", derive(Serialize, Deserialize))]
pub struct Time(OffsetDateTime);
impl Time {
pub fn format(&self) -> GpxResult<String> {
self.0.format(&Iso8601::DEFAULT).map_err(From::from)
}
}
impl From<OffsetDateTime> for Time {
fn from(t: OffsetDateTime) -> Self {
Time(t)
}
}
impl From<Time> for OffsetDateTime {
fn from(t: Time) -> Self {
t.0
}
}
pub fn consume<R: Read>(context: &mut Context<R>) -> GpxResult<Time> {
let time_str = string::consume(context, "time", false)?;
let time = OffsetDateTime::parse(&time_str, &Iso8601::PARSING).or_else(|_| {
PrimitiveDateTime::parse(&time_str, &Iso8601::PARSING).map(PrimitiveDateTime::assume_utc)
})?;
Ok(time.to_offset(UtcOffset::UTC).into())
}
#[cfg(test)]
mod tests {
use crate::GpxVersion;
use super::consume;
#[test]
fn consume_time() {
let result = consume!("<time>1996-12-19T16:39:57-08:00</time>", GpxVersion::Gpx11);
assert!(result.is_ok());
let result = consume!("<time>2001-10-26T21:32:52</time>", GpxVersion::Gpx11);
assert!(result.is_ok());
let result = consume!("<time>2001-10-26T21:32:52+02:00</time>", GpxVersion::Gpx11);
assert!(result.is_ok());
let result = consume!("<time>2001-10-26T19:32:52Z</time>", GpxVersion::Gpx11);
assert!(result.is_ok());
let result = consume!("<time>2001-10-26T19:32:52+00:00</time>", GpxVersion::Gpx11);
assert!(result.is_ok());
let result = consume!("<time>2001-10-26T21:32:52.12679</time>", GpxVersion::Gpx11);
assert!(result.is_ok());
let result = consume!("<time>2001-10-26T21:32</time>", GpxVersion::Gpx11);
assert!(result.is_ok());
let result = consume!("<time>2001-10-26</time>", GpxVersion::Gpx11);
assert!(result.is_err());
let result = consume!("<time>2001-10-26T25:32:52+02:00</time>", GpxVersion::Gpx11);
assert!(result.is_err());
let result = consume!("<time>01-10-26T21:32</time>", GpxVersion::Gpx11);
assert!(result.is_err());
let result = consume!("<time>-2001-10-26T21:32:52</time>", GpxVersion::Gpx11);
assert!(result.is_err());
let result = consume!("<time>2021-10-10T09:55:20.952</time>", GpxVersion::Gpx11);
assert!(result.is_ok());
}
}