time.rs 3.8 KB
Newer Older
1
use datetime::{LocalDateTime, TimeZone, DatePiece, TimePiece};
B
Benjamin Sago 已提交
2 3 4
use datetime::fmt::DateFormat;
use locale;

5
use fs::fields::Time;
B
Benjamin Sago 已提交
6 7


B
Benjamin Sago 已提交
8 9
pub enum TimeFormat {
    DefaultFormat(DefaultFormat),
10
    LongISO(LongISO),
B
Benjamin Sago 已提交
11 12 13 14 15 16
}

impl TimeFormat {
    pub fn format_local(&self, time: Time) -> String {
        match *self {
            TimeFormat::DefaultFormat(ref fmt) => fmt.format_local(time),
17
            TimeFormat::LongISO(ref iso)       => iso.format_local(time),
B
Benjamin Sago 已提交
18 19 20 21 22 23
        }
    }

    pub fn format_zoned(&self, time: Time, zone: &TimeZone) -> String {
        match *self {
            TimeFormat::DefaultFormat(ref fmt) => fmt.format_zoned(time, zone),
24
            TimeFormat::LongISO(ref iso)       => iso.format_zoned(time, zone),
B
Benjamin Sago 已提交
25 26 27 28 29
        }
    }
}


B
Benjamin Sago 已提交
30
#[derive(Debug, Clone)]
B
Benjamin Sago 已提交
31
pub struct DefaultFormat {
B
Benjamin Sago 已提交
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46

    /// The year of the current time. This gets used to determine which date
    /// format to use.
    pub current_year: i64,

    /// Localisation rules for formatting timestamps.
    pub locale: locale::Time,

    /// Date format for printing out timestamps that are in the current year.
    pub date_and_time: DateFormat<'static>,

    /// Date format for printing out timestamps that *aren’t*.
    pub date_and_year: DateFormat<'static>,
}

B
Benjamin Sago 已提交
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
impl DefaultFormat {
    pub fn new() -> DefaultFormat {
        use unicode_width::UnicodeWidthStr;

        let locale = locale::Time::load_user_locale()
                       .unwrap_or_else(|_| locale::Time::english());

        let current_year = LocalDateTime::now().year();

        // Some locales use a three-character wide month name (Jan to Dec);
        // others vary between three and four (1月 to 12月). We assume that
        // December is the month with the maximum width, and use the width of
        // that to determine how to pad the other months.
        let december_width = UnicodeWidthStr::width(&*locale.short_month_name(11));
        let date_and_time = match december_width {
            4  => DateFormat::parse("{2>:D} {4>:M} {2>:h}:{02>:m}").unwrap(),
            _  => DateFormat::parse("{2>:D} {:M} {2>:h}:{02>:m}").unwrap(),
        };

        let date_and_year = match december_width {
            4 => DateFormat::parse("{2>:D} {4>:M} {5>:Y}").unwrap(),
            _ => DateFormat::parse("{2>:D} {:M} {5>:Y}").unwrap()
        };

        DefaultFormat { current_year, locale, date_and_time, date_and_year }
    }

B
Benjamin Sago 已提交
74 75 76 77 78
    fn is_recent(&self, date: LocalDateTime) -> bool {
        date.year() == self.current_year
    }

    #[allow(trivial_numeric_casts)]
B
Benjamin Sago 已提交
79
    fn format_local(&self, time: Time) -> String {
80
        let date = LocalDateTime::at(time.seconds as i64);
B
Benjamin Sago 已提交
81 82 83 84 85 86 87 88 89 90

        if self.is_recent(date) {
            self.date_and_time.format(&date, &self.locale)
        }
        else {
            self.date_and_year.format(&date, &self.locale)
        }
    }

    #[allow(trivial_numeric_casts)]
B
Benjamin Sago 已提交
91
    fn format_zoned(&self, time: Time, zone: &TimeZone) -> String {
92
        let date = zone.to_zoned(LocalDateTime::at(time.seconds as i64));
B
Benjamin Sago 已提交
93 94 95 96 97 98 99 100 101

        if self.is_recent(date) {
            self.date_and_time.format(&date, &self.locale)
        }
        else {
            self.date_and_year.format(&date, &self.locale)
        }
    }
}
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120


pub struct LongISO;

impl LongISO {
    #[allow(trivial_numeric_casts)]
    fn format_local(&self, time: Time) -> String {
        let date = LocalDateTime::at(time.seconds as i64);
        format!("{:04}-{:02}-{:02} {:02}:{:02}",
                date.year(), date.month() as usize, date.day(), date.hour(), date.minute())
    }

    #[allow(trivial_numeric_casts)]
    fn format_zoned(&self, time: Time, zone: &TimeZone) -> String {
        let date = zone.to_zoned(LocalDateTime::at(time.seconds as i64));
        format!("{:04}-{:02}-{:02} {:02}:{:02}",
                date.year(), date.month() as usize, date.day(), date.hour(), date.minute())
    }
}