From 932e29aa9472dfe1fa71ec7a51922b0972cbac18 Mon Sep 17 00:00:00 2001 From: Kang Seonghoon Date: Mon, 1 Aug 2016 01:02:32 +0900 Subject: [PATCH] Better documentation and cross-references for naive types. --- AUTHORS.txt | 1 + Makefile | 28 +++ README.md | 2 +- src/lib.rs | 23 ++- src/naive/date.rs | 504 +++++++++++++++++++++++++++++++++++++++------- src/naive/time.rs | 280 ++++++++++++++++++++------ 6 files changed, 703 insertions(+), 135 deletions(-) diff --git a/AUTHORS.txt b/AUTHORS.txt index 8891787..7467bcd 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -18,6 +18,7 @@ John Nagle Ken Tossell Martin Risell Lilja Ryan Lewis +Sergey V. Galtsev Steve Klabnik Tom Gallacher klutzy diff --git a/Makefile b/Makefile index a614931..c716d74 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,6 @@ +# this Makefile is mostly for the packaging convenience. +# casual users should use `cargo` to retrieve the appropriate version of Chrono. + .PHONY: all all: @echo 'Try `cargo build` instead.' @@ -30,3 +33,28 @@ README.md: src/lib.rs awk '/^\/\/! ## /,!/^\/\/!/' $< | cut -b 5- | grep -v '^# ' | \ sed 's/](\.\//](https:\/\/lifthrasiir.github.io\/rust-chrono\/chrono\//g' >> $@ +.PHONY: test +test: + cargo test --features 'serde rustc-serialize' + +.PHONY: doc +doc: authors readme + cargo doc --features 'serde rustc-serialize' + +.PHONY: doc-publish +doc-publish: doc + ( \ + PKGID="$$(cargo pkgid)"; \ + PKGNAMEVER="$${PKGID#*#}"; \ + PKGNAME="$${PKGNAMEVER%:*}"; \ + REMOTE="$$(git config --get remote.origin.url)"; \ + cd target/doc && \ + rm -rf .git && \ + git init && \ + git checkout --orphan gh-pages && \ + echo '' > index.html && \ + git add . && \ + git commit -m 'updated docs.' && \ + git push "$$REMOTE" gh-pages -f; \ + ) + diff --git a/README.md b/README.md index f78167d..4ac00c2 100644 --- a/README.md +++ b/README.md @@ -307,7 +307,7 @@ Date types are limited in about +/- 262,000 years from the common epoch. Time types are limited in the nanosecond accuracy. [Leap seconds are supported in the representation but -Chrono doesn't try to make use of them](https://lifthrasiir.github.io/rust-chrono/chrono/naive/time/struct.NaiveTime.html#leap-second-what). +Chrono doesn't try to make use of them](https://lifthrasiir.github.io/rust-chrono/chrono/naive/time/index.html#leap-second-handling). (The main reason is that leap seconds are not really predictable.) Almost *every* operation over the possible leap seconds will ignore them. Consider using `NaiveDateTime` with the implicit TAI (International Atomic Time) scale diff --git a/src/lib.rs b/src/lib.rs index 2cca774..11785e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -307,7 +307,7 @@ //! Time types are limited in the nanosecond accuracy. //! //! [Leap seconds are supported in the representation but -//! Chrono doesn't try to make use of them](./naive/time/struct.NaiveTime.html#leap-second-what). +//! Chrono doesn't try to make use of them](./naive/time/index.html#leap-second-handling). //! (The main reason is that leap seconds are not really predictable.) //! Almost *every* operation over the possible leap seconds will ignore them. //! Consider using `NaiveDateTime` with the implicit TAI (International Atomic Time) scale @@ -516,7 +516,7 @@ impl num::traits::FromPrimitive for Weekday { /// The common set of methods for date component. pub trait Datelike: Sized { - /// Returns the year number. + /// Returns the year number in the [calendar date](./naive/date/index.html#calendar-date). fn year(&self) -> i32; /// Returns the absolute year number starting from 1 with a boolean flag, @@ -532,21 +532,33 @@ pub trait Datelike: Sized { } /// Returns the month number starting from 1. + /// + /// The return value ranges from 1 to 12. fn month(&self) -> u32; /// Returns the month number starting from 0. + /// + /// The return value ranges from 0 to 11. fn month0(&self) -> u32; /// Returns the day of month starting from 1. + /// + /// The return value ranges from 1 to 31. (The last day of month differs by months.) fn day(&self) -> u32; /// Returns the day of month starting from 0. + /// + /// The return value ranges from 0 to 30. (The last day of month differs by months.) fn day0(&self) -> u32; /// Returns the day of year starting from 1. + /// + /// The return value ranges from 1 to 366. (The last day of year differs by years.) fn ordinal(&self) -> u32; /// Returns the day of year starting from 0. + /// + /// The return value ranges from 0 to 365. (The last day of year differs by years.) fn ordinal0(&self) -> u32; /// Returns the day of week. @@ -631,7 +643,8 @@ pub trait Timelike: Sized { fn second(&self) -> u32; /// Returns the number of nanoseconds since the whole non-leap second. - /// The range from 1,000,000,000 to 1,999,999,999 represents the leap second. + /// The range from 1,000,000,000 to 1,999,999,999 represents + /// the [leap second](./naive/time/index.html#leap-second-handling). fn nanosecond(&self) -> u32; /// Makes a new value with the hour number changed. @@ -647,11 +660,15 @@ pub trait Timelike: Sized { /// Makes a new value with the second number changed. /// /// Returns `None` when the resulting value would be invalid. + /// As with the [`second`](#tymethod.second) method, + /// the input range is restricted to 0 through 59. fn with_second(&self, sec: u32) -> Option; /// Makes a new value with nanoseconds since the whole non-leap second changed. /// /// Returns `None` when the resulting value would be invalid. + /// As with the [`nanosecond`](#tymethod.nanosecond) method, + /// the input range can exceed 1,000,000,000 for leap seconds. fn with_nanosecond(&self, nano: u32) -> Option; /// Returns the number of non-leap seconds past the last midnight. diff --git a/src/naive/date.rs b/src/naive/date.rs index 2bcbf03..30a2b62 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -2,9 +2,50 @@ // Copyright (c) 2014-2015, Kang Seonghoon. // See README.md and LICENSE.txt for details. -/*! - * ISO 8601 calendar date without timezone. - */ +//! ISO 8601 calendar date without timezone. +//! +//! # Calendar Date +//! +//! The ISO 8601 **calendar date** follows the proleptic Gregorian calendar. +//! It is like a normal civil calendar but note some slight differences: +//! +//! * Dates before the Gregorian calendar's inception in 1582 are defined via the extrapolation. +//! Be careful, as historical dates are often noted in the Julian calendar and others +//! and the transition to Gregorian may differ across countries (as late as early 20C). +//! +//! (Some example: Both Shakespeare from Britain and Cervantes from Spain seemingly died +//! on the same calendar date---April 23, 1616---but in the different calendar. +//! Britain used the Julian calendar at that time, so Shakespeare's death is later.) +//! +//! * ISO 8601 calendars has the year 0, which is 1 BCE (a year before 1 CE). +//! If you need a typical BCE/BC and CE/AD notation for year numbers, +//! use the [`Datelike::year_ce`](../../trait.Datelike.html#method.year_ce) method. +//! +//! # Week Date +//! +//! The ISO 8601 **week date** is a triple of year number, week number +//! and [day of the week](../../enum.Weekday.html) with the following rules: +//! +//! * A week consists of Monday through Sunday, and is always numbered within some year. +//! The week number ranges from 1 to 52 or 53 depending on the year. +//! +//! * The week 1 of given year is defined as the first week containing January 4 of that year, +//! or equivalently, the first week containing four or more days in that year. +//! +//! * The year number in the week date may *not* correspond to the actual Gregorian year. +//! For example, January 3, 2016 (Sunday) was on the last (53rd) week of 2015. +//! +//! Chrono's date types default to the ISO 8601 [calendar date](#calendar-date), +//! but the [`Datelike::isoweekdate`](../../trait.Datelike.html#tymethod.isoweekdate) method +//! can be used to get the corresponding week date. +//! +//! # Ordinal Date +//! +//! The ISO 8601 **ordinal date** is a pair of year number and day of the year ("ordinal"). +//! The ordinal number ranges from 1 to 365 or 366 depending on the year. +//! The year number is same to that of the [calendar date](#calendar-date). +//! +//! This is currently the internal format of Chrono's date types. use std::{str, fmt, hash}; use std::ops::{Add, Sub}; @@ -46,7 +87,8 @@ const MIN_DAYS_FROM_YEAR_0: i32 = (MIN_YEAR + 400_000) * 365 + (MIN_YEAR + 400_000) / 400 - 146097_000; /// ISO 8601 calendar date without timezone. -/// Allows for every proleptic Gregorian date from Jan 1, 262145 BCE to Dec 31, 262143 CE. +/// Allows for every [proleptic Gregorian date](./index.html#calendar-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)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] @@ -54,9 +96,9 @@ pub struct NaiveDate { ymdf: DateImpl, // (year << 13) | of } -/// The minimum possible `NaiveDate`. +/// The minimum possible `NaiveDate` (January 1, 262145 BCE). pub const MIN: NaiveDate = NaiveDate { ymdf: (MIN_YEAR << 13) | (1 << 4) | 0o07 /*FE*/ }; -/// The maximum possible `NaiveDate`. +/// The maximum possible `NaiveDate` (December 31, 262143 CE). pub const MAX: NaiveDate = NaiveDate { ymdf: (MAX_YEAR << 13) | (365 << 4) | 0o17 /*F*/ }; // as it is hard to verify year flags in `MIN` and `MAX`, we use a separate run-time test. @@ -86,8 +128,8 @@ impl NaiveDate { NaiveDate::from_of(year, mdf.to_of()) } - /// Makes a new `NaiveDate` from year, month and day. - /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. + /// Makes a new `NaiveDate` from the [calendar date](./index.html#calendar-date) + /// (year, month and day). /// /// Panics on the out-of-range date, invalid month and/or day. /// @@ -108,8 +150,8 @@ impl NaiveDate { NaiveDate::from_ymd_opt(year, month, day).expect("invalid or out-of-range date") } - /// Makes a new `NaiveDate` from year, month and day. - /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. + /// Makes a new `NaiveDate` from the [calendar date](./index.html#calendar-date) + /// (year, month and day). /// /// Returns `None` on the out-of-range date, invalid month and/or day. /// @@ -131,10 +173,10 @@ impl NaiveDate { NaiveDate::from_mdf(year, Mdf::new(month, day, flags)) } - /// Makes a new `NaiveDate` from year and day of year (DOY or "ordinal"). - /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. + /// Makes a new `NaiveDate` from the [ordinal date](./index.html#ordinal-date) + /// (year and day of the year). /// - /// Panics on the out-of-range date and/or invalid DOY. + /// Panics on the out-of-range date and/or invalid day of year. /// /// # Example /// @@ -153,10 +195,10 @@ impl NaiveDate { NaiveDate::from_yo_opt(year, ordinal).expect("invalid or out-of-range date") } - /// Makes a new `NaiveDate` from year and day of year (DOY or "ordinal"). - /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. + /// Makes a new `NaiveDate` from the [ordinal date](./index.html#ordinal-date) + /// (year and day of the year). /// - /// Returns `None` on the out-of-range date and/or invalid DOY. + /// Returns `None` on the out-of-range date and/or invalid day of year. /// /// # Example /// @@ -177,8 +219,8 @@ impl NaiveDate { NaiveDate::from_of(year, Of::new(ordinal, flags)) } - /// Makes a new `NaiveDate` from ISO week date (year and week number) and day of the week (DOW). - /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. + /// Makes a new `NaiveDate` from the [ISO week date](./index.html#week-date) + /// (year, week number and day of the week). /// The resulting `NaiveDate` may have a different year from the input year. /// /// Panics on the out-of-range date and/or invalid week number. @@ -200,8 +242,8 @@ impl NaiveDate { NaiveDate::from_isoywd_opt(year, week, weekday).expect("invalid or out-of-range date") } - /// Makes a new `NaiveDate` from ISO week date (year and week number) and day of the week (DOW). - /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. + /// Makes a new `NaiveDate` from the [ISO week date](./index.html#week-date) + /// (year, week number and day of the week). /// The resulting `NaiveDate` may have a different year from the input year. /// /// Returns `None` on the out-of-range date and/or invalid week number. @@ -219,12 +261,16 @@ impl NaiveDate { /// assert_eq!(isoywd(2015, 30, Weekday::Mon), Some(ymd(2015, 7, 20))); /// assert_eq!(isoywd(2015, 60, Weekday::Mon), None); /// - /// // out-of-range dates /// assert_eq!(isoywd(400000, 10, Weekday::Fri), None); /// assert_eq!(isoywd(-400000, 10, Weekday::Sat), None); + /// ~~~~ /// - /// // year boundary behaviors - /// // + /// The year number of ISO week date may differ from that of the calendar date. + /// + /// ~~~~ + /// # use chrono::{NaiveDate, Weekday}; + /// # let ymd = |y,m,d| NaiveDate::from_ymd(y, m, d); + /// # let isoywd = |y,w,d| NaiveDate::from_isoywd_opt(y, w, d); /// // Mo Tu We Th Fr Sa Su /// // 2014-W52 22 23 24 25 26 27 28 has 4+ days of new year, /// // 2015-W01 29 30 31 1 2 3 4 <- so this is the first week @@ -284,6 +330,29 @@ impl NaiveDate { /// assert_eq!(d.ordinal(), 73); // day of year /// assert_eq!(d.isoweekdate(), (2015, 11, Weekday::Sat)); // ISO week and weekday /// ~~~~ + /// + /// While not directly supported by Chrono, + /// it is easy to convert from the Julian day number + /// (January 1, 4713 BCE in the *Julian* calendar being Day 0) + /// to Gregorian with this method. + /// (Note that this panics when `jd` is out of range.) + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// fn jd_to_date(jd: i32) -> NaiveDate { + /// // keep in mind that the Julian day number is 0-based + /// // while this method requires an 1-based number. + /// NaiveDate::from_num_days_from_ce(jd - 1721425) + /// } + /// + /// // January 1, 4713 BCE in Julian = November 24, 4714 BCE in Gregorian + /// assert_eq!(jd_to_date(0), NaiveDate::from_ymd(-4713, 11, 24)); + /// + /// assert_eq!(jd_to_date(1721426), NaiveDate::from_ymd(1, 1, 1)); + /// assert_eq!(jd_to_date(2450000), NaiveDate::from_ymd(1995, 10, 9)); + /// assert_eq!(jd_to_date(2451545), NaiveDate::from_ymd(2000, 1, 1)); + /// ~~~~ #[inline] pub fn from_num_days_from_ce(days: i32) -> NaiveDate { NaiveDate::from_num_days_from_ce_opt(days).expect("out-of-range date") @@ -380,7 +449,7 @@ impl NaiveDate { /// Makes a new `NaiveDateTime` from the current date, hour, minute and second. /// - /// No [leap second](../time/struct.NaiveTime.html#leap-second-what?) is allowed here; + /// No [leap second](../time/index.html#leap-second-handling) is allowed here; /// use `NaiveDate::and_hms_*` methods with a subsecond parameter instead. /// /// Panics on invalid hour, minute and/or second. @@ -404,7 +473,7 @@ impl NaiveDate { /// Makes a new `NaiveDateTime` from the current date, hour, minute and second. /// - /// No [leap second](../time/struct.NaiveTime.html#leap-second-what?) is allowed here; + /// No [leap second](../time/index.html#leap-second-handling) is allowed here; /// use `NaiveDate::and_hms_*_opt` methods with a subsecond parameter instead. /// /// Returns `None` on invalid hour, minute and/or second. @@ -428,7 +497,7 @@ impl NaiveDate { /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and millisecond. /// /// The millisecond part can exceed 1,000 - /// in order to represent the [leap second](../time/struct.NaiveTime.html#leap-second-what?). + /// in order to represent the [leap second](../time/index.html#leap-second-handling). /// /// Panics on invalid hour, minute, second and/or millisecond. /// @@ -453,7 +522,7 @@ impl NaiveDate { /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and millisecond. /// /// The millisecond part can exceed 1,000 - /// in order to represent the [leap second](../time/struct.NaiveTime.html#leap-second-what?). + /// in order to represent the [leap second](../time/index.html#leap-second-handling). /// /// Returns `None` on invalid hour, minute, second and/or millisecond. /// @@ -479,7 +548,7 @@ impl NaiveDate { /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and microsecond. /// /// The microsecond part can exceed 1,000,000 - /// in order to represent the [leap second](../time/struct.NaiveTime.html#leap-second-what?). + /// in order to represent the [leap second](../time/index.html#leap-second-handling). /// /// Panics on invalid hour, minute, second and/or microsecond. /// @@ -504,7 +573,7 @@ impl NaiveDate { /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and microsecond. /// /// The microsecond part can exceed 1,000,000 - /// in order to represent the [leap second](../time/struct.NaiveTime.html#leap-second-what?). + /// in order to represent the [leap second](../time/index.html#leap-second-handling). /// /// Returns `None` on invalid hour, minute, second and/or microsecond. /// @@ -530,7 +599,7 @@ impl NaiveDate { /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and nanosecond. /// /// The nanosecond part can exceed 1,000,000,000 - /// in order to represent the [leap second](../time/struct.NaiveTime.html#leap-second-what?). + /// in order to represent the [leap second](../time/index.html#leap-second-handling). /// /// Panics on invalid hour, minute, second and/or nanosecond. /// @@ -555,7 +624,7 @@ impl NaiveDate { /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and nanosecond. /// /// The nanosecond part can exceed 1,000,000,000 - /// in order to represent the [leap second](../time/struct.NaiveTime.html#leap-second-what?). + /// in order to represent the [leap second](../time/index.html#leap-second-handling). /// /// Returns `None` on invalid hour, minute, second and/or nanosecond. /// @@ -611,7 +680,7 @@ impl NaiveDate { } } - /// Makes a new `NaiveDate` for the next date. + /// Makes a new `NaiveDate` for the next calendar date. /// /// Panics when `self` is the last representable date. /// @@ -629,7 +698,7 @@ impl NaiveDate { self.succ_opt().expect("out of bound") } - /// Makes a new `NaiveDate` for the next date. + /// Makes a new `NaiveDate` for the next calendar date. /// /// Returns `None` when `self` is the last representable date. /// @@ -648,7 +717,7 @@ impl NaiveDate { self.with_of(self.of().succ()).or_else(|| NaiveDate::from_ymd_opt(self.year() + 1, 1, 1)) } - /// Makes a new `NaiveDate` for the prior date. + /// Makes a new `NaiveDate` for the previous calendar date. /// /// Panics when `self` is the first representable date. /// @@ -666,7 +735,7 @@ impl NaiveDate { self.pred_opt().expect("out of bound") } - /// Makes a new `NaiveDate` for the prior date. + /// Makes a new `NaiveDate` for the previous calendar date. /// /// Returns `None` when `self` is the first representable date. /// @@ -800,14 +869,182 @@ impl NaiveDate { } impl Datelike for NaiveDate { - #[inline] fn year(&self) -> i32 { self.ymdf >> 13 } - #[inline] fn month(&self) -> u32 { self.mdf().month() } - #[inline] fn month0(&self) -> u32 { self.mdf().month() - 1 } - #[inline] fn day(&self) -> u32 { self.mdf().day() } - #[inline] fn day0(&self) -> u32 { self.mdf().day() - 1 } - #[inline] fn ordinal(&self) -> u32 { self.of().ordinal() } - #[inline] fn ordinal0(&self) -> u32 { self.of().ordinal() - 1 } - #[inline] fn weekday(&self) -> Weekday { self.of().weekday() } + /// Returns the year number in the [calendar date](./index.html#calendar-date). + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).year(), 2015); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).year(), -308); // 309 BCE + /// ~~~~ + #[inline] + fn year(&self) -> i32 { + self.ymdf >> 13 + } + + /// Returns the month number starting from 1. + /// + /// The return value ranges from 1 to 12. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).month(), 9); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).month(), 3); + /// ~~~~ + #[inline] + fn month(&self) -> u32 { + self.mdf().month() + } + + /// Returns the month number starting from 0. + /// + /// The return value ranges from 0 to 11. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).month0(), 8); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).month0(), 2); + /// ~~~~ + #[inline] + fn month0(&self) -> u32 { + self.mdf().month() - 1 + } + + /// Returns the day of month starting from 1. + /// + /// The return value ranges from 1 to 31. (The last day of month differs by months.) + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).day(), 8); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).day(), 14); + /// ~~~~ + /// + /// Combined with [`NaiveDate::pred`](./struct.NaiveDate.html#method.pred), + /// one can determine the number of days in a particular month. + /// (Note that this panics when `year` is out of range.) + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// fn ndays_in_month(year: i32, month: u32) -> u32 { + /// // the first day of the next month... + /// let (y, m) = if month == 12 { (year + 1, 1) } else { (year, month + 1) }; + /// let d = NaiveDate::from_ymd(y, m, 1); + /// + /// // ...is preceded by the last day of the original month + /// d.pred().day() + /// } + /// + /// assert_eq!(ndays_in_month(2015, 8), 31); + /// assert_eq!(ndays_in_month(2015, 9), 30); + /// assert_eq!(ndays_in_month(2015, 12), 31); + /// assert_eq!(ndays_in_month(2016, 2), 29); + /// assert_eq!(ndays_in_month(2017, 2), 28); + /// ~~~~ + #[inline] + fn day(&self) -> u32 { + self.mdf().day() + } + + /// Returns the day of month starting from 0. + /// + /// The return value ranges from 0 to 30. (The last day of month differs by months.) + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).day0(), 7); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).day0(), 13); + /// ~~~~ + #[inline] + fn day0(&self) -> u32 { + self.mdf().day() - 1 + } + + /// Returns the day of year starting from 1. + /// + /// The return value ranges from 1 to 366. (The last day of year differs by years.) + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).ordinal(), 251); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).ordinal(), 74); + /// ~~~~ + /// + /// Combined with [`NaiveDate::pred`](./struct.NaiveDate.html#method.pred), + /// one can determine the number of days in a particular year. + /// (Note that this panics when `year` is out of range.) + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// fn ndays_in_year(year: i32) -> u32 { + /// // the first day of the next year... + /// let d = NaiveDate::from_ymd(year + 1, 1, 1); + /// + /// // ...is preceded by the last day of the original year + /// d.pred().ordinal() + /// } + /// + /// assert_eq!(ndays_in_year(2015), 365); + /// assert_eq!(ndays_in_year(2016), 366); + /// assert_eq!(ndays_in_year(2017), 365); + /// assert_eq!(ndays_in_year(2000), 366); + /// assert_eq!(ndays_in_year(2100), 365); + /// ~~~~ + #[inline] + fn ordinal(&self) -> u32 { + self.of().ordinal() + } + + /// Returns the day of year starting from 0. + /// + /// The return value ranges from 0 to 365. (The last day of year differs by years.) + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).ordinal0(), 250); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).ordinal0(), 73); + /// ~~~~ + #[inline] + fn ordinal0(&self) -> u32 { + self.of().ordinal() - 1 + } + + /// Returns the day of week. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike, Weekday}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).weekday(), Weekday::Tue); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).weekday(), Weekday::Fri); + /// ~~~~ + #[inline] + fn weekday(&self) -> Weekday { + self.of().weekday() + } fn isoweekdate(&self) -> (i32, u32, Weekday) { let of = self.of(); @@ -826,6 +1063,28 @@ impl Datelike for NaiveDate { } } + /// Makes a new `NaiveDate` with the year number changed. + /// + /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_year(2016), + /// Some(NaiveDate::from_ymd(2016, 9, 8))); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_year(-308), + /// Some(NaiveDate::from_ymd(-308, 9, 8))); + /// ~~~~ + /// + /// A leap day (February 29) is a good example that this method can return `None`. + /// + /// ~~~~ + /// # use chrono::{NaiveDate, Datelike}; + /// assert!(NaiveDate::from_ymd(2016, 2, 29).with_year(2015).is_none()); + /// assert!(NaiveDate::from_ymd(2016, 2, 29).with_year(2020).is_some()); + /// ~~~~ #[inline] fn with_year(&self, year: i32) -> Option { // we need to operate with `mdf` since we should keep the month and day number as is @@ -838,46 +1097,138 @@ impl Datelike for NaiveDate { NaiveDate::from_mdf(year, mdf) } + /// Makes a new `NaiveDate` with the month number (starting from 1) changed. + /// + /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month(10), + /// Some(NaiveDate::from_ymd(2015, 10, 8))); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month(13), None); // no month 13 + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 30).with_month(2), None); // no February 30 + /// ~~~~ #[inline] fn with_month(&self, month: u32) -> Option { self.with_mdf(self.mdf().with_month(month)) } + /// Makes a new `NaiveDate` with the month number (starting from 0) changed. + /// + /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month0(9), + /// Some(NaiveDate::from_ymd(2015, 10, 8))); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month0(12), None); // no month 13 + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 30).with_month0(1), None); // no February 30 + /// ~~~~ #[inline] fn with_month0(&self, month0: u32) -> Option { self.with_mdf(self.mdf().with_month(month0 + 1)) } + /// Makes a new `NaiveDate` with the day of month (starting from 1) changed. + /// + /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day(30), + /// Some(NaiveDate::from_ymd(2015, 9, 30))); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day(31), + /// None); // no September 31 + /// ~~~~ #[inline] fn with_day(&self, day: u32) -> Option { self.with_mdf(self.mdf().with_day(day)) } + /// Makes a new `NaiveDate` with the day of month (starting from 0) changed. + /// + /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day0(29), + /// Some(NaiveDate::from_ymd(2015, 9, 30))); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day0(30), + /// None); // no September 31 + /// ~~~~ #[inline] fn with_day0(&self, day0: u32) -> Option { self.with_mdf(self.mdf().with_day(day0 + 1)) } + /// Makes a new `NaiveDate` with the day of year (starting from 1) changed. + /// + /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal(60), + /// Some(NaiveDate::from_ymd(2015, 3, 1))); + /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1).with_ordinal(60), + /// Some(NaiveDate::from_ymd(2016, 2, 29))); + /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal(366), + /// None); // 2015 had only 365 days + /// ~~~~ #[inline] fn with_ordinal(&self, ordinal: u32) -> Option { self.with_of(self.of().with_ordinal(ordinal)) } + /// Makes a new `NaiveDate` with the day of year (starting from 0) changed. + /// + /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal0(59), + /// Some(NaiveDate::from_ymd(2015, 3, 1))); + /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1).with_ordinal0(59), + /// Some(NaiveDate::from_ymd(2016, 2, 29))); + /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal0(365), + /// None); // 2015 had only 365 days + /// ~~~~ #[inline] fn with_ordinal0(&self, ordinal0: u32) -> Option { self.with_of(self.of().with_ordinal(ordinal0 + 1)) } } +/// `NaiveDate` can be used as a key to the hash maps. impl hash::Hash for NaiveDate { - fn hash(&self, state: &mut H) { self.ymdf.hash(state) } + fn hash(&self, state: &mut H) { + // don't need to strip flags, as we can safely assume that it is correct + self.ymdf.hash(state); + } } /// An addition of `Duration` to `NaiveDate` discards the fractional days, /// rounding to the closest integral number of days towards `Duration::zero()`. /// /// Panics on underflow or overflow. -/// Use `NaiveDate::checked_add` for detecting that. +/// Use [`NaiveDate::checked_add`](#method.checked_add) to detect that. /// /// # Example /// @@ -903,8 +1254,10 @@ impl Add for NaiveDate { } } -/// A subtraction of `NaiveDate` from `NaiveDate` yields a `Duration` of integral numbers, -/// and does not overflow or underflow at all. +/// A subtraction of `NaiveDate` from `NaiveDate` yields a `Duration` of integral numbers. +/// +/// This does not overflow or underflow at all, +/// as all possible output fits in the range of `Duration`. /// /// # Example /// @@ -938,7 +1291,7 @@ impl Sub for NaiveDate { /// rounding to the closest integral number of days towards `Duration::zero()`. /// /// Panics on underflow or overflow. -/// Use `NaiveDate::checked_sub` for detecting that. +/// Use [`NaiveDate::checked_sub`](#method.checked_sub) to detect that. /// /// # Example /// @@ -965,7 +1318,6 @@ impl Sub for NaiveDate { } /// The `Debug` output of the naive date `d` is same to `d.format("%Y-%m-%d")`. -/// Note that ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE. /// /// The string printed can be readily parsed via the `parse` method on `str`. /// @@ -977,8 +1329,12 @@ impl Sub for NaiveDate { /// assert_eq!(format!("{:?}", NaiveDate::from_ymd(2015, 9, 5)), "2015-09-05"); /// assert_eq!(format!("{:?}", NaiveDate::from_ymd( 0, 1, 1)), "0000-01-01"); /// assert_eq!(format!("{:?}", NaiveDate::from_ymd(9999, 12, 31)), "9999-12-31"); +/// ~~~~ /// -/// // examples of an explicit year sign +/// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE. +/// +/// ~~~~ +/// # use chrono::NaiveDate; /// assert_eq!(format!("{:?}", NaiveDate::from_ymd( -1, 1, 1)), "-0001-01-01"); /// assert_eq!(format!("{:?}", NaiveDate::from_ymd(10000, 12, 31)), "+10000-12-31"); /// ~~~~ @@ -996,7 +1352,6 @@ impl fmt::Debug for NaiveDate { } /// The `Display` output of the naive date `d` is same to `d.format("%Y-%m-%d")`. -/// Note that ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE. /// /// The string printed can be readily parsed via the `parse` method on `str`. /// @@ -1008,8 +1363,12 @@ impl fmt::Debug for NaiveDate { /// assert_eq!(format!("{}", NaiveDate::from_ymd(2015, 9, 5)), "2015-09-05"); /// assert_eq!(format!("{}", NaiveDate::from_ymd( 0, 1, 1)), "0000-01-01"); /// assert_eq!(format!("{}", NaiveDate::from_ymd(9999, 12, 31)), "9999-12-31"); +/// ~~~~ /// -/// // examples of an explicit year sign +/// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE. +/// +/// ~~~~ +/// # use chrono::NaiveDate; /// assert_eq!(format!("{}", NaiveDate::from_ymd( -1, 1, 1)), "-0001-01-01"); /// assert_eq!(format!("{}", NaiveDate::from_ymd(10000, 12, 31)), "+10000-12-31"); /// ~~~~ @@ -1095,9 +1454,6 @@ mod tests { use duration::Duration; use std::{i32, u32}; - // TODO replace with range notion and adapters - use num::iter::{range_inclusive, range_step_inclusive}; - #[test] fn test_date_from_ymd() { let ymd_opt = |y,m,d| NaiveDate::from_ymd_opt(y, m, d); @@ -1175,8 +1531,8 @@ mod tests { #[test] fn test_date_from_isoymd_and_isoweekdate() { - for year in range_inclusive(2000i32, 2400) { - for week in range_inclusive(1u32, 53) { + for year in 2000..2401 { + for week in 1..54 { for &weekday in [Weekday::Mon, Weekday::Tue, Weekday::Wed, Weekday::Thu, Weekday::Fri, Weekday::Sat, Weekday::Sun].iter() { let d = NaiveDate::from_isoywd_opt(year, week, weekday); @@ -1192,9 +1548,9 @@ mod tests { } } - for year in range_inclusive(2000i32, 2400) { - for month in range_inclusive(1u32, 12) { - for day in range_inclusive(1u32, 31) { + for year in 2000..2401 { + for month in 1..13 { + for day in 1..32 { let d = NaiveDate::from_ymd_opt(year, month, day); if d.is_some() { let d = d.unwrap(); @@ -1228,7 +1584,7 @@ mod tests { assert_eq!(from_ndays_from_ce(-365), Some(NaiveDate::from_ymd(0, 1, 1))); assert_eq!(from_ndays_from_ce(-366), Some(NaiveDate::from_ymd(-1, 12, 31))); // 2 BCE - for days in range_step_inclusive(-999900i32, 1000000, 100) { + for days in (-9999..10001).map(|x| x * 100) { assert_eq!(from_ndays_from_ce(days).map(|d| d.num_days_from_ce()), Some(days)); } @@ -1328,7 +1684,7 @@ mod tests { fn test_date_num_days_from_ce() { assert_eq!(NaiveDate::from_ymd(1, 1, 1).num_days_from_ce(), 1); - for year in range_inclusive(-9999i32, 10000) { + for year in -9999..10001 { assert_eq!(NaiveDate::from_ymd(year, 1, 1).num_days_from_ce(), NaiveDate::from_ymd(year - 1, 12, 31).num_days_from_ce() + 1); } @@ -1539,19 +1895,17 @@ mod tests { } } -/** - * The internal implementation of the calendar and ordinal date. - * - * The current implementation is optimized for determining year, month, day and day of week. - * 4-bit `YearFlags` map to one of 14 possible classes of year in the Gregorian calendar, - * which are included in every packed `NaiveDate` instance. - * The conversion between the packed calendar date (`Mdf`) and the ordinal date (`Of`) is - * based on the moderately-sized lookup table (~1.5KB) - * and the packed representation is chosen for the efficient lookup. - * Every internal data structure does not validate its input, - * but the conversion keeps the valid value valid and the invalid value invalid - * so that the user-facing `NaiveDate` can validate the input as late as possible. - */ +/// The internal implementation of the calendar and ordinal date. +/// +/// The current implementation is optimized for determining year, month, day and day of week. +/// 4-bit `YearFlags` map to one of 14 possible classes of year in the Gregorian calendar, +/// which are included in every packed `NaiveDate` instance. +/// The conversion between the packed calendar date (`Mdf`) and the ordinal date (`Of`) is +/// based on the moderately-sized lookup table (~1.5KB) +/// and the packed representation is chosen for the efficient lookup. +/// Every internal data structure does not validate its input, +/// but the conversion keeps the valid value valid and the invalid value invalid +/// so that the user-facing `NaiveDate` can validate the input as late as possible. #[allow(dead_code)] // some internal methods have been left for consistency mod internals { use std::{i32, fmt}; diff --git a/src/naive/time.rs b/src/naive/time.rs index 6537c55..0c534cd 100644 --- a/src/naive/time.rs +++ b/src/naive/time.rs @@ -2,9 +2,45 @@ // Copyright (c) 2014-2015, Kang Seonghoon. // See README.md and LICENSE.txt for details. -/*! - * ISO 8601 time without timezone. - */ +//! ISO 8601 time without timezone. +//! +//! # Leap Second Handling +//! +//! Since 1960s, the manmade atomic clock has been so accurate that +//! it is much more accurate than Earth's own motion. +//! It became desirable to define the civil time in terms of the atomic clock, +//! but that risks the desynchronization of the civil time from Earth. +//! To account for this, the designers of the Coordinated Universal Time (UTC) +//! made that the UTC should be kept within 0.9 seconds of the observed Earth-bound time. +//! When the mean solar day is longer than the ideal (86,400 seconds), +//! the error slowly accumulates and it is necessary to add a **leap second** +//! to slow the UTC down a bit. +//! (We may also remove a second to speed the UTC up a bit, but it never happened.) +//! The leap second, if any, follows 23:59:59 of June 30 or December 31 in the UTC. +//! +//! Fast forward to the 21st century, +//! we have seen 26 leap seconds from January 1972 to December 2015. +//! Yes, 26 seconds. Probably you can read this paragraph within 26 seconds. +//! But those 26 seconds, and possibly more in the future, are never predictable, +//! and whether to add a leap second or not is known only before 6 months. +//! Internet-based clocks (via NTP) do account for known leap seconds, +//! but the system API normally doesn't (and often can't, with no network connection) +//! and there is no reliable way to retrieve leap second information. +//! +//! Chrono does not try to accurately implement leap seconds; it is impossible. +//! Rather, **it allows for leap seconds but behaves as if there are *no other* leap seconds.** +//! Various time arithmetics will ignore any possible leap second(s) +//! except when the operand were actually a leap second. +//! The leap second is indicated via fractional seconds more than 1 second, +//! so values like `NaiveTime::from_hms_milli(23, 56, 4, 1_005)` are allowed; +//! that value would mean 5ms after the beginning of a leap second following 23:56:04. +//! Parsing and formatting will correctly handle times that look like leap seconds, +//! and you can then conveniently ignore leap seconds if you are not prepared for them. +//! +//! If you cannot tolerate this behavior, +//! you must use a separate `TimeZone` for the International Atomic Time (TAI). +//! TAI is like UTC but has no leap seconds, and thus slightly differs from UTC. +//! Chrono 0.2 does not provide such implementation, but it is planned for 0.3. use std::{str, fmt, hash}; use std::ops::{Add, Sub}; @@ -18,43 +54,9 @@ use format::{parse, Parsed, ParseError, ParseResult, DelayedFormat, StrftimeItem /// ISO 8601 time without timezone. /// Allows for the nanosecond precision and optional leap second representation. /// -/// # Leap second WHAT? -/// -/// Since 1960s, the manmade atomic clock has been so accurate that -/// it is much more accurate than Earth's own motion. -/// It became desirable to define the civil time in terms of the atomic clock, -/// but that risks the desynchronization of the civil time from Earth. -/// To account for this, the designers of the Coordinated Universal Time (UTC) -/// made that the UTC should be kept within 0.9 seconds of the observed Earth-bound time. -/// When the mean solar day is longer than the ideal (86,400 seconds), -/// the error slowly accumulates and it is necessary to add a **leap second** -/// to slow the UTC down a bit. -/// (We may also remove a second to speed the UTC up a bit, but it never happened.) -/// The leap second, if any, follows 23:59:59 of June 30 or December 31 in the UTC. -/// -/// Fast forward to the 21st century, -/// we have seen 26 leap seconds from January 1972 to December 2015. -/// Yes, 26 seconds. Probably you can read this paragraph within 26 seconds. -/// But those 26 seconds, and possibly more in the future, are never predictable, -/// and whether to add a leap second or not is known only before 6 months. -/// Internet-based clocks (via NTP) do account for known leap seconds, -/// but the system API normally doesn't (and often can't, with no network connection) -/// and there is no reliable way to retrieve leap second information. -/// -/// Chrono does not try to accurately implement leap seconds; it is impossible. -/// Rather, **it allows for leap seconds but behaves as if there are *no other* leap seconds.** -/// Various time arithmetics will ignore any possible leap second(s) -/// except when the operand were actually a leap second. -/// The leap second is indicated via fractional seconds more than 1 second, -/// so values like `NaiveTime::from_hms_milli(23, 56, 4, 1_005)` are allowed; -/// that value would mean 5ms after the beginning of a leap second following 23:56:04. -/// Parsing and formatting will correctly handle times that look like leap seconds, -/// and you can then conveniently ignore leap seconds if you are not prepared for them. -/// -/// If you cannot tolerate this behavior, -/// you must use a separate `TimeZone` for the International Atomic Time (TAI). -/// TAI is like UTC but has no leap seconds, and thus slightly differs from UTC. -/// Chrono 0.2 does not provide such implementation, but it is planned for 0.3. +/// +/// Chrono has a notable policy on the [leap second handling](./index.html#leap-second-handling), +/// designed to be maximally useful for typical users. #[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] pub struct NaiveTime { @@ -65,7 +67,7 @@ pub struct NaiveTime { impl NaiveTime { /// Makes a new `NaiveTime` from hour, minute and second. /// - /// No [leap second](#leap-second-what?) is allowed here; + /// No [leap second](./index.html#leap-second-handling) is allowed here; /// use `NaiveTime::from_hms_*` methods with a subsecond parameter instead. /// /// Panics on invalid hour, minute and/or second. @@ -88,7 +90,7 @@ impl NaiveTime { /// Makes a new `NaiveTime` from hour, minute and second. /// - /// No [leap second](#leap-second-what?) is allowed here; + /// No [leap second](./index.html#leap-second-handling) is allowed here; /// use `NaiveTime::from_hms_*_opt` methods with a subsecond parameter instead. /// /// Returns `None` on invalid hour, minute and/or second. @@ -113,7 +115,7 @@ impl NaiveTime { /// Makes a new `NaiveTime` from hour, minute, second and millisecond. /// /// The millisecond part can exceed 1,000 - /// in order to represent the [leap second](#leap-second-what?). + /// in order to represent the [leap second](./index.html#leap-second-handling). /// /// Panics on invalid hour, minute, second and/or millisecond. /// @@ -136,7 +138,7 @@ impl NaiveTime { /// Makes a new `NaiveTime` from hour, minute, second and millisecond. /// /// The millisecond part can exceed 1,000 - /// in order to represent the [leap second](#leap-second-what?). + /// in order to represent the [leap second](./index.html#leap-second-handling). /// /// Returns `None` on invalid hour, minute, second and/or millisecond. /// @@ -163,7 +165,7 @@ impl NaiveTime { /// Makes a new `NaiveTime` from hour, minute, second and microsecond. /// /// The microsecond part can exceed 1,000,000 - /// in order to represent the [leap second](#leap-second-what?). + /// in order to represent the [leap second](./index.html#leap-second-handling). /// /// Panics on invalid hour, minute, second and/or microsecond. /// @@ -186,7 +188,7 @@ impl NaiveTime { /// Makes a new `NaiveTime` from hour, minute, second and microsecond. /// /// The microsecond part can exceed 1,000,000 - /// in order to represent the [leap second](#leap-second-what?). + /// in order to represent the [leap second](./index.html#leap-second-handling). /// /// Returns `None` on invalid hour, minute, second and/or microsecond. /// @@ -213,7 +215,7 @@ impl NaiveTime { /// Makes a new `NaiveTime` from hour, minute, second and nanosecond. /// /// The nanosecond part can exceed 1,000,000,000 - /// in order to represent the [leap second](#leap-second-what?). + /// in order to represent the [leap second](./index.html#leap-second-handling). /// /// Panics on invalid hour, minute, second and/or nanosecond. /// @@ -236,7 +238,7 @@ impl NaiveTime { /// Makes a new `NaiveTime` from hour, minute, second and nanosecond. /// /// The nanosecond part can exceed 1,000,000,000 - /// in order to represent the [leap second](#leap-second-what?). + /// in order to represent the [leap second](./index.html#leap-second-handling). /// /// Returns `None` on invalid hour, minute, second and/or nanosecond. /// @@ -264,7 +266,7 @@ impl NaiveTime { /// Makes a new `NaiveTime` from the number of seconds since midnight and nanosecond. /// /// The nanosecond part can exceed 1,000,000,000 - /// in order to represent the [leap second](#leap-second-what?). + /// in order to represent the [leap second](./index.html#leap-second-handling). /// /// Panics on invalid number of seconds and/or nanosecond. /// @@ -287,7 +289,7 @@ impl NaiveTime { /// Makes a new `NaiveTime` from the number of seconds since midnight and nanosecond. /// /// The nanosecond part can exceed 1,000,000,000 - /// in order to represent the [leap second](#leap-second-what?). + /// in order to represent the [leap second](./index.html#leap-second-handling). /// /// Returns `None` on invalid number of seconds and/or nanosecond. /// @@ -332,7 +334,7 @@ impl NaiveTime { /// Ok(NaiveTime::from_hms(12, 34, 56))); /// ~~~~ /// - /// [Leap seconds](#leap-second-what?) are correctly handled by + /// [Leap seconds](./index.html#leap-second-handling) are correctly handled by /// treating any time of the form `hh:mm:60` as a leap second. /// (This equally applies to the formatting, so the round trip is possible.) /// @@ -371,7 +373,7 @@ impl NaiveTime { } /// Formats the time with the specified formatting items. - /// Otherwise it is same to the ordinary `format` method. + /// Otherwise it is same to the ordinary [`format`](#method.format) method. /// /// The `Iterator` of items should be `Clone`able, /// since the resulting `DelayedFormat` value may be formatted multiple times. @@ -431,11 +433,103 @@ impl NaiveTime { } 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 } + /// Returns the hour number from 0 to 23. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// assert_eq!(NaiveTime::from_hms(0, 0, 0).hour(), 0); + /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).hour(), 23); + /// ~~~~ + #[inline] + fn hour(&self) -> u32 { + self.hms().0 + } + /// Returns the minute number from 0 to 59. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// assert_eq!(NaiveTime::from_hms(0, 0, 0).minute(), 0); + /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).minute(), 56); + /// ~~~~ + #[inline] + fn minute(&self) -> u32 { + self.hms().1 + } + + /// Returns the second number from 0 to 59. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// assert_eq!(NaiveTime::from_hms(0, 0, 0).second(), 0); + /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).second(), 4); + /// ~~~~ + /// + /// This method never returns 60 even when it is a leap second. + /// ([Why?](./index.html#leap-second-handling)) + /// Use the proper [formatting method](#method.format) to get a human-readable representation. + /// + /// ~~~~ + /// # use chrono::{NaiveTime, Timelike}; + /// let leap = NaiveTime::from_hms_milli(23, 59, 59, 1_000); + /// assert_eq!(leap.second(), 59); + /// assert_eq!(leap.format("%H:%M:%S").to_string(), "23:59:60"); + /// ~~~~ + #[inline] + fn second(&self) -> u32 { + self.hms().2 + } + + /// Returns the number of nanoseconds since the whole non-leap second. + /// The range from 1,000,000,000 to 1,999,999,999 represents + /// the [leap second](./naive/time/index.html#leap-second-handling). + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// assert_eq!(NaiveTime::from_hms(0, 0, 0).nanosecond(), 0); + /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).nanosecond(), 12_345_678); + /// ~~~~ + /// + /// Leap seconds may have seemingly out-of-range return values. + /// You can reduce the range with `time.nanosecond() % 1_000_000_000`, or + /// use the proper [formatting method](#method.format) to get a human-readable representation. + /// + /// ~~~~ + /// # use chrono::{NaiveTime, Timelike}; + /// let leap = NaiveTime::from_hms_milli(23, 59, 59, 1_000); + /// assert_eq!(leap.nanosecond(), 1_000_000_000); + /// assert_eq!(leap.format("%H:%M:%S%.9f").to_string(), "23:59:60.000000000"); + /// ~~~~ + #[inline] + fn nanosecond(&self) -> u32 { + self.frac + } + + /// Makes a new `NaiveTime` with the hour number changed. + /// + /// Returns `None` when the resulting `NaiveTime` would be invalid. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); + /// assert_eq!(dt.with_hour(7), Some(NaiveTime::from_hms_nano(7, 56, 4, 12_345_678))); + /// assert_eq!(dt.with_hour(24), None); + /// ~~~~ #[inline] fn with_hour(&self, hour: u32) -> Option { if hour >= 24 { return None; } @@ -443,6 +537,19 @@ impl Timelike for NaiveTime { Some(NaiveTime { secs: secs, ..*self }) } + /// Makes a new `NaiveTime` with the minute number changed. + /// + /// Returns `None` when the resulting `NaiveTime` would be invalid. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); + /// assert_eq!(dt.with_minute(45), Some(NaiveTime::from_hms_nano(23, 45, 4, 12_345_678))); + /// assert_eq!(dt.with_minute(60), None); + /// ~~~~ #[inline] fn with_minute(&self, min: u32) -> Option { if min >= 60 { return None; } @@ -450,6 +557,21 @@ impl Timelike for NaiveTime { Some(NaiveTime { secs: secs, ..*self }) } + /// Makes a new `NaiveTime` with the second number changed. + /// + /// Returns `None` when the resulting `NaiveTime` would be invalid. + /// As with the [`second`](#tymethod.second) method, + /// the input range is restricted to 0 through 59. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); + /// assert_eq!(dt.with_second(17), Some(NaiveTime::from_hms_nano(23, 56, 17, 12_345_678))); + /// assert_eq!(dt.with_second(60), None); + /// ~~~~ #[inline] fn with_second(&self, sec: u32) -> Option { if sec >= 60 { return None; } @@ -457,18 +579,64 @@ impl Timelike for NaiveTime { Some(NaiveTime { secs: secs, ..*self }) } + /// Makes a new `NaiveTime` with nanoseconds since the whole non-leap second changed. + /// + /// Returns `None` when the resulting `NaiveTime` would be invalid. + /// As with the [`nanosecond`](#tymethod.nanosecond) method, + /// the input range can exceed 1,000,000,000 for leap seconds. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); + /// assert_eq!(dt.with_nanosecond(333_333_333), + /// Some(NaiveTime::from_hms_nano(23, 56, 4, 333_333_333))); + /// assert_eq!(dt.with_nanosecond(2_000_000_000), None); + /// ~~~~ + /// + /// Leap seconds can theoretically follow *any* whole second. + /// The following would be a proper leap second at the time zone offset of UTC-00:03:57 + /// (there are several historical examples comparable to this "non-sense" offset), + /// and therefore is allowed. + /// + /// ~~~~ + /// # use chrono::{NaiveTime, Timelike}; + /// # let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); + /// assert_eq!(dt.with_nanosecond(1_333_333_333), + /// Some(NaiveTime::from_hms_nano(23, 56, 4, 1_333_333_333))); + /// ~~~~ #[inline] fn with_nanosecond(&self, nano: u32) -> Option { if nano >= 2_000_000_000 { return None; } Some(NaiveTime { frac: nano, ..*self }) } + /// Returns the number of non-leap seconds past the last midnight. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// assert_eq!(NaiveTime::from_hms(1, 2, 3).num_seconds_from_midnight(), + /// 3723); + /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).num_seconds_from_midnight(), + /// 86164); + /// assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 1_000).num_seconds_from_midnight(), + /// 86399); + /// ~~~~ #[inline] fn num_seconds_from_midnight(&self) -> u32 { self.secs // do not repeat the calculation! } } +/// `NaiveTime` can be used as a key to the hash maps (in principle). +/// +/// Practically this also takes account of fractional seconds, so it is not recommended. +/// (For the obvious reason this also distinguishes leap seconds from non-leap seconds.) impl hash::Hash for NaiveTime { fn hash(&self, state: &mut H) { self.secs.hash(state);