added `chrono::format` module and `format` methods.
this is a saner replacement for `time::strftime`; it does not allocate the additional memory.
This commit is contained in:
parent
ed71a1037b
commit
f1931ad21e
|
@ -15,6 +15,7 @@ use naive;
|
||||||
use naive::date::NaiveDate;
|
use naive::date::NaiveDate;
|
||||||
use naive::time::NaiveTime;
|
use naive::time::NaiveTime;
|
||||||
use datetime::DateTime;
|
use datetime::DateTime;
|
||||||
|
use format::DelayedFormat;
|
||||||
|
|
||||||
/// ISO 8601 calendar date with timezone.
|
/// ISO 8601 calendar date with timezone.
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
|
@ -158,6 +159,13 @@ impl<Off:Offset> Date<Off> {
|
||||||
self.date.pred_opt().map(|date| Date::from_utc(date, self.offset.clone()))
|
self.date.pred_opt().map(|date| Date::from_utc(date, self.offset.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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.
|
/// Returns a view to the local date.
|
||||||
fn local(&self) -> NaiveDate {
|
fn local(&self) -> NaiveDate {
|
||||||
self.offset.to_local_date(&self.date)
|
self.offset.to_local_date(&self.date)
|
||||||
|
|
|
@ -14,6 +14,7 @@ use duration::Duration;
|
||||||
use naive::datetime::NaiveDateTime;
|
use naive::datetime::NaiveDateTime;
|
||||||
use time::Time;
|
use time::Time;
|
||||||
use date::Date;
|
use date::Date;
|
||||||
|
use format::DelayedFormat;
|
||||||
|
|
||||||
/// ISO 8601 combined date and time with timezone.
|
/// ISO 8601 combined date and time with timezone.
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
|
@ -48,6 +49,14 @@ impl<Off:Offset> DateTime<Off> {
|
||||||
self.datetime.num_seconds_from_unix_epoch()
|
self.datetime.num_seconds_from_unix_epoch()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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.
|
/// Returns a view to the local datetime.
|
||||||
fn local(&self) -> NaiveDateTime {
|
fn local(&self) -> NaiveDateTime {
|
||||||
self.offset.to_local_datetime(&self.datetime)
|
self.offset.to_local_datetime(&self.datetime)
|
||||||
|
|
|
@ -0,0 +1,215 @@
|
||||||
|
// This is a part of rust-chrono.
|
||||||
|
// Copyright (c) 2014, Kang Seonghoon.
|
||||||
|
// See README.md and LICENSE.txt for details.
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Formatting utilities for date and time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use std::str::MaybeOwned;
|
||||||
|
use std::io::{IoResult, IoError, InvalidInput};
|
||||||
|
|
||||||
|
use {Datelike, Timelike};
|
||||||
|
use duration::Duration;
|
||||||
|
use offset::Offset;
|
||||||
|
use naive::date::NaiveDate;
|
||||||
|
use naive::time::NaiveTime;
|
||||||
|
|
||||||
|
/// The internal workhouse for `DelayedFormat`.
|
||||||
|
fn format(w: &mut Writer, date: Option<&NaiveDate>, time: Option<&NaiveTime>,
|
||||||
|
off: Option<&(MaybeOwned<'static>, Duration)>, fmt: &str) -> IoResult<()> {
|
||||||
|
static SHORT_MONTHS: [&'static str, ..12] =
|
||||||
|
["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
||||||
|
static LONG_MONTHS: [&'static str, ..12] =
|
||||||
|
["January", "February", "March", "April", "May", "June",
|
||||||
|
"July", "August", "September", "October", "November", "December"];
|
||||||
|
static SHORT_WEEKDAYS: [&'static str, ..7] =
|
||||||
|
["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
||||||
|
static LONG_WEEKDAYS: [&'static str, ..7] =
|
||||||
|
["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
|
||||||
|
|
||||||
|
let mut parts = fmt.split('%');
|
||||||
|
match parts.next() {
|
||||||
|
Some(first) => try!(write!(w, "{}", first)),
|
||||||
|
None => return Ok(()),
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut last_was_percent = false;
|
||||||
|
for part in parts {
|
||||||
|
if last_was_percent { // `%%<part>`
|
||||||
|
last_was_percent = false;
|
||||||
|
try!(write!(w, "%{}", part));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (head, tail) = part.slice_shift_char();
|
||||||
|
match (head, date, time, off) {
|
||||||
|
// year
|
||||||
|
(Some('Y'), Some(d), _, _) => try!(write!(w, "{}", d.year())),
|
||||||
|
(Some('C'), Some(d), _, _) => try!(write!(w, "{:02}", d.year() / 100)),
|
||||||
|
(Some('y'), Some(d), _, _) => try!(write!(w, "{:02}", d.year() % 100)),
|
||||||
|
(Some('G'), Some(d), _, _) => try!(write!(w, "{:04}", d.isoweekdate().val0())),
|
||||||
|
(Some('g'), Some(d), _, _) => try!(write!(w, "{:02}", d.isoweekdate().val0() % 100)),
|
||||||
|
|
||||||
|
// 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])),
|
||||||
|
(Some('B'), Some(d), _, _) =>
|
||||||
|
try!(write!(w, "{}", LONG_MONTHS[d.month0() as uint])),
|
||||||
|
|
||||||
|
// day of month
|
||||||
|
(Some('d'), Some(d), _, _) => try!(write!(w, "{:02}", d.day())),
|
||||||
|
(Some('e'), Some(d), _, _) => try!(write!(w, "{:2}", d.day())),
|
||||||
|
|
||||||
|
// week
|
||||||
|
(Some('U'), Some(d), _, _) =>
|
||||||
|
try!(write!(w, "{:02}", (d.ordinal() - d.weekday().num_days_from_sunday()
|
||||||
|
+ 7) / 7)),
|
||||||
|
(Some('W'), Some(d), _, _) =>
|
||||||
|
try!(write!(w, "{:02}", (d.ordinal() - d.weekday().num_days_from_monday()
|
||||||
|
+ 7) / 7)),
|
||||||
|
(Some('V'), Some(d), _, _) => try!(write!(w, "{:02}", d.isoweekdate().val1())),
|
||||||
|
|
||||||
|
// day of week
|
||||||
|
(Some('a'), Some(d), _, _) =>
|
||||||
|
try!(write!(w, "{}", SHORT_WEEKDAYS[d.weekday().num_days_from_monday() as uint])),
|
||||||
|
(Some('A'), Some(d), _, _) =>
|
||||||
|
try!(write!(w, "{}", LONG_WEEKDAYS[d.weekday().num_days_from_monday() as uint])),
|
||||||
|
(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())),
|
||||||
|
|
||||||
|
// day of year
|
||||||
|
(Some('j'), Some(d), _, _) => try!(write!(w, "{:03}", d.ordinal())),
|
||||||
|
|
||||||
|
// combined date
|
||||||
|
(Some('D'), Some(d), _, _) | (Some('x'), Some(d), _, _) => // `%m/%d/%y`
|
||||||
|
try!(write!(w, "{:02}/{:02}/{:02}", d.month(), d.day(), d.year() % 100)),
|
||||||
|
(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],
|
||||||
|
d.year())),
|
||||||
|
|
||||||
|
// hour
|
||||||
|
(Some('H'), _, Some(t), _) => try!(write!(w, "{:02}", t.hour())),
|
||||||
|
(Some('k'), _, Some(t), _) => try!(write!(w, "{:2}", t.hour())),
|
||||||
|
(Some('I'), _, Some(t), _) => try!(write!(w, "{:02}", t.hour12().val1())),
|
||||||
|
(Some('l'), _, Some(t), _) => try!(write!(w, "{:2}", t.hour12().val1())),
|
||||||
|
(Some('P'), _, Some(t), _) =>
|
||||||
|
try!(write!(w, "{}", if t.hour12().val0() {"pm"} else {"am"})),
|
||||||
|
(Some('p'), _, Some(t), _) =>
|
||||||
|
try!(write!(w, "{}", if t.hour12().val0() {"PM"} else {"AM"})),
|
||||||
|
|
||||||
|
// minute
|
||||||
|
(Some('M'), _, Some(t), _) => try!(write!(w, "{:02}", t.minute())),
|
||||||
|
|
||||||
|
// second and below
|
||||||
|
(Some('S'), _, Some(t), _) => try!(write!(w, "{:02}", t.second())),
|
||||||
|
(Some('f'), _, Some(t), _) => try!(write!(w, "{:09}", t.nanosecond())),
|
||||||
|
|
||||||
|
// combined time
|
||||||
|
(Some('R'), _, Some(t), _) => // `%H:%M`
|
||||||
|
try!(write!(w, "{:02}:{:02}", t.hour(), t.minute())),
|
||||||
|
(Some('T'), _, Some(t), _) | (Some('X'), _, Some(t), _) => // `%H:%M:%S`
|
||||||
|
try!(write!(w, "{:02}:{:02}:{:02}", t.hour(), t.minute(), t.second())),
|
||||||
|
(Some('r'), _, Some(t), _) => { // `%I:%M:%S %p`
|
||||||
|
let (is_pm, hour12) = t.hour12();
|
||||||
|
try!(write!(w, "{:02}:{:02}:{:02} {}", hour12, t.minute(), t.second(),
|
||||||
|
if is_pm {"PM"} else {"AM"}))
|
||||||
|
},
|
||||||
|
|
||||||
|
// timezone
|
||||||
|
(Some('Z'), _, _, Some(&(ref name, _))) => try!(write!(w, "{}", *name)),
|
||||||
|
(Some('z'), _, _, Some(&(_, ref local_minus_utc))) => {
|
||||||
|
let off = local_minus_utc.num_minutes();
|
||||||
|
let (sign, off) = if off < 0 {('-', -off)} else {('+', off)};
|
||||||
|
try!(write!(w, "{}{:02}{:02}", sign, off / 60, off % 60))
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
// timestamp
|
||||||
|
(Some('s'), Some(d), Some(t), Some(o)) => { // XXX
|
||||||
|
let datetime = o.from_local_datetime(&d.and_time(t.clone())).unwrap();
|
||||||
|
try!(write!(w, "{}", datetime.num_seconds_from_unix_epoch()))
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 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(),
|
||||||
|
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
|
||||||
|
let off = local_minus_utc.num_minutes();
|
||||||
|
let (sign, off) = if off < 0 {('-', -off)} else {('+', off)};
|
||||||
|
try!(write!(w, "{}-{:02}-{:02}T{:02}:{:02}:{:02}{}{:02}:{:02}",
|
||||||
|
d.year(), d.month(), d.day(), t.hour(), t.minute(), t.second(),
|
||||||
|
sign, off / 60, off % 60))
|
||||||
|
},
|
||||||
|
|
||||||
|
// special characters
|
||||||
|
(Some('t'), _, _, _) => try!(write!(w, "\t")),
|
||||||
|
(Some('n'), _, _, _) => try!(write!(w, "\n")),
|
||||||
|
|
||||||
|
(Some(c), _, _, _) => {
|
||||||
|
return Err(IoError { kind: InvalidInput, desc: "invalid date/time format",
|
||||||
|
detail: Some(format!("unsupported escape sequence %{}", c)) });
|
||||||
|
}
|
||||||
|
|
||||||
|
(None, _, _, _) => {
|
||||||
|
// if there is the next part, a single `%` and that part should be printed
|
||||||
|
// in verbatim. otherwise it is an error (the stray `%`).
|
||||||
|
last_was_percent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try!(write!(w, "{}", tail));
|
||||||
|
}
|
||||||
|
|
||||||
|
if last_was_percent { // a stray `%`
|
||||||
|
Err(IoError { kind: InvalidInput,
|
||||||
|
desc: "invalid date/time format: stray `%`", detail: None })
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
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<(MaybeOwned<'static>, Duration)>,
|
||||||
|
/// The format string.
|
||||||
|
fmt: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DelayedFormat<'a> {
|
||||||
|
/// Makes a new `DelayedFormat` value out of local date and time.
|
||||||
|
pub fn new(date: Option<NaiveDate>, time: Option<NaiveTime>,
|
||||||
|
fmt: &'a str) -> DelayedFormat<'a> {
|
||||||
|
DelayedFormat { date: date, time: time, off: None, fmt: fmt }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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());
|
||||||
|
DelayedFormat { date: date, time: time, off: Some(name_and_diff), fmt: fmt }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> fmt::Show 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::WriteError) // XXX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ pub mod naive {
|
||||||
pub mod date;
|
pub mod date;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
pub mod datetime;
|
pub mod datetime;
|
||||||
|
pub mod format;
|
||||||
|
|
||||||
/// The day of week (DOW).
|
/// The day of week (DOW).
|
||||||
///
|
///
|
||||||
|
|
|
@ -13,6 +13,7 @@ use {Weekday, Datelike};
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
use naive::time::NaiveTime;
|
use naive::time::NaiveTime;
|
||||||
use naive::datetime::NaiveDateTime;
|
use naive::datetime::NaiveDateTime;
|
||||||
|
use format::DelayedFormat;
|
||||||
|
|
||||||
use self::internals::{DateImpl, Of, Mdf, YearFlags};
|
use self::internals::{DateImpl, Of, Mdf, YearFlags};
|
||||||
|
|
||||||
|
@ -296,6 +297,13 @@ impl NaiveDate {
|
||||||
pub fn pred_opt(&self) -> Option<NaiveDate> {
|
pub fn pred_opt(&self) -> Option<NaiveDate> {
|
||||||
self.with_of(self.of().pred()).or_else(|| NaiveDate::from_ymd_opt(self.year() - 1, 12, 31))
|
self.with_of(self.of().pred()).or_else(|| NaiveDate::from_ymd_opt(self.year() - 1, 12, 31))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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(Some(self.clone()), None, fmt)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Datelike for NaiveDate {
|
impl Datelike for NaiveDate {
|
||||||
|
@ -736,6 +744,27 @@ mod tests {
|
||||||
assert_eq!(format!("{:+30}", NaiveDate::from_ymd(1234, 5, 6)), "1234-05-06".to_string());
|
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(12345, 6, 7)), "+12345-06-07".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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());
|
||||||
|
|
||||||
|
// 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());
|
||||||
|
assert_eq!(NaiveDate::from_ymd(2010, 1, 3).format("%G,%g,%U,%W,%V").to_string(),
|
||||||
|
"2009,09,01,00,53".to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,6 +13,7 @@ use {Weekday, Timelike, Datelike};
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
use naive::time::NaiveTime;
|
use naive::time::NaiveTime;
|
||||||
use naive::date::NaiveDate;
|
use naive::date::NaiveDate;
|
||||||
|
use format::DelayedFormat;
|
||||||
|
|
||||||
/// ISO 8601 combined date and time without timezone.
|
/// ISO 8601 combined date and time without timezone.
|
||||||
#[deriving(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
|
#[deriving(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
|
||||||
|
@ -77,6 +78,13 @@ impl NaiveDateTime {
|
||||||
let nseconds = self.time.num_seconds_from_midnight() as i64;
|
let nseconds = self.time.num_seconds_from_midnight() as i64;
|
||||||
(ndays - 719163) * 86400 + nseconds
|
(ndays - 719163) * 86400 + nseconds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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> {
|
||||||
|
DelayedFormat::new(Some(self.date.clone()), Some(self.time.clone()), fmt)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Datelike for NaiveDateTime {
|
impl Datelike for NaiveDateTime {
|
||||||
|
@ -247,5 +255,12 @@ mod tests {
|
||||||
assert_eq!(to_timestamp(2001, 9, 9, 1, 46, 40), 1_000_000_000);
|
assert_eq!(to_timestamp(2001, 9, 9, 1, 46, 40), 1_000_000_000);
|
||||||
assert_eq!(to_timestamp(2038, 1, 19, 3, 14, 7), 0x7fffffff);
|
assert_eq!(to_timestamp(2038, 1, 19, 3, 14, 7), 0x7fffffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ use num::Integer;
|
||||||
use Timelike;
|
use Timelike;
|
||||||
use offset::Offset;
|
use offset::Offset;
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
|
use format::DelayedFormat;
|
||||||
|
|
||||||
/// ISO 8601 time without timezone.
|
/// ISO 8601 time without timezone.
|
||||||
/// Allows for the nanosecond precision and optional leap second representation.
|
/// Allows for the nanosecond precision and optional leap second representation.
|
||||||
|
@ -115,6 +116,13 @@ impl NaiveTime {
|
||||||
Some(NaiveTime { secs: secs, frac: nano })
|
Some(NaiveTime { secs: secs, frac: nano })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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(None, Some(self.clone()), fmt)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a triple of the hour, minute and second numbers.
|
/// Returns a triple of the hour, minute and second numbers.
|
||||||
fn hms(&self) -> (u32, u32, u32) {
|
fn hms(&self) -> (u32, u32, u32) {
|
||||||
let (mins, sec) = self.secs.div_mod_floor(&60);
|
let (mins, sec) = self.secs.div_mod_floor(&60);
|
||||||
|
@ -350,5 +358,21 @@ mod tests {
|
||||||
assert_eq!(format!("{:30}", NaiveTime::from_hms_milli(3, 5, 7, 9)),
|
assert_eq!(format!("{:30}", NaiveTime::from_hms_milli(3, 5, 7, 9)),
|
||||||
"03:05:07.009".to_string());
|
"03:05:07.009".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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());
|
||||||
|
|
||||||
|
// corner cases
|
||||||
|
assert_eq!(NaiveTime::from_hms(13, 57, 9).format("%r").to_string(),
|
||||||
|
"01:57:09 PM".to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::str::MaybeOwned;
|
||||||
use stdtime;
|
use stdtime;
|
||||||
use num::Integer;
|
use num::Integer;
|
||||||
|
|
||||||
|
@ -214,6 +215,12 @@ pub trait Offset: Clone + fmt::Show {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a name or abbreviation of this offset.
|
||||||
|
fn name(&self) -> MaybeOwned<'static>;
|
||||||
|
|
||||||
|
/// Returns the *current* offset from UTC to the local time.
|
||||||
|
fn local_minus_utc(&self) -> Duration;
|
||||||
|
|
||||||
/// Converts the local `NaiveDate` to the timezone-aware `Date` if possible.
|
/// Converts the local `NaiveDate` to the timezone-aware `Date` if possible.
|
||||||
fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<Self>>;
|
fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<Self>>;
|
||||||
|
|
||||||
|
@ -253,6 +260,9 @@ impl UTC {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Offset for UTC {
|
impl Offset for UTC {
|
||||||
|
fn name(&self) -> MaybeOwned<'static> { "UTC".into_maybe_owned() }
|
||||||
|
fn local_minus_utc(&self) -> Duration { Duration::zero() }
|
||||||
|
|
||||||
fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<UTC>> {
|
fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<UTC>> {
|
||||||
Single(Date::from_utc(local.clone(), UTC))
|
Single(Date::from_utc(local.clone(), UTC))
|
||||||
}
|
}
|
||||||
|
@ -321,6 +331,9 @@ impl FixedOffset {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Offset for FixedOffset {
|
impl Offset for FixedOffset {
|
||||||
|
fn name(&self) -> MaybeOwned<'static> { "UTC".into_maybe_owned() } // XXX
|
||||||
|
fn local_minus_utc(&self) -> Duration { Duration::seconds(self.local_minus_utc) }
|
||||||
|
|
||||||
fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<FixedOffset>> {
|
fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<FixedOffset>> {
|
||||||
Single(Date::from_utc(local.clone(), self.clone()))
|
Single(Date::from_utc(local.clone(), self.clone()))
|
||||||
}
|
}
|
||||||
|
@ -359,7 +372,7 @@ impl fmt::Show for FixedOffset {
|
||||||
/// The local timescale. This is implemented via the standard `time` crate.
|
/// The local timescale. This is implemented via the standard `time` crate.
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
pub struct Local {
|
pub struct Local {
|
||||||
cached: FixedOffset,
|
cached: FixedOffset,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Local {
|
impl Local {
|
||||||
|
@ -410,6 +423,9 @@ impl Local {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Offset for Local {
|
impl Offset for Local {
|
||||||
|
fn name(&self) -> MaybeOwned<'static> { "LMT".into_maybe_owned() } // XXX XXX
|
||||||
|
fn local_minus_utc(&self) -> Duration { self.cached.local_minus_utc() }
|
||||||
|
|
||||||
fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<Local>> {
|
fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<Local>> {
|
||||||
match self.from_local_datetime(&local.and_hms(0, 0, 0)) {
|
match self.from_local_datetime(&local.and_hms(0, 0, 0)) {
|
||||||
NoResult => NoResult,
|
NoResult => NoResult,
|
||||||
|
|
|
@ -12,6 +12,7 @@ use Timelike;
|
||||||
use offset::Offset;
|
use offset::Offset;
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
use naive::time::NaiveTime;
|
use naive::time::NaiveTime;
|
||||||
|
use format::DelayedFormat;
|
||||||
|
|
||||||
/// ISO 8601 time with timezone.
|
/// ISO 8601 time with timezone.
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
|
@ -28,6 +29,13 @@ impl<Off:Offset> Time<Off> {
|
||||||
Time { time: time, offset: offset }
|
Time { time: time, offset: offset }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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.
|
/// Returns a view to the local time.
|
||||||
fn local(&self) -> NaiveTime {
|
fn local(&self) -> NaiveTime {
|
||||||
self.offset.to_local_time(&self.time)
|
self.offset.to_local_time(&self.time)
|
||||||
|
|
Loading…
Reference in New Issue