//! Chrono currently uses
//! the [`time::Duration`](https://docs.rs/time/0.1.40/time/struct.Duration.html) type
//! from the `time` crate to represent the magnitude of a time span.
-//! Since this has the same name to the newer, standard type for duration,
+//! Since this has the same name as the newer, standard type for duration,
//! the reference will refer this type as `OldDuration`.
//! Note that this is an "accurate" duration represented as seconds and
//! nanoseconds and does not represent "nominal" components such as days or
//! months.
//!
//! Chrono does not yet natively support
-//! the standard [`Duration`](https://docs.rs/time/0.1.40/time/struct.Duration.html) type,
+//! the standard [`Duration`](https://doc.rust-lang.org/std/time/struct.Duration.html) type,
//! but it will be supported in the future.
//! Meanwhile you can convert between two types with
//! [`Duration::from_std`](https://docs.rs/time/0.1.40/time/struct.Duration.html#method.from_std)
//! The following illustrates most supported operations to the date and time:
//!
//! ```rust
-//! # extern crate chrono; extern crate time; fn main() {
+//! # extern crate chrono;
+//! extern crate time;
+//!
+//! # fn main() {
//! use chrono::prelude::*;
//! use time::Duration;
//!
-//! # /* we intentionally fake the datetime...
//! // assume this returned `2014-11-28T21:45:59.324310806+09:00`:
-//! let dt = Local::now();
-//! # */ // up to here. we now define a fixed datetime for the illustrative purpose.
-//! # let dt = FixedOffset::east(9*3600).ymd(2014, 11, 28).and_hms_nano(21, 45, 59, 324310806);
+//! let dt = FixedOffset::east(9*3600).ymd(2014, 11, 28).and_hms_nano(21, 45, 59, 324310806);
//!
//! // property accessors
//! assert_eq!((dt.year(), dt.month(), dt.day()), (2014, 11, 28));
//! assert_eq!((dt.month0(), dt.day0()), (10, 27)); // for unfortunate souls
//! assert_eq!((dt.hour(), dt.minute(), dt.second()), (21, 45, 59));
//! assert_eq!(dt.weekday(), Weekday::Fri);
-//! assert_eq!(dt.weekday().number_from_monday(), 5); // Mon=1, ..., Sat=7
+//! assert_eq!(dt.weekday().number_from_monday(), 5); // Mon=1, ..., Sun=7
//! assert_eq!(dt.ordinal(), 332); // the day of year
//! assert_eq!(dt.num_days_from_ce(), 735565); // the number of days from and including Jan 1, 1
//!
//! to get the number of additional number of nanoseconds.
//!
//! ```rust
-//! # use chrono::DateTime;
-//! # use chrono::Utc;
//! // We need the trait in scope to use Utc::timestamp().
-//! use chrono::TimeZone;
+//! use chrono::{DateTime, TimeZone, Utc};
//!
//! // Construct a datetime from epoch:
//! let dt = Utc.timestamp(1_500_000_000, 0);
//! For example, "a month later" of 2014-01-30 is not well-defined
//! and consequently `Utc.ymd(2014, 1, 30).with_month(2)` returns `None`.
//!
+//! Non ISO week handling is not yet supported.
+//! For now you can use the [chrono_ext](https://crates.io/crates/chrono_ext)
+//! crate ([sources](https://github.com/bcourtine/chrono-ext/)).
+//!
//! Advanced time zone handling is not yet supported.
//! For now you can try the [Chrono-tz](https://github.com/chronotope/chrono-tz/) crate instead.
#![doc(html_root_url = "https://docs.rs/chrono/latest/")]
-
-#![cfg_attr(bench, feature(test))] // lib stability features as per RFC #507
+#![cfg_attr(feature = "bench", feature(test))] // lib stability features as per RFC #507
#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
-
-// The explicit 'static lifetimes are still needed for rustc 1.13-16
-// backward compatibility, and this appeases clippy. If minimum rustc
-// becomes 1.17, should be able to remove this, those 'static lifetimes,
-// and use `static` in a lot of places `const` is used now.
-//
-// Similarly, redundant_field_names lints on not using the
-// field-init-shorthand, which was stabilized in rust 1.17.
-//
-// Changing trivially_copy_pass_by_ref would require an incompatible version
-// bump.
+#![deny(dead_code)]
+// lints are added all the time, we test on 1.13
+#![allow(unknown_lints)]
+#![cfg_attr(not(any(feature = "std", test)), no_std)]
#![cfg_attr(feature = "cargo-clippy", allow(
- const_static_lifetime,
+ renamed_and_removed_lints,
+ // The explicit 'static lifetimes are still needed for rustc 1.13-16
+ // backward compatibility, and this appeases clippy. If minimum rustc
+ // becomes 1.17, should be able to remove this, those 'static lifetimes,
+ // and use `static` in a lot of places `const` is used now.
+ redundant_static_lifetimes,
+ // Similarly, redundant_field_names lints on not using the
+ // field-init-shorthand, which was stabilized in rust 1.17.
redundant_field_names,
+ // Changing trivially_copy_pass_by_ref would require an incompatible version
+ // bump.
trivially_copy_pass_by_ref,
+ try_err,
+ // Currently deprecated, we use the separate implementation to add docs
+ // warning that putting a time in a hash table is probably a bad idea
+ derive_hash_xor_eq,
))]
-#[cfg(feature="clock")]
+#[cfg(feature = "alloc")]
+extern crate alloc;
+#[cfg(all(feature = "std", not(feature = "alloc")))]
+extern crate std as alloc;
+#[cfg(any(feature = "std", test))]
+extern crate std as core;
+
+#[cfg(feature = "clock")]
extern crate time as oldtime;
+#[cfg(not(feature = "clock"))]
+mod oldtime;
extern crate num_integer;
extern crate num_traits;
#[cfg(feature = "rustc-serialize")]
extern crate rustc_serialize;
#[cfg(feature = "serde")]
extern crate serde as serdelib;
+#[cfg(feature = "__doctest")]
+#[cfg_attr(feature = "__doctest", cfg(doctest))]
+#[macro_use]
+extern crate doc_comment;
+#[cfg(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind"))]
+extern crate js_sys;
+#[cfg(feature = "bench")]
+extern crate test;
+#[cfg(all(target_arch = "wasm32", not(target_os = "wasi"), feature = "wasmbind"))]
+extern crate wasm_bindgen;
+
+#[cfg(feature = "__doctest")]
+#[cfg_attr(feature = "__doctest", cfg(doctest))]
+doctest!("../README.md");
// this reexport is to aid the transition and should not be in the prelude!
pub use oldtime::Duration;
-#[cfg(feature="clock")]
-#[doc(no_inline)] pub use offset::Local;
-#[doc(no_inline)] pub use offset::{TimeZone, Offset, LocalResult, Utc, FixedOffset};
-#[doc(no_inline)] pub use naive::{NaiveDate, IsoWeek, NaiveTime, NaiveDateTime};
-pub use date::{Date, MIN_DATE, MAX_DATE};
-pub use datetime::{DateTime, SecondsFormat};
+pub use date::{Date, MAX_DATE, MIN_DATE};
#[cfg(feature = "rustc-serialize")]
pub use datetime::rustc_serialize::TsSeconds;
+pub use datetime::{DateTime, SecondsFormat};
pub use format::{ParseError, ParseResult};
+#[doc(no_inline)]
+pub use naive::{IsoWeek, NaiveDate, NaiveDateTime, NaiveTime};
+#[cfg(feature = "clock")]
+#[doc(no_inline)]
+pub use offset::Local;
+#[doc(no_inline)]
+pub use offset::{FixedOffset, LocalResult, Offset, TimeZone, Utc};
pub use round::SubsecRound;
/// A convenience module appropriate for glob imports (`use chrono::prelude::*;`).
pub mod prelude {
- #[doc(no_inline)] pub use {Datelike, Timelike, Weekday};
- #[doc(no_inline)] pub use {TimeZone, Offset};
- #[cfg(feature="clock")]
- #[doc(no_inline)] pub use Local;
- #[doc(no_inline)] pub use {Utc, FixedOffset};
- #[doc(no_inline)] pub use {NaiveDate, NaiveTime, NaiveDateTime};
- #[doc(no_inline)] pub use Date;
- #[doc(no_inline)] pub use {DateTime, SecondsFormat};
- #[doc(no_inline)] pub use SubsecRound;
+ #[doc(no_inline)]
+ pub use Date;
+ #[cfg(feature = "clock")]
+ #[doc(no_inline)]
+ pub use Local;
+ #[doc(no_inline)]
+ pub use SubsecRound;
+ #[doc(no_inline)]
+ pub use {DateTime, SecondsFormat};
+ #[doc(no_inline)]
+ pub use {Datelike, Timelike, Weekday};
+ #[doc(no_inline)]
+ pub use {FixedOffset, Utc};
+ #[doc(no_inline)]
+ pub use {NaiveDate, NaiveDateTime, NaiveTime};
+ #[doc(no_inline)]
+ pub use {Offset, TimeZone};
}
// useful throughout the codebase
macro_rules! try_opt {
- ($e:expr) => (match $e { Some(v) => v, None => return None })
+ ($e:expr) => {
+ match $e {
+ Some(v) => v,
+ None => return None,
+ }
+ };
}
mod div;
-#[cfg(not(feature="clock"))]
-mod oldtime;
pub mod offset;
pub mod naive {
- //! Date and time types which do not concern about the timezones.
+ //! Date and time types unconcerned with timezones.
//!
//! They are primarily building blocks for other types
//! (e.g. [`TimeZone`](../offset/trait.TimeZone.html)),
//! but can be also used for the simpler date and time handling.
- mod internals;
mod date;
+ mod datetime;
+ mod internals;
mod isoweek;
mod time;
- mod datetime;
- pub use self::date::{NaiveDate, MIN_DATE, MAX_DATE};
- pub use self::isoweek::IsoWeek;
- pub use self::time::NaiveTime;
- pub use self::datetime::NaiveDateTime;
+ pub use self::date::{NaiveDate, MAX_DATE, MIN_DATE};
#[cfg(feature = "rustc-serialize")]
#[allow(deprecated)]
pub use self::datetime::rustc_serialize::TsSeconds;
+ pub use self::datetime::NaiveDateTime;
+ pub use self::isoweek::IsoWeek;
+ pub use self::time::NaiveTime;
+ #[cfg(feature = "__internal_bench")]
+ #[doc(hidden)]
+ pub use self::internals::YearFlags as __BenchYearFlags;
/// Serialization/Deserialization of naive types in alternate formats
///
pub mod format;
mod round;
+#[cfg(feature = "__internal_bench")]
+#[doc(hidden)]
+pub use naive::__BenchYearFlags;
+
/// Serialization/Deserialization in alternate formats
///
/// The various modules in here are intended to be used with serde's [`with`
pub use super::datetime::serde::*;
}
+// Until rust 1.18 there is no "pub(crate)" so to share this we need it in the root
+
+#[cfg(feature = "serde")]
+enum SerdeError<V: fmt::Display, D: fmt::Display> {
+ NonExistent { timestamp: V },
+ Ambiguous { timestamp: V, min: D, max: D },
+}
+
+/// Construct a [`SerdeError::NonExistent`]
+#[cfg(feature = "serde")]
+fn ne_timestamp<T: fmt::Display>(ts: T) -> SerdeError<T, u8> {
+ SerdeError::NonExistent::<T, u8> { timestamp: ts }
+}
+
+#[cfg(feature = "serde")]
+impl<V: fmt::Display, D: fmt::Display> fmt::Debug for SerdeError<V, D> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ChronoSerdeError({})", self)
+ }
+}
+
+// impl<V: fmt::Display, D: fmt::Debug> core::error::Error for SerdeError<V, D> {}
+#[cfg(feature = "serde")]
+impl<V: fmt::Display, D: fmt::Display> fmt::Display for SerdeError<V, D> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ &SerdeError::NonExistent { ref timestamp } => {
+ write!(f, "value is not a legal timestamp: {}", timestamp)
+ }
+ &SerdeError::Ambiguous { ref timestamp, ref min, ref max } => write!(
+ f,
+ "value is an ambiguous timestamp: {}, could be either of {}, {}",
+ timestamp, min, max
+ ),
+ }
+ }
+}
+
/// The day of week.
///
/// The order of the days of week depends on the context.
}
}
+impl fmt::Display for Weekday {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(match *self {
+ Weekday::Mon => "Mon",
+ Weekday::Tue => "Tue",
+ Weekday::Wed => "Wed",
+ Weekday::Thu => "Thu",
+ Weekday::Fri => "Fri",
+ Weekday::Sat => "Sat",
+ Weekday::Sun => "Sun",
+ })
+ }
+}
+
/// Any weekday can be represented as an integer from 0 to 6, which equals to
/// [`Weekday::num_days_from_monday`](#method.num_days_from_monday) in this implementation.
/// Do not heavily depend on this though; use explicit methods whenever possible.
}
}
-use std::fmt;
+use core::fmt;
/// An error resulting from reading `Weekday` value with `FromStr`.
#[derive(Clone, PartialEq)]
#[cfg(feature = "serde")]
mod weekday_serde {
use super::Weekday;
- use std::fmt;
- use serdelib::{ser, de};
+ use core::fmt;
+ use serdelib::{de, ser};
impl ser::Serialize for Weekday {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where S: ser::Serializer
+ where
+ S: ser::Serializer,
{
- serializer.serialize_str(&format!("{:?}", self))
+ serializer.collect_str(&self)
}
}
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
- where E: de::Error
+ where
+ E: de::Error,
{
value.parse().map_err(|_| E::custom("short or long weekday names expected"))
}
impl<'de> de::Deserialize<'de> for Weekday {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where D: de::Deserializer<'de>
+ where
+ D: de::Deserializer<'de>,
{
deserializer.deserialize_str(WeekdayVisitor)
}
assert_eq!(weekday, expected_weekday);
}
- let errors: Vec<&str> = vec![
- "\"not a weekday\"",
- "\"monDAYs\"",
- "\"mond\"",
- "mon",
- "\"thur\"",
- "\"thurs\"",
- ];
+ let errors: Vec<&str> =
+ vec!["\"not a weekday\"", "\"monDAYs\"", "\"mond\"", "mon", "\"thur\"", "\"thurs\""];
for str in errors {
from_str::<Weekday>(str).unwrap_err();
/// Returns `None` when the resulting value would be invalid.
fn with_ordinal0(&self, ordinal0: u32) -> Option<Self>;
- /// Returns the number of days since January 1, Year 1 (aka Day 1) in the
- /// proleptic Gregorian calendar.
+ /// Counts the days in the proleptic Gregorian calendar, with January 1, Year 1 (CE) as day 1.
///
- /// # Example:
+ /// # Examples
///
- /// ~~~
+ /// ```
/// use chrono::{NaiveDate, Datelike};
- /// assert_eq!(NaiveDate::from_ymd(1970, 1, 1).num_days_from_ce(), 719163);
+ ///
+ /// assert_eq!(NaiveDate::from_ymd(1970, 1, 1).num_days_from_ce(), 719_163);
+ /// assert_eq!(NaiveDate::from_ymd(2, 1, 1).num_days_from_ce(), 366);
+ /// assert_eq!(NaiveDate::from_ymd(1, 1, 1).num_days_from_ce(), 1);
/// assert_eq!(NaiveDate::from_ymd(0, 1, 1).num_days_from_ce(), -365);
- /// ~~~
+ /// ```
fn num_days_from_ce(&self) -> i32 {
+ // See test_num_days_from_ce_against_alternative_impl below for a more straightforward
+ // implementation.
+
// we know this wouldn't overflow since year is limited to 1/2^13 of i32's full range.
let mut year = self.year() - 1;
let mut ndays = 0;
}
}
-#[cfg(test)] extern crate num_iter;
+#[cfg(test)]
+extern crate num_iter;
#[test]
fn test_readme_doomsday() {
assert!(other_dates.iter().all(|d| d.weekday() == weekday));
}
}
+
+/// Tests `Datelike::num_days_from_ce` against an alternative implementation.
+///
+/// The alternative implementation is not as short as the current one but it is simpler to
+/// understand, with less unexplained magic constants.
+#[test]
+fn test_num_days_from_ce_against_alternative_impl() {
+ /// Returns the number of multiples of `div` in the range `start..end`.
+ ///
+ /// If the range `start..end` is back-to-front, i.e. `start` is greater than `end`, the
+ /// behaviour is defined by the following equation:
+ /// `in_between(start, end, div) == - in_between(end, start, div)`.
+ ///
+ /// When `div` is 1, this is equivalent to `end - start`, i.e. the length of `start..end`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `div` is not positive.
+ fn in_between(start: i32, end: i32, div: i32) -> i32 {
+ assert!(div > 0, "in_between: nonpositive div = {}", div);
+ let start = (start.div_euclid(div), start.rem_euclid(div));
+ let end = (end.div_euclid(div), end.rem_euclid(div));
+ // The lowest multiple of `div` greater than or equal to `start`, divided.
+ let start = start.0 + (start.1 != 0) as i32;
+ // The lowest multiple of `div` greater than or equal to `end`, divided.
+ let end = end.0 + (end.1 != 0) as i32;
+ end - start
+ }
+
+ /// Alternative implementation to `Datelike::num_days_from_ce`
+ fn num_days_from_ce<Date: Datelike>(date: &Date) -> i32 {
+ let year = date.year();
+ let diff = move |div| in_between(1, year, div);
+ // 365 days a year, one more in leap years. In the gregorian calendar, leap years are all
+ // the multiples of 4 except multiples of 100 but including multiples of 400.
+ date.ordinal() as i32 + 365 * diff(1) + diff(4) - diff(100) + diff(400)
+ }
+
+ use num_iter::range_inclusive;
+
+ for year in range_inclusive(naive::MIN_DATE.year(), naive::MAX_DATE.year()) {
+ let jan1_year = NaiveDate::from_ymd(year, 1, 1);
+ assert_eq!(
+ jan1_year.num_days_from_ce(),
+ num_days_from_ce(&jan1_year),
+ "on {:?}",
+ jan1_year
+ );
+ let mid_year = jan1_year + Duration::days(133);
+ assert_eq!(mid_year.num_days_from_ce(), num_days_from_ce(&mid_year), "on {:?}", mid_year);
+ }
+}