diff --git a/Cargo.toml b/Cargo.toml index 72b93ed..ca7635a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "chrono" -version = "0.1.12" +version = "0.1.13" authors = ["Kang Seonghoon "] description = "Date and time library for Rust" @@ -15,5 +15,5 @@ license = "MIT/Apache-2.0" name = "chrono" [dependencies] -time = "0.1.11" +time = "0.1.12" diff --git a/README.md b/README.md index 4f448a8..b5408d7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[Chrono][doc] 0.1.12 +[Chrono][doc] 0.1.13 ==================== [![Chrono on Travis CI][travis-image]][travis] @@ -115,17 +115,18 @@ assert_eq!(UTC.ymd(1970, 1, 1).and_hms(0, 0, 0) - Duration::seconds(1_000_000_00 Formatting is done via the `format` method, which format is equivalent to the familiar `strftime` format. -The default `to_string` method also gives a reasonable representation. +The default `to_string` method and `{:?}` specifier also give a reasonable representation. ~~~~ {.rust} use chrono::{UTC, Offset}; let dt = UTC.ymd(2014, 11, 28).and_hms(12, 0, 9); -assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2014-11-28 12:00:09".to_string()); -assert_eq!(dt.format("%a %b %e %T %Y").to_string(), "Fri Nov 28 12:00:09 2014".to_string()); +assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2014-11-28 12:00:09"); +assert_eq!(dt.format("%a %b %e %T %Y").to_string(), "Fri Nov 28 12:00:09 2014"); assert_eq!(dt.format("%a %b %e %T %Y").to_string(), dt.format("%c").to_string()); -assert_eq!(dt.to_string(), "2014-11-28T12:00:09Z".to_string()); +assert_eq!(dt.to_string(), "2014-11-28 12:00:09 UTC"); +assert_eq!(format!("{:?}", dt), "2014-11-28T12:00:09Z"); ~~~~ ### Individual date and time @@ -143,7 +144,7 @@ assert_eq!(Local::today(), Local::now().date()); assert_eq!(UTC.ymd(2014, 11, 28).weekday(), Weekday::Fri); assert_eq!(UTC.ymd_opt(2014, 11, 31), LocalResult::None); -assert_eq!(UTC.hms_milli(7, 8, 9, 10).format("%H%M%S").to_string(), "070809".to_string()); +assert_eq!(UTC.hms_milli(7, 8, 9, 10).format("%H%M%S").to_string(), "070809"); ~~~~ `DateTime` has two methods, `date` and `time`, diff --git a/src/date.rs b/src/date.rs index d409f0e..5b0c556 100644 --- a/src/date.rs +++ b/src/date.rs @@ -175,17 +175,19 @@ impl Date { Date::from_utc(self.date, offset) } + /// Returns a view to the local date. + fn local(&self) -> NaiveDate { + self.offset.to_local_date(&self.date) + } +} + +impl Date { /// Formats the date in the specified format string. /// See the `format` module on the supported escape sequences. #[inline] pub fn format<'a>(&'a self, fmt: &'a str) -> DelayedFormat<'a> { DelayedFormat::new_with_offset(Some(self.local()), None, &self.offset, fmt) } - - /// Returns a view to the local date. - fn local(&self) -> NaiveDate { - self.offset.to_local_date(&self.date) - } } impl Datelike for Date { @@ -259,8 +261,8 @@ impl Ord for Date { fn cmp(&self, other: &Date) -> Ordering { self.date.cmp(&other.date) } } -impl hash::Hash for Date { - fn hash(&self, state: &mut hash::sip::SipState) { self.date.hash(state) } +impl hash::Hash for Date { + fn hash(&self, state: &mut H) { self.date.hash(state) } } impl Add for Date { @@ -284,7 +286,13 @@ impl Sub for Date { fn sub(self, rhs: Duration) -> Date { self.add(-rhs) } } -impl fmt::Show for Date { +impl fmt::Show for Date { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}{:?}", self.local(), self.offset) + } +} + +impl fmt::String for Date { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}{}", self.local(), self.offset) } @@ -292,9 +300,7 @@ impl fmt::Show for Date { #[cfg(test)] mod tests { - use std::borrow::IntoCow; use std::fmt; - use std::string::CowString; use duration::Duration; use naive::date::NaiveDate; @@ -309,7 +315,6 @@ mod tests { struct UTC1y; // same to UTC but with an offset of 365 days impl Offset for UTC1y { - fn name(&self) -> CowString<'static> { "UTC+8760".into_cow() } // yes, no kidding fn local_minus_utc(&self) -> Duration { Duration::zero() } fn from_local_date(&self, local: &NaiveDate) -> LocalResult> { @@ -335,13 +340,13 @@ mod tests { #[test] fn test_date_weird_offset() { - assert_eq!(UTC1y.ymd(2012, 2, 29).to_string(), + assert_eq!(format!("{:?}", UTC1y.ymd(2012, 2, 29)), "2012-02-29+8760:00".to_string()); - assert_eq!(UTC1y.ymd(2012, 2, 29).and_hms(5, 6, 7).to_string(), + assert_eq!(format!("{:?}", UTC1y.ymd(2012, 2, 29).and_hms(5, 6, 7)), "2012-02-29T05:06:07+8760:00".to_string()); - assert_eq!(UTC1y.ymd(2012, 3, 4).to_string(), + assert_eq!(format!("{:?}", UTC1y.ymd(2012, 3, 4)), "2012-03-04+8760:00".to_string()); - assert_eq!(UTC1y.ymd(2012, 3, 4).and_hms(5, 6, 7).to_string(), + assert_eq!(format!("{:?}", UTC1y.ymd(2012, 3, 4).and_hms(5, 6, 7)), "2012-03-04T05:06:07+8760:00".to_string()); } } diff --git a/src/datetime.rs b/src/datetime.rs index 39fe12e..b2341f2 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -64,6 +64,13 @@ impl DateTime { DateTime::from_utc(self.datetime, offset) } + /// Returns a view to the local datetime. + fn local(&self) -> NaiveDateTime { + self.offset.to_local_datetime(&self.datetime) + } +} + +impl DateTime { /// Formats the combined date and time in the specified format string. /// See the `format` module on the supported escape sequences. #[inline] @@ -71,11 +78,6 @@ impl DateTime { let local = self.local(); DelayedFormat::new_with_offset(Some(local.date()), Some(local.time()), &self.offset, fmt) } - - /// Returns a view to the local datetime. - fn local(&self) -> NaiveDateTime { - self.offset.to_local_datetime(&self.datetime) - } } impl Datelike for DateTime { @@ -180,8 +182,8 @@ impl Ord for DateTime { fn cmp(&self, other: &DateTime) -> Ordering { self.datetime.cmp(&other.datetime) } } -impl hash::Hash for DateTime { - fn hash(&self, state: &mut hash::sip::SipState) { self.datetime.hash(state) } +impl hash::Hash for DateTime { + fn hash(&self, state: &mut H) { self.datetime.hash(state) } } impl Add for DateTime { @@ -205,9 +207,15 @@ impl Sub for DateTime { fn sub(self, rhs: Duration) -> DateTime { self.add(-rhs) } } -impl fmt::Show for DateTime { +impl fmt::Show for DateTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}{}", self.local(), self.offset) + write!(f, "{:?}{:?}", self.local(), self.offset) + } +} + +impl fmt::String for DateTime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} {}", self.local(), self.offset) } } @@ -222,10 +230,15 @@ mod tests { let EST = FixedOffset::east(5*60*60); let EDT = FixedOffset::east(4*60*60); - assert_eq!(UTC.ymd(2014, 5, 6).and_hms(7, 8, 9).to_string(), - "2014-05-06T07:08:09Z".to_string()); - assert_eq!(EDT.ymd(2014, 5, 6).and_hms(7, 8, 9).to_string(), - "2014-05-06T07:08:09+04:00".to_string()); + assert_eq!(format!("{}", UTC.ymd(2014, 5, 6).and_hms(7, 8, 9)), + "2014-05-06 07:08:09 UTC"); + assert_eq!(format!("{}", EDT.ymd(2014, 5, 6).and_hms(7, 8, 9)), + "2014-05-06 07:08:09 +04:00"); + assert_eq!(format!("{:?}", UTC.ymd(2014, 5, 6).and_hms(7, 8, 9)), + "2014-05-06T07:08:09Z"); + assert_eq!(format!("{:?}", EDT.ymd(2014, 5, 6).and_hms(7, 8, 9)), + "2014-05-06T07:08:09+04:00"); + assert_eq!(UTC.ymd(2014, 5, 6).and_hms(7, 8, 9), EDT.ymd(2014, 5, 6).and_hms(11, 8, 9)); assert_eq!(UTC.ymd(2014, 5, 6).and_hms(7, 8, 9) + Duration::seconds(3600 + 60 + 1), UTC.ymd(2014, 5, 6).and_hms(8, 9, 10)); diff --git a/src/div.rs b/src/div.rs index cc5d600..750714f 100644 --- a/src/div.rs +++ b/src/div.rs @@ -43,28 +43,28 @@ mod tests { #[test] fn test_mod_floor() { - assert_eq!(mod_floor( 8i, 3), 2); - assert_eq!(mod_floor( 8i, -3), -1); - assert_eq!(mod_floor(-8i, 3), 1); - assert_eq!(mod_floor(-8i, -3), -2); + assert_eq!(mod_floor( 8, 3), 2); + assert_eq!(mod_floor( 8, -3), -1); + assert_eq!(mod_floor(-8, 3), 1); + assert_eq!(mod_floor(-8, -3), -2); - assert_eq!(mod_floor( 1i, 2), 1); - assert_eq!(mod_floor( 1i, -2), -1); - assert_eq!(mod_floor(-1i, 2), 1); - assert_eq!(mod_floor(-1i, -2), -1); + assert_eq!(mod_floor( 1, 2), 1); + assert_eq!(mod_floor( 1, -2), -1); + assert_eq!(mod_floor(-1, 2), 1); + assert_eq!(mod_floor(-1, -2), -1); } #[test] fn test_div_mod_floor() { - assert_eq!(div_mod_floor( 8i, 3), ( 2, 2)); - assert_eq!(div_mod_floor( 8i, -3), (-3, -1)); - assert_eq!(div_mod_floor(-8i, 3), (-3, 1)); - assert_eq!(div_mod_floor(-8i, -3), ( 2, -2)); + assert_eq!(div_mod_floor( 8, 3), ( 2, 2)); + assert_eq!(div_mod_floor( 8, -3), (-3, -1)); + assert_eq!(div_mod_floor(-8, 3), (-3, 1)); + assert_eq!(div_mod_floor(-8, -3), ( 2, -2)); - assert_eq!(div_mod_floor( 1i, 2), ( 0, 1)); - assert_eq!(div_mod_floor( 1i, -2), (-1, -1)); - assert_eq!(div_mod_floor(-1i, 2), (-1, 1)); - assert_eq!(div_mod_floor(-1i, -2), ( 0, -1)); + assert_eq!(div_mod_floor( 1, 2), ( 0, 1)); + assert_eq!(div_mod_floor( 1, -2), (-1, -1)); + assert_eq!(div_mod_floor(-1, 2), (-1, 1)); + assert_eq!(div_mod_floor(-1, -2), ( 0, -1)); } } diff --git a/src/format.rs b/src/format.rs index 439dd69..af7dc61 100644 --- a/src/format.rs +++ b/src/format.rs @@ -7,7 +7,6 @@ */ use std::fmt; -use std::string::CowString; use {Datelike, Timelike}; use duration::Duration; @@ -17,7 +16,7 @@ use naive::time::NaiveTime; /// The internal workhouse for `DelayedFormat`. fn format(w: &mut fmt::Formatter, date: Option<&NaiveDate>, time: Option<&NaiveTime>, - off: Option<&(CowString<'static>, Duration)>, fmt: &str) -> fmt::Result { + off: Option<&(String, Duration)>, fmt: &str) -> fmt::Result { static SHORT_MONTHS: [&'static str; 12] = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; static LONG_MONTHS: [&'static str; 12] = @@ -57,9 +56,9 @@ fn format(w: &mut fmt::Formatter, date: Option<&NaiveDate>, time: Option<&NaiveT // month (Some('m'), Some(d), _, _) => try!(write!(w, "{:02}", d.month())), (Some('b'), Some(d), _, _) | (Some('h'), Some(d), _, _) => - try!(write!(w, "{}", SHORT_MONTHS[d.month0() as uint])), + try!(write!(w, "{}", SHORT_MONTHS[d.month0() as usize])), (Some('B'), Some(d), _, _) => - try!(write!(w, "{}", LONG_MONTHS[d.month0() as uint])), + try!(write!(w, "{}", LONG_MONTHS[d.month0() as usize])), // day of month (Some('d'), Some(d), _, _) => try!(write!(w, "{:02}", d.day())), @@ -76,9 +75,9 @@ fn format(w: &mut fmt::Formatter, date: Option<&NaiveDate>, time: Option<&NaiveT // day of week (Some('a'), Some(d), _, _) => - try!(write!(w, "{}", SHORT_WEEKDAYS[d.weekday().num_days_from_monday() as uint])), + try!(write!(w, "{}", SHORT_WEEKDAYS[d.weekday().num_days_from_monday() as usize])), (Some('A'), Some(d), _, _) => - try!(write!(w, "{}", LONG_WEEKDAYS[d.weekday().num_days_from_monday() as uint])), + try!(write!(w, "{}", LONG_WEEKDAYS[d.weekday().num_days_from_monday() as usize])), (Some('w'), Some(d), _, _) => try!(write!(w, "{}", d.weekday().num_days_from_sunday())), (Some('u'), Some(d), _, _) => try!(write!(w, "{}", d.weekday().number_from_monday())), @@ -91,7 +90,7 @@ fn format(w: &mut fmt::Formatter, date: Option<&NaiveDate>, time: Option<&NaiveT (Some('F'), Some(d), _, _) => // `%Y-%m-%d' try!(write!(w, "{:04}-{:02}-{:02}", d.year(), d.month(), d.day())), (Some('v'), Some(d), _, _) => // `%e-%b-%Y' - try!(write!(w, "{:2}-{}-{:04}", d.day(), SHORT_MONTHS[d.month0() as uint], + try!(write!(w, "{:2}-{}-{:04}", d.day(), SHORT_MONTHS[d.month0() as usize], d.year())), // hour @@ -141,8 +140,8 @@ fn format(w: &mut fmt::Formatter, date: Option<&NaiveDate>, time: Option<&NaiveT // combined date and time (Some('c'), Some(d), Some(t), _) => // `%a %b %e %T %Y` try!(write!(w, "{} {} {:2} {:02}:{:02}:{:02} {:04}", - SHORT_WEEKDAYS[d.weekday().num_days_from_monday() as uint], - SHORT_MONTHS[d.month0() as uint], d.day(), + SHORT_WEEKDAYS[d.weekday().num_days_from_monday() as usize], + SHORT_MONTHS[d.month0() as usize], d.day(), t.hour(), t.minute(), t.second(), d.year())), (Some('+'), Some(d), Some(t), Some(&(_, ref local_minus_utc))) => { // `%Y-%m-%dT%H:%M:%S` plus tz @@ -180,13 +179,14 @@ fn format(w: &mut fmt::Formatter, date: Option<&NaiveDate>, time: Option<&NaiveT /// A *temporary* object which can be used as an argument to `format!` or others. /// This is normally constructed via `format` methods of each date and time type. +#[derive(Show)] pub struct DelayedFormat<'a> { /// The date view, if any. date: Option, /// The time view, if any. time: Option, /// The name and local-to-UTC difference for the offset (timezone), if any. - off: Option<(CowString<'static>, Duration)>, + off: Option<(String, Duration)>, /// The format string. fmt: &'a str, } @@ -199,14 +199,15 @@ impl<'a> DelayedFormat<'a> { } /// Makes a new `DelayedFormat` value out of local date and time and UTC offset. - pub fn new_with_offset(date: Option, time: Option, - offset: &Off, fmt: &'a str) -> DelayedFormat<'a> { - let name_and_diff = (offset.name(), offset.local_minus_utc()); + pub fn new_with_offset(date: Option, time: Option, + offset: &Off, fmt: &'a str) -> DelayedFormat<'a> + where Off: Offset + fmt::String { + let name_and_diff = (offset.to_string(), offset.local_minus_utc()); DelayedFormat { date: date, time: time, off: Some(name_and_diff), fmt: fmt } } } -impl<'a> fmt::Show for DelayedFormat<'a> { +impl<'a> fmt::String for DelayedFormat<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let ret = format(f, self.date.as_ref(), self.time.as_ref(), self.off.as_ref(), self.fmt); ret.map_err(|_| fmt::Error) // we don't have any good means to pass detailed errors... diff --git a/src/lib.rs b/src/lib.rs index 845a9d9..dc62965 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,7 @@ /*! -# Chrono 0.1.12 +# Chrono 0.1.13 Date and time handling for Rust. (also known as `rust-chrono`) It aims to be a feature-complete superset of the [time](https://github.com/rust-lang/time) library. @@ -78,6 +78,7 @@ Addition and subtraction is also supported. The following illustrates most supported operations to the date and time: ~~~~ {.rust} +# #![allow(unstable)] # /* we intentionally fake the datetime... use chrono::{UTC, Local, Datelike, Timelike, Weekday, Duration}; @@ -116,17 +117,19 @@ assert_eq!(UTC.ymd(1970, 1, 1).and_hms(0, 0, 0) - Duration::seconds(1_000_000_00 Formatting is done via the `format` method, which format is equivalent to the familiar `strftime` format. -The default `to_string` method also gives a reasonable representation. +The default `to_string` method and `{:?}` specifier also give a reasonable representation. ~~~~ {.rust} +# #![allow(unstable)] use chrono::{UTC, Offset}; let dt = UTC.ymd(2014, 11, 28).and_hms(12, 0, 9); -assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2014-11-28 12:00:09".to_string()); -assert_eq!(dt.format("%a %b %e %T %Y").to_string(), "Fri Nov 28 12:00:09 2014".to_string()); +assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2014-11-28 12:00:09"); +assert_eq!(dt.format("%a %b %e %T %Y").to_string(), "Fri Nov 28 12:00:09 2014"); assert_eq!(dt.format("%a %b %e %T %Y").to_string(), dt.format("%c").to_string()); -assert_eq!(dt.to_string(), "2014-11-28T12:00:09Z".to_string()); +assert_eq!(dt.to_string(), "2014-11-28 12:00:09 UTC"); +assert_eq!(format!("{:?}", dt), "2014-11-28T12:00:09Z"); ~~~~ ### Individual date and time @@ -137,6 +140,7 @@ Most operations available to `DateTime` are also available to `Date` and `Time` whenever appropriate. ~~~~ {.rust} +# #![allow(unstable)] use chrono::{UTC, Local, Offset, LocalResult, Datelike, Weekday}; # // these *may* fail, but only very rarely. just rerun the test if you were that unfortunate ;) @@ -145,7 +149,7 @@ assert_eq!(Local::today(), Local::now().date()); assert_eq!(UTC.ymd(2014, 11, 28).weekday(), Weekday::Fri); assert_eq!(UTC.ymd_opt(2014, 11, 31), LocalResult::None); -assert_eq!(UTC.hms_milli(7, 8, 9, 10).format("%H%M%S").to_string(), "070809".to_string()); +assert_eq!(UTC.hms_milli(7, 8, 9, 10).format("%H%M%S").to_string(), "070809"); ~~~~ `DateTime` has two methods, `date` and `time`, @@ -184,6 +188,7 @@ Advanced offset handling and date/time parsing is not yet supported (but is plan #![doc(html_root_url = "https://lifthrasiir.github.io/rust-chrono/")] +#![allow(unstable)] #![deny(missing_docs)] extern crate "time" as stdtime; diff --git a/src/naive/date.rs b/src/naive/date.rs index 2ba71ab..bd3e137 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -6,7 +6,7 @@ * ISO 8601 calendar date without timezone. */ -use std::fmt; +use std::{fmt, hash}; use std::num::{Int, ToPrimitive}; use std::ops::{Add, Sub}; @@ -25,7 +25,7 @@ const MIN_YEAR: i32 = internals::MIN_YEAR as i32; /// ISO 8601 calendar date without timezone. /// Allows for every proleptic Gregorian date from Jan 1, 262145 BCE to Dec 31, 262143 CE. /// Also supports the conversion from ISO 8601 ordinal and week date. -#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] pub struct NaiveDate { ymdf: DateImpl, // (year << 13) | of } @@ -40,8 +40,10 @@ pub const MAX: NaiveDate = NaiveDate { ymdf: (MAX_YEAR << 13) | (365 << 4) | 0o1 fn test_date_bounds() { let calculated_min = NaiveDate::from_ymd(MIN_YEAR, 1, 1); let calculated_max = NaiveDate::from_ymd(MAX_YEAR, 12, 31); - assert!(MIN == calculated_min, "`MIN` should have a year flag {}", calculated_min.of().flags()); - assert!(MAX == calculated_max, "`MAX` should have a year flag {}", calculated_max.of().flags()); + assert!(MIN == calculated_min, + "`MIN` should have a year flag {:?}", calculated_min.of().flags()); + assert!(MAX == calculated_max, + "`MAX` should have a year flag {:?}", calculated_max.of().flags()); } impl NaiveDate { @@ -378,6 +380,10 @@ impl Datelike for NaiveDate { } } +impl hash::Hash for NaiveDate { + fn hash(&self, state: &mut H) { self.ymdf.hash(state) } +} + impl Add for NaiveDate { type Output = NaiveDate; @@ -432,6 +438,18 @@ impl fmt::Show for NaiveDate { } } +impl fmt::String for NaiveDate { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let year = self.year(); + let mdf = self.mdf(); + if year >= 0 { + write!(f, "{:04}-{:02}-{:02}", year, mdf.month(), mdf.day()) + } else { + write!(f, "{:+05}-{:02}-{:02}", year, mdf.month(), mdf.day()) + } + } +} + #[cfg(test)] mod tests { use super::{NaiveDate, MIN, MAX}; @@ -736,35 +754,40 @@ mod tests { #[test] fn test_date_fmt() { - assert_eq!(NaiveDate::from_ymd(2012, 3, 4).to_string(), "2012-03-04".to_string()); - assert_eq!(NaiveDate::from_ymd(0, 3, 4).to_string(), "0000-03-04".to_string()); - assert_eq!(NaiveDate::from_ymd(-307, 3, 4).to_string(), "-0307-03-04".to_string()); - assert_eq!(NaiveDate::from_ymd(12345, 3, 4).to_string(), "+12345-03-04".to_string()); + assert_eq!(format!("{:?}", NaiveDate::from_ymd(2012, 3, 4)), "2012-03-04"); + assert_eq!(format!("{:?}", NaiveDate::from_ymd(0, 3, 4)), "0000-03-04"); + assert_eq!(format!("{:?}", NaiveDate::from_ymd(-307, 3, 4)), "-0307-03-04"); + assert_eq!(format!("{:?}", NaiveDate::from_ymd(12345, 3, 4)), "+12345-03-04"); + + assert_eq!(NaiveDate::from_ymd(2012, 3, 4).to_string(), "2012-03-04"); + assert_eq!(NaiveDate::from_ymd(0, 3, 4).to_string(), "0000-03-04"); + assert_eq!(NaiveDate::from_ymd(-307, 3, 4).to_string(), "-0307-03-04"); + assert_eq!(NaiveDate::from_ymd(12345, 3, 4).to_string(), "12345-03-04"); // the format specifier should have no effect on `NaiveTime` - assert_eq!(format!("{:+30}", NaiveDate::from_ymd(1234, 5, 6)), "1234-05-06".to_string()); - assert_eq!(format!("{:30}", NaiveDate::from_ymd(12345, 6, 7)), "+12345-06-07".to_string()); + assert_eq!(format!("{:+30?}", NaiveDate::from_ymd(1234, 5, 6)), "1234-05-06"); + assert_eq!(format!("{:30?}", NaiveDate::from_ymd(12345, 6, 7)), "+12345-06-07"); } #[test] fn test_date_format() { let d = NaiveDate::from_ymd(2012, 3, 4); - assert_eq!(d.format("%Y,%C,%y,%G,%g").to_string(), "2012,20,12,2012,12".to_string()); - assert_eq!(d.format("%m,%b,%h,%B").to_string(), "03,Mar,Mar,March".to_string()); - assert_eq!(d.format("%d,%e").to_string(), "04, 4".to_string()); - assert_eq!(d.format("%U,%W,%V").to_string(), "10,09,09".to_string()); - assert_eq!(d.format("%a,%A,%w,%u").to_string(), "Sun,Sunday,0,7".to_string()); - assert_eq!(d.format("%j").to_string(), "064".to_string()); // since 2012 is a leap year - assert_eq!(d.format("%D,%x").to_string(), "03/04/12,03/04/12".to_string()); - assert_eq!(d.format("%F").to_string(), "2012-03-04".to_string()); - assert_eq!(d.format("%v").to_string(), " 4-Mar-2012".to_string()); - assert_eq!(d.format("%t%n%%%n%t").to_string(), "\t\n%\n\t".to_string()); + assert_eq!(d.format("%Y,%C,%y,%G,%g").to_string(), "2012,20,12,2012,12"); + assert_eq!(d.format("%m,%b,%h,%B").to_string(), "03,Mar,Mar,March"); + assert_eq!(d.format("%d,%e").to_string(), "04, 4"); + assert_eq!(d.format("%U,%W,%V").to_string(), "10,09,09"); + assert_eq!(d.format("%a,%A,%w,%u").to_string(), "Sun,Sunday,0,7"); + assert_eq!(d.format("%j").to_string(), "064"); // since 2012 is a leap year + assert_eq!(d.format("%D,%x").to_string(), "03/04/12,03/04/12"); + assert_eq!(d.format("%F").to_string(), "2012-03-04"); + assert_eq!(d.format("%v").to_string(), " 4-Mar-2012"); + assert_eq!(d.format("%t%n%%%n%t").to_string(), "\t\n%\n\t"); // corner cases assert_eq!(NaiveDate::from_ymd(2007, 12, 31).format("%G,%g,%U,%W,%V").to_string(), - "2008,08,53,53,01".to_string()); + "2008,08,53,53,01"); assert_eq!(NaiveDate::from_ymd(2010, 1, 3).format("%G,%g,%U,%W,%V").to_string(), - "2009,09,01,00,53".to_string()); + "2009,09,01,00,53"); } } @@ -860,10 +883,10 @@ mod internals { pub fn cycle_to_yo(cycle: u32) -> (u32, u32) { let (mut year_mod_400, mut ordinal0) = div_rem(cycle, 365); - let delta = YEAR_DELTAS[year_mod_400 as uint] as u32; + let delta = YEAR_DELTAS[year_mod_400 as usize] as u32; if ordinal0 < delta { year_mod_400 -= 1; - ordinal0 += 365 - YEAR_DELTAS[year_mod_400 as uint] as u32; + ordinal0 += 365 - YEAR_DELTAS[year_mod_400 as usize] as u32; } else { ordinal0 -= delta; } @@ -871,7 +894,7 @@ mod internals { } pub fn yo_to_cycle(year_mod_400: u32, ordinal: u32) -> u32 { - year_mod_400 * 365 + YEAR_DELTAS[year_mod_400 as uint] as u32 + ordinal - 1 + year_mod_400 * 365 + YEAR_DELTAS[year_mod_400 as usize] as u32 + ordinal - 1 } impl YearFlags { @@ -883,7 +906,7 @@ mod internals { #[inline] pub fn from_year_mod_400(year: i32) -> YearFlags { - YEAR_TO_FLAGS[year as uint] + YEAR_TO_FLAGS[year as usize] } #[inline] @@ -903,7 +926,7 @@ mod internals { #[inline] pub fn nisoweeks(&self) -> u32 { let YearFlags(flags) = *self; - 52 + ((0b00000100_00000110 >> flags as uint) & 1) + 52 + ((0b00000100_00000110 >> flags as usize) & 1) } } @@ -930,7 +953,7 @@ mod internals { pub const MAX_MDL: u32 = (12 << 6) | (31 << 1) | 1; const XX: i8 = -128; - static MDL_TO_OL: [i8; (MAX_MDL as uint + 1u)] = [ + static MDL_TO_OL: [i8; (MAX_MDL as usize + 1us)] = [ XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, @@ -985,7 +1008,7 @@ mod internals { 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, // 12 ]; - static OL_TO_MDL: [u8; (MAX_OL as uint + 1u)] = [ + static OL_TO_MDL: [u8; (MAX_OL as usize + 1us)] = [ 0, 0, // 0 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, @@ -1059,7 +1082,7 @@ mod internals { #[inline] pub fn from_mdf(Mdf(mdf): Mdf) -> Of { let mdl = mdf >> 3; - match MDL_TO_OL.get(mdl as uint) { + match MDL_TO_OL.get(mdl as usize) { Some(&v) => Of(mdf - ((v as i32 as u32 & 0x3ff) << 3)), None => Of(0) } @@ -1132,7 +1155,7 @@ mod internals { impl fmt::Show for Of { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let Of(of) = *self; - write!(f, "Of(({} << 4) | {:#04o} /*{}*/)", + write!(f, "Of(({} << 4) | {:#04o} /*{:?}*/)", of >> 4, of & 0b1111, YearFlags((of & 0b1111) as u8)) } } @@ -1166,7 +1189,7 @@ mod internals { #[inline] pub fn from_of(Of(of): Of) -> Mdf { let ol = of >> 3; - match OL_TO_MDL.get(ol as uint) { + match OL_TO_MDL.get(ol as usize) { Some(&v) => Mdf(of + ((v as u32) << 3)), None => Mdf(0) } @@ -1176,7 +1199,7 @@ mod internals { pub fn valid(&self) -> bool { let Mdf(mdf) = *self; let mdl = mdf >> 3; - match MDL_TO_OL.get(mdl as uint) { + match MDL_TO_OL.get(mdl as usize) { Some(&v) => v >= 0, None => false } @@ -1229,7 +1252,7 @@ mod internals { impl fmt::Show for Mdf { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let Mdf(mdf) = *self; - write!(f, "Mdf(({} << 9) | ({} << 4) | {:#04o} /*{}*/)", + write!(f, "Mdf(({} << 9) | ({} << 4) | {:#04o} /*{:?}*/)", mdf >> 9, (mdf >> 4) & 0b11111, mdf & 0b1111, YearFlags((mdf & 0b1111) as u8)) } } @@ -1298,7 +1321,7 @@ mod internals { for ordinal in range_inclusive(ordinal1, ordinal2) { let of = Of::new(ordinal, flags); assert!(of.valid() == expected, - "ordinal {} = {} should be {} for dominical year {}", + "ordinal {} = {:?} should be {} for dominical year {:?}", ordinal, of, if expected {"valid"} else {"invalid"}, flags); } } @@ -1326,7 +1349,7 @@ mod internals { for day in range_inclusive(day1, day2) { let mdf = Mdf::new(month, day, flags); assert!(mdf.valid() == expected, - "month {} day {} = {} should be {} for dominical year {}", + "month {} day {} = {:?} should be {} for dominical year {:?}", month, day, mdf, if expected {"valid"} else {"invalid"}, flags); } } diff --git a/src/naive/datetime.rs b/src/naive/datetime.rs index f9e5e4f..f531845 100644 --- a/src/naive/datetime.rs +++ b/src/naive/datetime.rs @@ -6,7 +6,7 @@ * ISO 8601 date and time without timezone. */ -use std::fmt; +use std::{fmt, hash}; use std::num::{Int, ToPrimitive}; use std::ops::{Add, Sub}; @@ -18,7 +18,7 @@ use naive::date::NaiveDate; use format::DelayedFormat; /// ISO 8601 combined date and time without timezone. -#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] pub struct NaiveDateTime { date: NaiveDate, time: NaiveTime, @@ -163,6 +163,10 @@ impl Timelike for NaiveDateTime { } } +impl hash::Hash for NaiveDateTime { + fn hash(&self, state: &mut H) { self.date.hash(state); self.time.hash(state) } +} + impl Add for NaiveDateTime { type Output = NaiveDateTime; @@ -203,7 +207,13 @@ impl Sub for NaiveDateTime { impl fmt::Show for NaiveDateTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}T{}", self.date, self.time) + write!(f, "{:?}T{:?}", self.date, self.time) + } +} + +impl fmt::String for NaiveDateTime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} {}", self.date, self.time) } } @@ -270,8 +280,8 @@ mod tests { #[test] fn test_datetime_format() { let dt = NaiveDate::from_ymd(2010, 9, 8).and_hms_milli(7, 6, 54, 321); - assert_eq!(dt.format("%c").to_string(), "Wed Sep 8 07:06:54 2010".to_string()); - assert_eq!(dt.format("%t%n%%%n%t").to_string(), "\t\n%\n\t".to_string()); + assert_eq!(dt.format("%c").to_string(), "Wed Sep 8 07:06:54 2010"); + assert_eq!(dt.format("%t%n%%%n%t").to_string(), "\t\n%\n\t"); } } diff --git a/src/naive/time.rs b/src/naive/time.rs index 70e1c90..0a50e46 100644 --- a/src/naive/time.rs +++ b/src/naive/time.rs @@ -6,7 +6,7 @@ * ISO 8601 time without timezone. */ -use std::fmt; +use std::{fmt, hash}; use std::num::Int; use std::ops::{Add, Sub}; @@ -18,7 +18,7 @@ use format::DelayedFormat; /// ISO 8601 time without timezone. /// Allows for the nanosecond precision and optional leap second representation. -#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] pub struct NaiveTime { secs: u32, frac: u32, @@ -172,6 +172,10 @@ impl Timelike for NaiveTime { } } +impl hash::Hash for NaiveTime { + fn hash(&self, state: &mut H) { self.secs.hash(state); self.frac.hash(state) } +} + impl Add for NaiveTime { type Output = NaiveTime; @@ -241,6 +245,10 @@ impl fmt::Show for NaiveTime { } } +impl fmt::String for NaiveTime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Show::fmt(self, f) } +} + #[cfg(test)] mod tests { use super::NaiveTime; @@ -350,36 +358,29 @@ mod tests { #[test] fn test_time_fmt() { - assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 999).to_string(), - "23:59:59.999".to_string()); - assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 1_000).to_string(), - "23:59:60".to_string()); - assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 1_001).to_string(), - "23:59:60.001".to_string()); - assert_eq!(NaiveTime::from_hms_micro(0, 0, 0, 43210).to_string(), - "00:00:00.043210".to_string()); - assert_eq!(NaiveTime::from_hms_nano(0, 0, 0, 6543210).to_string(), - "00:00:00.006543210".to_string()); + 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"); // the format specifier should have no effect on `NaiveTime` - assert_eq!(format!("{:30}", NaiveTime::from_hms_milli(3, 5, 7, 9)), - "03:05:07.009".to_string()); + assert_eq!(format!("{:30}", NaiveTime::from_hms_milli(3, 5, 7, 9)), "03:05:07.009"); } #[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".to_string()); - assert_eq!(t.format("%M").to_string(), "05".to_string()); - assert_eq!(t.format("%S,%f").to_string(), "07,098765432".to_string()); - assert_eq!(t.format("%R").to_string(), "03:05".to_string()); - assert_eq!(t.format("%T,%X").to_string(), "03:05:07,03:05:07".to_string()); - assert_eq!(t.format("%r").to_string(), "03:05:07 AM".to_string()); - assert_eq!(t.format("%t%n%%%n%t").to_string(), "\t\n%\n\t".to_string()); + 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").to_string(), "07,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"); // corner cases - assert_eq!(NaiveTime::from_hms(13, 57, 9).format("%r").to_string(), - "01:57:09 PM".to_string()); + assert_eq!(NaiveTime::from_hms(13, 57, 9).format("%r").to_string(), "01:57:09 PM"); } } diff --git a/src/offset.rs b/src/offset.rs index 4adccc6..cbdc1ca 100644 --- a/src/offset.rs +++ b/src/offset.rs @@ -6,9 +6,7 @@ * Offsets from the local time to UTC. */ -use std::borrow::IntoCow; use std::fmt; -use std::string::CowString; use stdtime; use {Weekday, Datelike, Timelike}; @@ -125,14 +123,14 @@ impl LocalResult> { } -impl LocalResult { +impl LocalResult { /// Returns the single unique conversion result, or fails accordingly. pub fn unwrap(self) -> T { match self { LocalResult::None => panic!("No such local time"), LocalResult::Single(t) => t, LocalResult::Ambiguous(t1,t2) => { - panic!("Ambiguous local time, ranging from {} to {}", t1, t2) + panic!("Ambiguous local time, ranging from {:?} to {:?}", t1, t2) } } } @@ -293,9 +291,6 @@ pub trait Offset: Clone + fmt::Show { } } - /// Returns a name or abbreviation of this offset. - fn name(&self) -> CowString<'static>; - /// Returns the *current* offset from UTC to the local time. fn local_minus_utc(&self) -> Duration; @@ -338,7 +333,6 @@ impl UTC { } impl Offset for UTC { - fn name(&self) -> CowString<'static> { "UTC".into_cow() } fn local_minus_utc(&self) -> Duration { Duration::zero() } fn from_local_date(&self, local: &NaiveDate) -> LocalResult> { @@ -360,6 +354,10 @@ impl fmt::Show for UTC { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Z") } } +impl fmt::String for UTC { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "UTC") } +} + /// The fixed offset, from UTC-23:59:59 to UTC+23:59:59. #[derive(Copy, Clone, PartialEq, Eq)] pub struct FixedOffset { @@ -409,7 +407,6 @@ impl FixedOffset { } impl Offset for FixedOffset { - fn name(&self) -> CowString<'static> { "UTC".into_cow() } // XXX fn local_minus_utc(&self) -> Duration { Duration::seconds(self.local_minus_utc as i64) } fn from_local_date(&self, local: &NaiveDate) -> LocalResult> { @@ -451,6 +448,10 @@ impl fmt::Show for FixedOffset { } } +impl fmt::String for FixedOffset { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Show::fmt(self, f) } +} + /// The local timescale. This is implemented via the standard `time` crate. #[derive(Copy, Clone)] pub struct Local { @@ -505,7 +506,6 @@ impl Local { } impl Offset for Local { - fn name(&self) -> CowString<'static> { "LMT".into_cow() } // XXX XXX fn local_minus_utc(&self) -> Duration { self.cached.local_minus_utc() } fn from_local_date(&self, local: &NaiveDate) -> LocalResult> { diff --git a/src/time.rs b/src/time.rs index cc6404f..19337c8 100644 --- a/src/time.rs +++ b/src/time.rs @@ -44,17 +44,19 @@ impl Time { Time::from_utc(self.time, offset) } + /// Returns a view to the local time. + fn local(&self) -> NaiveTime { + self.offset.to_local_time(&self.time) + } +} + +impl Time { /// Formats the time in the specified format string. /// See the `format` module on the supported escape sequences. #[inline] pub fn format<'a>(&'a self, fmt: &'a str) -> DelayedFormat<'a> { DelayedFormat::new_with_offset(None, Some(self.local()), &self.offset, fmt) } - - /// Returns a view to the local time. - fn local(&self) -> NaiveTime { - self.offset.to_local_time(&self.time) - } } impl Timelike for Time { @@ -108,8 +110,8 @@ impl Ord for Time { fn cmp(&self, other: &Time) -> Ordering { self.time.cmp(&other.time) } } -impl hash::Hash for Time { - fn hash(&self, state: &mut hash::sip::SipState) { self.time.hash(state) } +impl hash::Hash for Time { + fn hash(&self, state: &mut H) { self.time.hash(state) } } impl Add for Time { @@ -133,7 +135,13 @@ impl Sub for Time { fn sub(self, rhs: Duration) -> Time { self.add(-rhs) } } -impl fmt::Show for Time { +impl fmt::Show for Time { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}{:?}", self.local(), self.offset) + } +} + +impl fmt::String for Time { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}{}", self.local(), self.offset) }