#[cfg(any(feature = "alloc", feature = "std", test))]
use core::borrow::Borrow;
use core::{str, fmt, hash};
use core::ops::{Add, Sub, AddAssign, SubAssign};
use oldtime::Duration as OldDuration;
use Timelike;
use div::div_mod_floor;
use format::{Item, Numeric, Pad, Fixed};
use format::{parse, Parsed, ParseError, ParseResult, StrftimeItems};
#[cfg(any(feature = "alloc", feature = "std", test))]
use format::DelayedFormat;
#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
pub struct NaiveTime {
secs: u32,
frac: u32,
}
impl NaiveTime {
#[inline]
pub fn from_hms(hour: u32, min: u32, sec: u32) -> NaiveTime {
NaiveTime::from_hms_opt(hour, min, sec).expect("invalid time")
}
#[inline]
pub fn from_hms_opt(hour: u32, min: u32, sec: u32) -> Option<NaiveTime> {
NaiveTime::from_hms_nano_opt(hour, min, sec, 0)
}
#[inline]
pub fn from_hms_milli(hour: u32, min: u32, sec: u32, milli: u32) -> NaiveTime {
NaiveTime::from_hms_milli_opt(hour, min, sec, milli).expect("invalid time")
}
#[inline]
pub fn from_hms_milli_opt(hour: u32, min: u32, sec: u32, milli: u32) -> Option<NaiveTime> {
milli.checked_mul(1_000_000)
.and_then(|nano| NaiveTime::from_hms_nano_opt(hour, min, sec, nano))
}
#[inline]
pub fn from_hms_micro(hour: u32, min: u32, sec: u32, micro: u32) -> NaiveTime {
NaiveTime::from_hms_micro_opt(hour, min, sec, micro).expect("invalid time")
}
#[inline]
pub fn from_hms_micro_opt(hour: u32, min: u32, sec: u32, micro: u32) -> Option<NaiveTime> {
micro.checked_mul(1_000)
.and_then(|nano| NaiveTime::from_hms_nano_opt(hour, min, sec, nano))
}
#[inline]
pub fn from_hms_nano(hour: u32, min: u32, sec: u32, nano: u32) -> NaiveTime {
NaiveTime::from_hms_nano_opt(hour, min, sec, nano).expect("invalid time")
}
#[inline]
pub fn from_hms_nano_opt(hour: u32, min: u32, sec: u32, nano: u32) -> Option<NaiveTime> {
if hour >= 24 || min >= 60 || sec >= 60 || nano >= 2_000_000_000 { return None; }
let secs = hour * 3600 + min * 60 + sec;
Some(NaiveTime { secs: secs, frac: nano })
}
#[inline]
pub fn from_num_seconds_from_midnight(secs: u32, nano: u32) -> NaiveTime {
NaiveTime::from_num_seconds_from_midnight_opt(secs, nano).expect("invalid time")
}
#[inline]
pub fn from_num_seconds_from_midnight_opt(secs: u32, nano: u32) -> Option<NaiveTime> {
if secs >= 86_400 || nano >= 2_000_000_000 { return None; }
Some(NaiveTime { secs: secs, frac: nano })
}
pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult<NaiveTime> {
let mut parsed = Parsed::new();
parse(&mut parsed, s, StrftimeItems::new(fmt))?;
parsed.to_naive_time()
}
#[cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity))]
pub fn overflowing_add_signed(&self, mut rhs: OldDuration) -> (NaiveTime, i64) {
let mut secs = self.secs;
let mut frac = self.frac;
if frac >= 1_000_000_000 {
let rfrac = 2_000_000_000 - frac;
if rhs >= OldDuration::nanoseconds(i64::from(rfrac)) {
rhs = rhs - OldDuration::nanoseconds(i64::from(rfrac));
secs += 1;
frac = 0;
} else if rhs < OldDuration::nanoseconds(-i64::from(frac)) {
rhs = rhs + OldDuration::nanoseconds(i64::from(frac));
frac = 0;
} else {
frac = (i64::from(frac) + rhs.num_nanoseconds().unwrap()) as u32;
debug_assert!(frac < 2_000_000_000);
return (NaiveTime { secs: secs, frac: frac }, 0);
}
}
debug_assert!(secs <= 86_400);
debug_assert!(frac < 1_000_000_000);
let rhssecs = rhs.num_seconds();
let rhsfrac = (rhs - OldDuration::seconds(rhssecs)).num_nanoseconds().unwrap();
debug_assert_eq!(OldDuration::seconds(rhssecs) + OldDuration::nanoseconds(rhsfrac), rhs);
let rhssecsinday = rhssecs % 86_400;
let mut morerhssecs = rhssecs - rhssecsinday;
let rhssecs = rhssecsinday as i32;
let rhsfrac = rhsfrac as i32;
debug_assert!(-86_400 < rhssecs && rhssecs < 86_400);
debug_assert_eq!(morerhssecs % 86_400, 0);
debug_assert!(-1_000_000_000 < rhsfrac && rhsfrac < 1_000_000_000);
let mut secs = secs as i32 + rhssecs;
let mut frac = frac as i32 + rhsfrac;
debug_assert!(-86_400 < secs && secs < 2 * 86_400);
debug_assert!(-1_000_000_000 < frac && frac < 2_000_000_000);
if frac < 0 {
frac += 1_000_000_000;
secs -= 1;
} else if frac >= 1_000_000_000 {
frac -= 1_000_000_000;
secs += 1;
}
debug_assert!(-86_400 <= secs && secs < 2 * 86_400);
debug_assert!(0 <= frac && frac < 1_000_000_000);
if secs < 0 {
secs += 86_400;
morerhssecs -= 86_400;
} else if secs >= 86_400 {
secs -= 86_400;
morerhssecs += 86_400;
}
debug_assert!(0 <= secs && secs < 86_400);
(NaiveTime { secs: secs as u32, frac: frac as u32 }, morerhssecs)
}
#[inline]
pub fn overflowing_sub_signed(&self, rhs: OldDuration) -> (NaiveTime, i64) {
let (time, rhs) = self.overflowing_add_signed(-rhs);
(time, -rhs) }
pub fn signed_duration_since(self, rhs: NaiveTime) -> OldDuration {
use core::cmp::Ordering;
let secs = i64::from(self.secs) - i64::from(rhs.secs);
let frac = i64::from(self.frac) - i64::from(rhs.frac);
let adjust = match self.secs.cmp(&rhs.secs) {
Ordering::Greater => if rhs.frac >= 1_000_000_000 { 1 } else { 0 },
Ordering::Equal => 0,
Ordering::Less => if self.frac >= 1_000_000_000 { -1 } else { 0 },
};
OldDuration::seconds(secs + adjust) + OldDuration::nanoseconds(frac)
}
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline]
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
where I: Iterator<Item=B> + Clone, B: Borrow<Item<'a>> {
DelayedFormat::new(None, Some(*self), items)
}
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt))
}
fn hms(&self) -> (u32, u32, u32) {
let (mins, sec) = div_mod_floor(self.secs, 60);
let (hour, min) = div_mod_floor(mins, 60);
(hour, min, sec)
}
}
impl Timelike for NaiveTime {
#[inline]
fn hour(&self) -> u32 {
self.hms().0
}
#[inline]
fn minute(&self) -> u32 {
self.hms().1
}
#[inline]
fn second(&self) -> u32 {
self.hms().2
}
#[inline]
fn nanosecond(&self) -> u32 {
self.frac
}
#[inline]
fn with_hour(&self, hour: u32) -> Option<NaiveTime> {
if hour >= 24 { return None; }
let secs = hour * 3600 + self.secs % 3600;
Some(NaiveTime { secs: secs, ..*self })
}
#[inline]
fn with_minute(&self, min: u32) -> Option<NaiveTime> {
if min >= 60 { return None; }
let secs = self.secs / 3600 * 3600 + min * 60 + self.secs % 60;
Some(NaiveTime { secs: secs, ..*self })
}
#[inline]
fn with_second(&self, sec: u32) -> Option<NaiveTime> {
if sec >= 60 { return None; }
let secs = self.secs / 60 * 60 + sec;
Some(NaiveTime { secs: secs, ..*self })
}
#[inline]
fn with_nanosecond(&self, nano: u32) -> Option<NaiveTime> {
if nano >= 2_000_000_000 { return None; }
Some(NaiveTime { frac: nano, ..*self })
}
#[inline]
fn num_seconds_from_midnight(&self) -> u32 {
self.secs }
}
#[cfg_attr(feature = "cargo-clippy", allow(derive_hash_xor_eq))]
impl hash::Hash for NaiveTime {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.secs.hash(state);
self.frac.hash(state);
}
}
impl Add<OldDuration> for NaiveTime {
type Output = NaiveTime;
#[inline]
fn add(self, rhs: OldDuration) -> NaiveTime {
self.overflowing_add_signed(rhs).0
}
}
impl AddAssign<OldDuration> for NaiveTime {
#[inline]
fn add_assign(&mut self, rhs: OldDuration) {
*self = self.add(rhs);
}
}
impl Sub<OldDuration> for NaiveTime {
type Output = NaiveTime;
#[inline]
fn sub(self, rhs: OldDuration) -> NaiveTime {
self.overflowing_sub_signed(rhs).0
}
}
impl SubAssign<OldDuration> for NaiveTime {
#[inline]
fn sub_assign(&mut self, rhs: OldDuration) {
*self = self.sub(rhs);
}
}
impl Sub<NaiveTime> for NaiveTime {
type Output = OldDuration;
#[inline]
fn sub(self, rhs: NaiveTime) -> OldDuration {
self.signed_duration_since(rhs)
}
}
impl fmt::Debug for NaiveTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (hour, min, sec) = self.hms();
let (sec, nano) = if self.frac >= 1_000_000_000 {
(sec + 1, self.frac - 1_000_000_000)
} else {
(sec, self.frac)
};
write!(f, "{:02}:{:02}:{:02}", hour, min, sec)?;
if nano == 0 {
Ok(())
} else if nano % 1_000_000 == 0 {
write!(f, ".{:03}", nano / 1_000_000)
} else if nano % 1_000 == 0 {
write!(f, ".{:06}", nano / 1_000)
} else {
write!(f, ".{:09}", nano)
}
}
}
impl fmt::Display for NaiveTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self, f) }
}
impl str::FromStr for NaiveTime {
type Err = ParseError;
fn from_str(s: &str) -> ParseResult<NaiveTime> {
const ITEMS: &'static [Item<'static>] = &[
Item::Numeric(Numeric::Hour, Pad::Zero),
Item::Space(""), Item::Literal(":"),
Item::Numeric(Numeric::Minute, Pad::Zero),
Item::Space(""), Item::Literal(":"),
Item::Numeric(Numeric::Second, Pad::Zero),
Item::Fixed(Fixed::Nanosecond), Item::Space(""),
];
let mut parsed = Parsed::new();
parse(&mut parsed, s, ITEMS.iter())?;
parsed.to_naive_time()
}
}
#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
fn test_encodable_json<F, E>(to_string: F)
where F: Fn(&NaiveTime) -> Result<String, E>, E: ::std::fmt::Debug
{
assert_eq!(to_string(&NaiveTime::from_hms(0, 0, 0)).ok(),
Some(r#""00:00:00""#.into()));
assert_eq!(to_string(&NaiveTime::from_hms_milli(0, 0, 0, 950)).ok(),
Some(r#""00:00:00.950""#.into()));
assert_eq!(to_string(&NaiveTime::from_hms_milli(0, 0, 59, 1_000)).ok(),
Some(r#""00:00:60""#.into()));
assert_eq!(to_string(&NaiveTime::from_hms(0, 1, 2)).ok(),
Some(r#""00:01:02""#.into()));
assert_eq!(to_string(&NaiveTime::from_hms_nano(3, 5, 7, 98765432)).ok(),
Some(r#""03:05:07.098765432""#.into()));
assert_eq!(to_string(&NaiveTime::from_hms(7, 8, 9)).ok(),
Some(r#""07:08:09""#.into()));
assert_eq!(to_string(&NaiveTime::from_hms_micro(12, 34, 56, 789)).ok(),
Some(r#""12:34:56.000789""#.into()));
assert_eq!(to_string(&NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999)).ok(),
Some(r#""23:59:60.999999999""#.into()));
}
#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
fn test_decodable_json<F, E>(from_str: F)
where F: Fn(&str) -> Result<NaiveTime, E>, E: ::std::fmt::Debug
{
assert_eq!(from_str(r#""00:00:00""#).ok(),
Some(NaiveTime::from_hms(0, 0, 0)));
assert_eq!(from_str(r#""0:0:0""#).ok(),
Some(NaiveTime::from_hms(0, 0, 0)));
assert_eq!(from_str(r#""00:00:00.950""#).ok(),
Some(NaiveTime::from_hms_milli(0, 0, 0, 950)));
assert_eq!(from_str(r#""0:0:0.95""#).ok(),
Some(NaiveTime::from_hms_milli(0, 0, 0, 950)));
assert_eq!(from_str(r#""00:00:60""#).ok(),
Some(NaiveTime::from_hms_milli(0, 0, 59, 1_000)));
assert_eq!(from_str(r#""00:01:02""#).ok(),
Some(NaiveTime::from_hms(0, 1, 2)));
assert_eq!(from_str(r#""03:05:07.098765432""#).ok(),
Some(NaiveTime::from_hms_nano(3, 5, 7, 98765432)));
assert_eq!(from_str(r#""07:08:09""#).ok(),
Some(NaiveTime::from_hms(7, 8, 9)));
assert_eq!(from_str(r#""12:34:56.000789""#).ok(),
Some(NaiveTime::from_hms_micro(12, 34, 56, 789)));
assert_eq!(from_str(r#""23:59:60.999999999""#).ok(),
Some(NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999)));
assert_eq!(from_str(r#""23:59:60.9999999999997""#).ok(), Some(NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999)));
assert!(from_str(r#""""#).is_err());
assert!(from_str(r#""000000""#).is_err());
assert!(from_str(r#""00:00:61""#).is_err());
assert!(from_str(r#""00:60:00""#).is_err());
assert!(from_str(r#""24:00:00""#).is_err());
assert!(from_str(r#""23:59:59,1""#).is_err());
assert!(from_str(r#""012:34:56""#).is_err());
assert!(from_str(r#""hh:mm:ss""#).is_err());
assert!(from_str(r#"0"#).is_err());
assert!(from_str(r#"86399"#).is_err());
assert!(from_str(r#"{}"#).is_err());
assert!(from_str(r#"{"secs":0,"frac":0}"#).is_err());
assert!(from_str(r#"null"#).is_err());
}
#[cfg(feature = "rustc-serialize")]
mod rustc_serialize {
use super::NaiveTime;
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
impl Encodable for NaiveTime {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
format!("{:?}", self).encode(s)
}
}
impl Decodable for NaiveTime {
fn decode<D: Decoder>(d: &mut D) -> Result<NaiveTime, D::Error> {
d.read_str()?.parse().map_err(|_| d.error("invalid time"))
}
}
#[cfg(test)] use rustc_serialize::json;
#[test]
fn test_encodable() {
super::test_encodable_json(json::encode);
}
#[test]
fn test_decodable() {
super::test_decodable_json(json::decode);
}
}
#[cfg(feature = "serde")]
mod serde {
use core::fmt;
use super::NaiveTime;
use serdelib::{ser, de};
impl ser::Serialize for NaiveTime {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: ser::Serializer
{
serializer.collect_str(&self)
}
}
struct NaiveTimeVisitor;
impl<'de> de::Visitor<'de> for NaiveTimeVisitor {
type Value = NaiveTime;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result
{
write!(formatter, "a formatted time string")
}
fn visit_str<E>(self, value: &str) -> Result<NaiveTime, E>
where E: de::Error
{
value.parse().map_err(E::custom)
}
}
impl<'de> de::Deserialize<'de> for NaiveTime {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: de::Deserializer<'de>
{
deserializer.deserialize_str(NaiveTimeVisitor)
}
}
#[cfg(test)] extern crate serde_json;
#[cfg(test)] extern crate bincode;
#[test]
fn test_serde_serialize() {
super::test_encodable_json(self::serde_json::to_string);
}
#[test]
fn test_serde_deserialize() {
super::test_decodable_json(|input| self::serde_json::from_str(&input));
}
#[test]
fn test_serde_bincode() {
use self::bincode::{Infinite, serialize, deserialize};
let t = NaiveTime::from_hms_nano(3, 5, 7, 98765432);
let encoded = serialize(&t, Infinite).unwrap();
let decoded: NaiveTime = deserialize(&encoded).unwrap();
assert_eq!(t, decoded);
}
}
#[cfg(test)]
mod tests {
use super::NaiveTime;
use Timelike;
use std::u32;
use oldtime::Duration;
#[test]
fn test_time_from_hms_milli() {
assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 0),
Some(NaiveTime::from_hms_nano(3, 5, 7, 0)));
assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 777),
Some(NaiveTime::from_hms_nano(3, 5, 7, 777_000_000)));
assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 1_999),
Some(NaiveTime::from_hms_nano(3, 5, 7, 1_999_000_000)));
assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 2_000), None);
assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 5_000), None); assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, u32::MAX), None);
}
#[test]
fn test_time_from_hms_micro() {
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 0),
Some(NaiveTime::from_hms_nano(3, 5, 7, 0)));
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 333),
Some(NaiveTime::from_hms_nano(3, 5, 7, 333_000)));
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 777_777),
Some(NaiveTime::from_hms_nano(3, 5, 7, 777_777_000)));
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 1_999_999),
Some(NaiveTime::from_hms_nano(3, 5, 7, 1_999_999_000)));
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 2_000_000), None);
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 5_000_000), None); assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, u32::MAX), None);
}
#[test]
fn test_time_hms() {
assert_eq!(NaiveTime::from_hms(3, 5, 7).hour(), 3);
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(0),
Some(NaiveTime::from_hms(0, 5, 7)));
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(23),
Some(NaiveTime::from_hms(23, 5, 7)));
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(24), None);
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(u32::MAX), None);
assert_eq!(NaiveTime::from_hms(3, 5, 7).minute(), 5);
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(0),
Some(NaiveTime::from_hms(3, 0, 7)));
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(59),
Some(NaiveTime::from_hms(3, 59, 7)));
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(60), None);
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(u32::MAX), None);
assert_eq!(NaiveTime::from_hms(3, 5, 7).second(), 7);
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(0),
Some(NaiveTime::from_hms(3, 5, 0)));
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(59),
Some(NaiveTime::from_hms(3, 5, 59)));
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(60), None);
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(u32::MAX), None);
}
#[test]
fn test_time_add() {
macro_rules! check {
($lhs:expr, $rhs:expr, $sum:expr) => ({
assert_eq!($lhs + $rhs, $sum);
})
}
let hmsm = |h,m,s,mi| NaiveTime::from_hms_milli(h, m, s, mi);
check!(hmsm(3, 5, 7, 900), Duration::zero(), hmsm(3, 5, 7, 900));
check!(hmsm(3, 5, 7, 900), Duration::milliseconds(100), hmsm(3, 5, 8, 0));
check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(-1800), hmsm(3, 5, 6, 500));
check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(-800), hmsm(3, 5, 7, 500));
check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(-100), hmsm(3, 5, 7, 1_200));
check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(100), hmsm(3, 5, 7, 1_400));
check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(800), hmsm(3, 5, 8, 100));
check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(1800), hmsm(3, 5, 9, 100));
check!(hmsm(3, 5, 7, 900), Duration::seconds(86399), hmsm(3, 5, 6, 900)); check!(hmsm(3, 5, 7, 900), Duration::seconds(-86399), hmsm(3, 5, 8, 900));
check!(hmsm(3, 5, 7, 900), Duration::days(12345), hmsm(3, 5, 7, 900));
check!(hmsm(3, 5, 7, 1_300), Duration::days(1), hmsm(3, 5, 7, 300));
check!(hmsm(3, 5, 7, 1_300), Duration::days(-1), hmsm(3, 5, 8, 300));
check!(hmsm(0, 0, 0, 0), Duration::milliseconds(-990), hmsm(23, 59, 59, 10));
check!(hmsm(0, 0, 0, 0), Duration::milliseconds(-9990), hmsm(23, 59, 50, 10));
}
#[test]
fn test_time_overflowing_add() {
let hmsm = NaiveTime::from_hms_milli;
assert_eq!(hmsm(3, 4, 5, 678).overflowing_add_signed(Duration::hours(11)),
(hmsm(14, 4, 5, 678), 0));
assert_eq!(hmsm(3, 4, 5, 678).overflowing_add_signed(Duration::hours(23)),
(hmsm(2, 4, 5, 678), 86_400));
assert_eq!(hmsm(3, 4, 5, 678).overflowing_add_signed(Duration::hours(-7)),
(hmsm(20, 4, 5, 678), -86_400));
assert_eq!(hmsm(3, 4, 5, 1_678).overflowing_add_signed(Duration::days(1)),
(hmsm(3, 4, 5, 678), 86_400));
assert_eq!(hmsm(3, 4, 5, 1_678).overflowing_add_signed(Duration::days(-1)),
(hmsm(3, 4, 6, 678), -86_400));
}
#[test]
fn test_time_addassignment() {
let hms = NaiveTime::from_hms;
let mut time = hms(12, 12, 12);
time += Duration::hours(10);
assert_eq!(time, hms(22, 12, 12));
time += Duration::hours(10);
assert_eq!(time, hms(8, 12, 12));
}
#[test]
fn test_time_subassignment() {
let hms = NaiveTime::from_hms;
let mut time = hms(12, 12, 12);
time -= Duration::hours(10);
assert_eq!(time, hms(2, 12, 12));
time -= Duration::hours(10);
assert_eq!(time, hms(16, 12, 12));
}
#[test]
fn test_time_sub() {
macro_rules! check {
($lhs:expr, $rhs:expr, $diff:expr) => ({
assert_eq!($lhs.signed_duration_since($rhs), $diff);
assert_eq!($rhs.signed_duration_since($lhs), -$diff);
})
}
let hmsm = |h,m,s,mi| NaiveTime::from_hms_milli(h, m, s, mi);
check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 900), Duration::zero());
check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 600), Duration::milliseconds(300));
check!(hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 200), Duration::seconds(3600 + 60 + 1));
check!(hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 300),
Duration::seconds(3600 + 60) + Duration::milliseconds(900));
check!(hmsm(3, 5, 7, 200), hmsm(3, 5, 6, 1_800), Duration::milliseconds(400));
check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 1_800), Duration::milliseconds(1400));
check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 800), Duration::milliseconds(1400));
assert_eq!(hmsm(3, 5, 6, 800) + Duration::milliseconds(400), hmsm(3, 5, 7, 200));
assert_eq!(hmsm(3, 5, 6, 1_800) + Duration::milliseconds(400), hmsm(3, 5, 7, 200));
}
#[test]
fn test_time_fmt() {
assert_eq!(format!("{}", NaiveTime::from_hms_milli(23, 59, 59, 999)), "23:59:59.999");
assert_eq!(format!("{}", NaiveTime::from_hms_milli(23, 59, 59, 1_000)), "23:59:60");
assert_eq!(format!("{}", NaiveTime::from_hms_milli(23, 59, 59, 1_001)), "23:59:60.001");
assert_eq!(format!("{}", NaiveTime::from_hms_micro(0, 0, 0, 43210)), "00:00:00.043210");
assert_eq!(format!("{}", NaiveTime::from_hms_nano(0, 0, 0, 6543210)), "00:00:00.006543210");
assert_eq!(format!("{:30}", NaiveTime::from_hms_milli(3, 5, 7, 9)), "03:05:07.009");
}
#[test]
fn test_date_from_str() {
let valid = [
"0:0:0",
"0:0:0.0000000",
"0:0:0.0000003",
" 4 : 3 : 2.1 ",
" 09:08:07 ",
" 9:8:07 ",
"23:59:60.373929310237",
];
for &s in &valid {
let d = match s.parse::<NaiveTime>() {
Ok(d) => d,
Err(e) => panic!("parsing `{}` has failed: {}", s, e)
};
let s_ = format!("{:?}", d);
let d_ = match s_.parse::<NaiveTime>() {
Ok(d) => d,
Err(e) => panic!("`{}` is parsed into `{:?}`, but reparsing that has failed: {}",
s, d, e)
};
assert!(d == d_, "`{}` is parsed into `{:?}`, but reparsed result \
`{:?}` does not match", s, d, d_);
}
assert!("".parse::<NaiveTime>().is_err());
assert!("x".parse::<NaiveTime>().is_err());
assert!("15".parse::<NaiveTime>().is_err());
assert!("15:8".parse::<NaiveTime>().is_err());
assert!("15:8:x".parse::<NaiveTime>().is_err());
assert!("15:8:9x".parse::<NaiveTime>().is_err());
assert!("23:59:61".parse::<NaiveTime>().is_err());
assert!("12:34:56.x".parse::<NaiveTime>().is_err());
assert!("12:34:56. 0".parse::<NaiveTime>().is_err());
}
#[test]
fn test_time_parse_from_str() {
let hms = |h,m,s| NaiveTime::from_hms(h,m,s);
assert_eq!(NaiveTime::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
Ok(hms(12, 34, 56))); assert_eq!(NaiveTime::parse_from_str("PM 12:59", "%P %H:%M"),
Ok(hms(12, 59, 0)));
assert!(NaiveTime::parse_from_str("12:3456", "%H:%M:%S").is_err());
}
#[test]
fn test_time_format() {
let t = NaiveTime::from_hms_nano(3, 5, 7, 98765432);
assert_eq!(t.format("%H,%k,%I,%l,%P,%p").to_string(), "03, 3,03, 3,am,AM");
assert_eq!(t.format("%M").to_string(), "05");
assert_eq!(t.format("%S,%f,%.f").to_string(), "07,098765432,.098765432");
assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".098,.098765,.098765432");
assert_eq!(t.format("%R").to_string(), "03:05");
assert_eq!(t.format("%T,%X").to_string(), "03:05:07,03:05:07");
assert_eq!(t.format("%r").to_string(), "03:05:07 AM");
assert_eq!(t.format("%t%n%%%n%t").to_string(), "\t\n%\n\t");
let t = NaiveTime::from_hms_micro(3, 5, 7, 432100);
assert_eq!(t.format("%S,%f,%.f").to_string(), "07,432100000,.432100");
assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".432,.432100,.432100000");
let t = NaiveTime::from_hms_milli(3, 5, 7, 210);
assert_eq!(t.format("%S,%f,%.f").to_string(), "07,210000000,.210");
assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".210,.210000,.210000000");
let t = NaiveTime::from_hms(3, 5, 7);
assert_eq!(t.format("%S,%f,%.f").to_string(), "07,000000000,");
assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".000,.000000,.000000000");
assert_eq!(NaiveTime::from_hms(13, 57, 9).format("%r").to_string(), "01:57:09 PM");
assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 1_000).format("%X").to_string(),
"23:59:60");
}
}