Skip to content

Commit

Permalink
0.1.13: language changes and fmt::String supports.
Browse files Browse the repository at this point in the history
- Every type modulo `LocalResult` and `Offset` now implements
  `std::fmt::String`, so `.to_string()` can be used.
  The exact format has been changed for better looking output.

- `std::fmt::Show` are intended for "stricter" output,
  which mostly means the strict ISO 8601 format.
  `DelayedFormat` also implements this, but only for inspection.

- `Offset` should implement `Show` but can omit `String`.
  The old `name` method is merged into `String` implementations.
  • Loading branch information
lifthrasiir committed Jan 9, 2015
1 parent d79c460 commit ca84749
Show file tree
Hide file tree
Showing 12 changed files with 221 additions and 154 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "chrono"
version = "0.1.12"
version = "0.1.13"
authors = ["Kang Seonghoon <[email protected]>"]

description = "Date and time library for Rust"
Expand All @@ -15,5 +15,5 @@ license = "MIT/Apache-2.0"
name = "chrono"

[dependencies]
time = "0.1.11"
time = "0.1.12"

13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[Chrono][doc] 0.1.12
[Chrono][doc] 0.1.13
====================

[![Chrono on Travis CI][travis-image]][travis]
Expand Down Expand Up @@ -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
Expand All @@ -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`,
Expand Down
35 changes: 20 additions & 15 deletions src/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,17 +175,19 @@ impl<Off:Offset> Date<Off> {
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<Off: Offset + fmt::String> Date<Off> {
/// 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<Off:Offset> Datelike for Date<Off> {
Expand Down Expand Up @@ -259,8 +261,8 @@ impl<Off:Offset> Ord for Date<Off> {
fn cmp(&self, other: &Date<Off>) -> Ordering { self.date.cmp(&other.date) }
}

impl<Off:Offset> hash::Hash for Date<Off> {
fn hash(&self, state: &mut hash::sip::SipState) { self.date.hash(state) }
impl<Off: Offset, H: hash::Hasher + hash::Writer> hash::Hash<H> for Date<Off> {
fn hash(&self, state: &mut H) { self.date.hash(state) }
}

impl<Off:Offset> Add<Duration> for Date<Off> {
Expand All @@ -284,17 +286,21 @@ impl<Off:Offset> Sub<Duration> for Date<Off> {
fn sub(self, rhs: Duration) -> Date<Off> { self.add(-rhs) }
}

impl<Off:Offset> fmt::Show for Date<Off> {
impl<Off: Offset> fmt::Show for Date<Off> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}{:?}", self.local(), self.offset)
}
}

impl<Off: Offset + fmt::String> fmt::String for Date<Off> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}", self.local(), self.offset)
}
}

#[cfg(test)]
mod tests {
use std::borrow::IntoCow;
use std::fmt;
use std::string::CowString;

use duration::Duration;
use naive::date::NaiveDate;
Expand All @@ -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<Date<UTC1y>> {
Expand All @@ -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());
}
}
Expand Down
39 changes: 26 additions & 13 deletions src/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,20 @@ impl<Off:Offset> DateTime<Off> {
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<Off: Offset + fmt::String> DateTime<Off> {
/// Formats the combined date and 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> {
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<Off:Offset> Datelike for DateTime<Off> {
Expand Down Expand Up @@ -180,8 +182,8 @@ impl<Off:Offset> Ord for DateTime<Off> {
fn cmp(&self, other: &DateTime<Off>) -> Ordering { self.datetime.cmp(&other.datetime) }
}

impl<Off:Offset> hash::Hash for DateTime<Off> {
fn hash(&self, state: &mut hash::sip::SipState) { self.datetime.hash(state) }
impl<Off: Offset, H: hash::Hasher + hash::Writer> hash::Hash<H> for DateTime<Off> {
fn hash(&self, state: &mut H) { self.datetime.hash(state) }
}

impl<Off:Offset> Add<Duration> for DateTime<Off> {
Expand All @@ -205,9 +207,15 @@ impl<Off:Offset> Sub<Duration> for DateTime<Off> {
fn sub(self, rhs: Duration) -> DateTime<Off> { self.add(-rhs) }
}

impl<Off:Offset> fmt::Show for DateTime<Off> {
impl<Off: Offset> fmt::Show for DateTime<Off> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}{:?}", self.local(), self.offset)
}
}

impl<Off: Offset + fmt::String> fmt::String for DateTime<Off> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}", self.local(), self.offset)
write!(f, "{} {}", self.local(), self.offset)
}
}

Expand All @@ -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));
Expand Down
32 changes: 16 additions & 16 deletions src/div.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}

29 changes: 15 additions & 14 deletions src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
*/

use std::fmt;
use std::string::CowString;

use {Datelike, Timelike};
use duration::Duration;
Expand All @@ -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] =
Expand Down Expand Up @@ -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())),
Expand All @@ -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())),

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<NaiveDate>,
/// The time view, if any.
time: Option<NaiveTime>,
/// 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,
}
Expand All @@ -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<Off:Offset>(date: Option<NaiveDate>, time: Option<NaiveTime>,
offset: &Off, fmt: &'a str) -> DelayedFormat<'a> {
let name_and_diff = (offset.name(), offset.local_minus_utc());
pub fn new_with_offset<Off>(date: Option<NaiveDate>, time: Option<NaiveTime>,
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...
Expand Down
Loading

0 comments on commit ca84749

Please sign in to comment.