Merge pull request #341 from CryZe/no-std

Implement Support for no_std
This commit is contained in:
Brandon W Maister 2019-11-22 16:53:09 -05:00 committed by GitHub
commit d9929a60b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 374 additions and 131 deletions

View File

@ -24,25 +24,26 @@ appveyor = { repository = "chronotope/chrono" }
name = "chrono" name = "chrono"
[features] [features]
default = ["clock"] default = ["clock", "std"]
clock = ["time"] alloc = []
std = []
clock = ["time", "std"]
wasmbind = ["wasm-bindgen", "js-sys"] wasmbind = ["wasm-bindgen", "js-sys"]
[dependencies] [dependencies]
libc = { version = "0.2", default-features = false }
time = { version = "0.1.39", optional = true } time = { version = "0.1.39", optional = true }
num-integer = { version = "0.1.36", default-features = false } num-integer = { version = "0.1.36", default-features = false }
num-traits = { version = "0.2", default-features = false } num-traits = { version = "0.2", default-features = false }
rustc-serialize = { version = "0.3.20", optional = true } rustc-serialize = { version = "0.3.20", optional = true }
serde = { version = "1", optional = true } serde = { version = "1.0.99", default-features = false, optional = true }
[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies] [target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies]
wasm-bindgen = { version = "0.2", optional = true } wasm-bindgen = { version = "0.2", optional = true }
js-sys = { version = "0.3", optional = true } # contains FFI bindings for the JS Date API js-sys = { version = "0.3", optional = true } # contains FFI bindings for the JS Date API
[dev-dependencies] [dev-dependencies]
serde_json = { version = "1" } serde_json = { version = "1", default-features = false }
serde_derive = { version = "1" } serde_derive = { version = "1", default-features = false }
bincode = { version = "0.8.0" } bincode = { version = "0.8.0" }
num-iter = { version = "0.1.35", default-features = false } num-iter = { version = "0.1.35", default-features = false }
doc-comment = "0.3" doc-comment = "0.3"

View File

@ -1,6 +1,8 @@
# this Makefile is mostly for the packaging convenience. # this Makefile is mostly for the packaging convenience.
# casual users should use `cargo` to retrieve the appropriate version of Chrono. # casual users should use `cargo` to retrieve the appropriate version of Chrono.
CHANNEL=stable
.PHONY: all .PHONY: all
all: all:
@echo 'Try `cargo build` instead.' @echo 'Try `cargo build` instead.'
@ -20,11 +22,8 @@ README.md: src/lib.rs
.PHONY: test .PHONY: test
test: test:
TZ=UTC0 cargo test --features 'serde rustc-serialize bincode' --lib CHANNEL=$(CHANNEL) ./ci/travis.sh
TZ=ACST-9:30 cargo test --features 'serde rustc-serialize bincode' --lib
TZ=EST4 cargo test --features 'serde rustc-serialize bincode'
.PHONY: doc .PHONY: doc
doc: authors readme doc: authors readme
cargo doc --features 'serde rustc-serialize bincode' cargo doc --features 'serde rustc-serialize bincode'

14
ci/core-test/Cargo.toml Normal file
View File

@ -0,0 +1,14 @@
[package]
name = "core-test"
version = "0.1.0"
authors = [
"Kang Seonghoon <public+rust@mearie.org>",
"Brandon W Maister <quodlibetor@gmail.com>",
]
edition = "2018"
[dependencies]
chrono = { path = "../..", default-features = false, features = ["serde"] }
[features]
alloc = ["chrono/alloc"]

7
ci/core-test/src/lib.rs Normal file
View File

@ -0,0 +1,7 @@
#![no_std]
use chrono::{TimeZone, Utc};
pub fn create_time() {
let _ = Utc.ymd(2019, 1, 1).and_hms(0, 0, 0);
}

View File

@ -2,25 +2,50 @@
# This is the script that's executed by travis, you can run it yourself to run # This is the script that's executed by travis, you can run it yourself to run
# the exact same suite # the exact same suite
#
# When running it locally the most important thing to set is the CHANNEL env
# var, otherwise it will run tests against every version of rust that it knows
# about (nightly, beta, stable, 1.13.0):
#
# $ CHANNEL=stable ./ci/travis.sh
set -e set -e
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
channel() {
if [ -n "${TRAVIS}" ]; then main() {
if [ "${TRAVIS_RUST_VERSION}" = "${CHANNEL}" ]; then if [[ -n "$CHANNEL" ]] ; then
pwd if [[ "$CHANNEL" == 1.13.0 ]]; then
(set -x; cargo "$@") banner "Building $CHANNEL"
fi build_only
elif [ -n "${APPVEYOR}" ]; then else
if [ "${APPVEYOR_RUST_CHANNEL}" = "${CHANNEL}" ]; then banner "Building/testing $CHANNEL"
pwd build_and_test
(set -x; cargo "$@") banner "Testing Core $CHANNEL"
build_core_test
fi fi
else else
pwd CHANNEL=nightly
(set -x; cargo "+${CHANNEL}" "$@") matching_banner "Test $CHANNEL"
if [[ "${CLIPPY}" = y ]] ; then
run_clippy
else
build_and_test
fi
CHANNEL=beta
matching_banner "Test $CHANNEL"
build_and_test
CHANNEL=stable
matching_banner "Test $CHANNEL"
build_and_test
build_core_test
CHANNEL=1.13.0
matching_banner "Test $CHANNEL"
build_only
fi fi
} }
@ -54,14 +79,20 @@ build_and_test_nonwasm() {
TZ=Asia/Katmandu channel test -v --features serde,rustc-serialize TZ=Asia/Katmandu channel test -v --features serde,rustc-serialize
# without default "clock" feature # without default "clock" feature
channel build -v --no-default-features channel build -v --no-default-features --features std
TZ=ACST-9:30 channel test -v --no-default-features --lib TZ=ACST-9:30 channel test -v --no-default-features --lib
channel build -v --no-default-features --features rustc-serialize channel build -v --no-default-features --features std,rustc-serialize
TZ=EST4 channel test -v --no-default-features --features rustc-serialize --lib TZ=EST4 channel test -v --no-default-features --features rustc-serialize --lib
channel build -v --no-default-features --features serde channel build -v --no-default-features --features std,serde
TZ=UTC0 channel test -v --no-default-features --features serde --lib TZ=UTC0 channel test -v --no-default-features --features serde --lib
channel build -v --no-default-features --features serde,rustc-serialize channel build -v --no-default-features --features std,serde,rustc-serialize
TZ=Asia/Katmandu channel test -v --no-default-features --features serde,rustc-serialize --lib TZ=Asia/Katmandu channel test -v --no-default-features --features std,serde,rustc-serialize --lib
channel build -v --no-default-features --features 'serde'
TZ=UTC0 channel test -v --no-default-features --features 'serde' --lib
channel build -v --no-default-features --features 'alloc serde'
TZ=UTC0 channel test -v --no-default-features --features 'alloc serde' --lib
} }
build_and_test_wasm() { build_and_test_wasm() {
@ -81,8 +112,16 @@ build_only() {
cargo clean cargo clean
channel build -v channel build -v
channel build -v --features rustc-serialize channel build -v --features rustc-serialize
channel build -v --features 'serde bincode' channel build -v --features serde
channel build -v --no-default-features channel build -v --no-default-features --features std
}
build_core_test() {
channel_run rustup target add thumbv6m-none-eabi --toolchain "$CHANNEL"
(
cd ci/core-test
channel build -v --target thumbv6m-none-eabi
)
} }
run_clippy() { run_clippy() {
@ -92,7 +131,7 @@ run_clippy() {
exit exit
fi fi
cargo clippy --features 'serde bincode rustc-serialize' -- -Dclippy cargo clippy --features 'serde rustc-serialize' -- -Dclippy
} }
check_readme() { check_readme() {
@ -100,22 +139,70 @@ check_readme() {
(set -x; git diff --exit-code -- README.md) ; echo $? (set -x; git diff --exit-code -- README.md) ; echo $?
} }
rustc --version # script helpers
cargo --version
node --version
CHANNEL=nightly banner() {
if [ "x${CLIPPY}" = xy ] ; then echo "======================================================================"
run_clippy echo "$*"
else echo "======================================================================"
build_and_test }
fi
CHANNEL=beta underline() {
build_and_test echo "$*"
echo "${*//?/^}"
}
CHANNEL=stable matching_banner() {
build_and_test if channel_matches || ! is_ci ; then
banner "$*"
echo_versions
fi
}
CHANNEL=1.13.0 echo_versions() {
build_only channel_run rustc --version
channel_run cargo --version
node --version
}
channel() {
channel_run cargo "$@"
}
channel_run() {
if channel_matches ; then
local the_cmd="$ $*"
underline "$the_cmd"
"$@"
elif ! is_ci ; then
local cmd="$1"
shift
if [[ $cmd == cargo || $cmd == rustc ]] ; then
underline "$ $cmd +${CHANNEL} $*"
"$cmd" "+${CHANNEL}" "$@"
else
underline "$ $cmd $*"
"$cmd" "$@"
fi
fi
}
channel_matches() {
if is_ci ; then
if [[ "${TRAVIS_RUST_VERSION}" = "${CHANNEL}"
|| "${APPVEYOR_RUST_CHANNEL}" = "${CHANNEL}" ]] ; then
return 0
fi
fi
return 1
}
is_ci() {
if [[ -n "$TRAVIS" || -n "$APPVEYOR" ]] ; then
return 0
else
return 1
fi
}
main

View File

@ -3,16 +3,17 @@
//! ISO 8601 calendar date with time zone. //! ISO 8601 calendar date with time zone.
use std::{fmt, hash}; use core::{fmt, hash};
use std::cmp::Ordering; use core::cmp::Ordering;
use std::ops::{Add, Sub}; use core::ops::{Add, Sub};
use oldtime::Duration as OldDuration; use oldtime::Duration as OldDuration;
use {Weekday, Datelike}; use {Weekday, Datelike};
use offset::{TimeZone, Utc}; use offset::{TimeZone, Utc};
use naive::{self, NaiveDate, NaiveTime, IsoWeek}; use naive::{self, NaiveDate, NaiveTime, IsoWeek};
use DateTime; use DateTime;
use format::{Item, DelayedFormat, StrftimeItems}; #[cfg(any(feature = "alloc", feature = "std", test))]
use format::{DelayedFormat, Item, StrftimeItems};
/// ISO 8601 calendar date with time zone. /// ISO 8601 calendar date with time zone.
/// ///
@ -255,6 +256,7 @@ fn map_local<Tz: TimeZone, F>(d: &Date<Tz>, mut f: F) -> Option<Date<Tz>>
impl<Tz: TimeZone> Date<Tz> where Tz::Offset: fmt::Display { impl<Tz: TimeZone> Date<Tz> where Tz::Offset: fmt::Display {
/// Formats the date with the specified formatting items. /// Formats the date with the specified formatting items.
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline] #[inline]
pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I> pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I>
where I: Iterator<Item=Item<'a>> + Clone { where I: Iterator<Item=Item<'a>> + Clone {
@ -264,6 +266,7 @@ impl<Tz: TimeZone> Date<Tz> where Tz::Offset: fmt::Display {
/// Formats the date with the specified format string. /// Formats the date with the specified format string.
/// See the [`format::strftime` module](./format/strftime/index.html) /// See the [`format::strftime` module](./format/strftime/index.html)
/// on the supported escape sequences. /// on the supported escape sequences.
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline] #[inline]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> { pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt)) self.format_with_items(StrftimeItems::new(fmt))

View File

@ -3,12 +3,18 @@
//! ISO 8601 date and time with time zone. //! ISO 8601 date and time with time zone.
use std::{str, fmt, hash}; use core::{str, fmt, hash};
use std::cmp::Ordering; use core::cmp::Ordering;
use std::ops::{Add, Sub}; use core::ops::{Add, Sub};
#[cfg(any(feature = "std", test))]
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use oldtime::Duration as OldDuration; use oldtime::Duration as OldDuration;
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::string::{String, ToString};
#[cfg(feature = "std")]
use std::string::ToString;
use {Weekday, Timelike, Datelike}; use {Weekday, Timelike, Datelike};
#[cfg(feature="clock")] #[cfg(feature="clock")]
use offset::Local; use offset::Local;
@ -16,7 +22,9 @@ use offset::{TimeZone, Offset, Utc, FixedOffset};
use naive::{NaiveTime, NaiveDateTime, IsoWeek}; use naive::{NaiveTime, NaiveDateTime, IsoWeek};
use Date; use Date;
use format::{Item, Numeric, Pad, Fixed}; use format::{Item, Numeric, Pad, Fixed};
use format::{parse, Parsed, ParseError, ParseResult, DelayedFormat, StrftimeItems}; use format::{parse, Parsed, ParseError, ParseResult, StrftimeItems};
#[cfg(any(feature = "alloc", feature = "std", test))]
use format::DelayedFormat;
/// Specific formatting options for seconds. This may be extended in the /// Specific formatting options for seconds. This may be extended in the
/// future, so exhaustive matching in external code is not recommended. /// future, so exhaustive matching in external code is not recommended.
@ -363,12 +371,14 @@ impl DateTime<FixedOffset> {
impl<Tz: TimeZone> DateTime<Tz> where Tz::Offset: fmt::Display { impl<Tz: TimeZone> DateTime<Tz> where Tz::Offset: fmt::Display {
/// Returns an RFC 2822 date and time string such as `Tue, 1 Jul 2003 10:52:37 +0200`. /// Returns an RFC 2822 date and time string such as `Tue, 1 Jul 2003 10:52:37 +0200`.
#[cfg(any(feature = "alloc", feature = "std", test))]
pub fn to_rfc2822(&self) -> String { pub fn to_rfc2822(&self) -> String {
const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC2822)]; const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC2822)];
self.format_with_items(ITEMS.iter().cloned()).to_string() self.format_with_items(ITEMS.iter().cloned()).to_string()
} }
/// Returns an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`. /// Returns an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`.
#[cfg(any(feature = "alloc", feature = "std", test))]
pub fn to_rfc3339(&self) -> String { pub fn to_rfc3339(&self) -> String {
const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC3339)]; const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC3339)];
self.format_with_items(ITEMS.iter().cloned()).to_string() self.format_with_items(ITEMS.iter().cloned()).to_string()
@ -398,6 +408,7 @@ impl<Tz: TimeZone> DateTime<Tz> where Tz::Offset: fmt::Display {
/// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true), /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true),
/// "2018-01-26T10:30:09+08:00"); /// "2018-01-26T10:30:09+08:00");
/// ``` /// ```
#[cfg(any(feature = "alloc", feature = "std", test))]
pub fn to_rfc3339_opts(&self, secform: SecondsFormat, use_z: bool) -> String { pub fn to_rfc3339_opts(&self, secform: SecondsFormat, use_z: bool) -> String {
use format::Numeric::*; use format::Numeric::*;
use format::Pad::Zero; use format::Pad::Zero;
@ -449,6 +460,7 @@ impl<Tz: TimeZone> DateTime<Tz> where Tz::Offset: fmt::Display {
} }
/// Formats the combined date and time with the specified formatting items. /// Formats the combined date and time with the specified formatting items.
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline] #[inline]
pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I> pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I>
where I: Iterator<Item=Item<'a>> + Clone { where I: Iterator<Item=Item<'a>> + Clone {
@ -459,6 +471,7 @@ impl<Tz: TimeZone> DateTime<Tz> where Tz::Offset: fmt::Display {
/// Formats the combined date and time with the specified format string. /// Formats the combined date and time with the specified format string.
/// See the [`format::strftime` module](./format/strftime/index.html) /// See the [`format::strftime` module](./format/strftime/index.html)
/// on the supported escape sequences. /// on the supported escape sequences.
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline] #[inline]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> { pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt)) self.format_with_items(StrftimeItems::new(fmt))
@ -647,6 +660,7 @@ impl str::FromStr for DateTime<Local> {
} }
} }
#[cfg(any(feature = "std", test))]
impl From<SystemTime> for DateTime<Utc> { impl From<SystemTime> for DateTime<Utc> {
fn from(t: SystemTime) -> DateTime<Utc> { fn from(t: SystemTime) -> DateTime<Utc> {
let (sec, nsec) = match t.duration_since(UNIX_EPOCH) { let (sec, nsec) = match t.duration_since(UNIX_EPOCH) {
@ -672,6 +686,7 @@ impl From<SystemTime> for DateTime<Local> {
} }
} }
#[cfg(any(feature = "std", test))]
impl<Tz: TimeZone> From<DateTime<Tz>> for SystemTime { impl<Tz: TimeZone> From<DateTime<Tz>> for SystemTime {
fn from(dt: DateTime<Tz>) -> SystemTime { fn from(dt: DateTime<Tz>) -> SystemTime {
use std::time::Duration; use std::time::Duration;
@ -699,7 +714,7 @@ fn test_auto_conversion() {
fn test_encodable_json<FUtc, FFixed, E>(to_string_utc: FUtc, to_string_fixed: FFixed) fn test_encodable_json<FUtc, FFixed, E>(to_string_utc: FUtc, to_string_fixed: FFixed)
where FUtc: Fn(&DateTime<Utc>) -> Result<String, E>, where FUtc: Fn(&DateTime<Utc>) -> Result<String, E>,
FFixed: Fn(&DateTime<FixedOffset>) -> Result<String, E>, FFixed: Fn(&DateTime<FixedOffset>) -> Result<String, E>,
E: ::std::fmt::Debug E: ::core::fmt::Debug
{ {
assert_eq!(to_string_utc(&Utc.ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(), assert_eq!(to_string_utc(&Utc.ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(),
Some(r#""2014-07-24T12:34:06Z""#.into())); Some(r#""2014-07-24T12:34:06Z""#.into()));
@ -717,7 +732,7 @@ fn test_decodable_json<FUtc, FFixed, FLocal, E>(utc_from_str: FUtc,
where FUtc: Fn(&str) -> Result<DateTime<Utc>, E>, where FUtc: Fn(&str) -> Result<DateTime<Utc>, E>,
FFixed: Fn(&str) -> Result<DateTime<FixedOffset>, E>, FFixed: Fn(&str) -> Result<DateTime<FixedOffset>, E>,
FLocal: Fn(&str) -> Result<DateTime<Local>, E>, FLocal: Fn(&str) -> Result<DateTime<Local>, E>,
E: ::std::fmt::Debug E: ::core::fmt::Debug
{ {
// should check against the offset as well (the normal DateTime comparison will ignore them) // should check against the offset as well (the normal DateTime comparison will ignore them)
fn norm<Tz: TimeZone>(dt: &Option<DateTime<Tz>>) -> Option<(&DateTime<Tz>, &Tz::Offset)> { fn norm<Tz: TimeZone>(dt: &Option<DateTime<Tz>>) -> Option<(&DateTime<Tz>, &Tz::Offset)> {
@ -754,7 +769,7 @@ fn test_decodable_json_timestamps<FUtc, FFixed, FLocal, E>(utc_from_str: FUtc,
where FUtc: Fn(&str) -> Result<rustc_serialize::TsSeconds<Utc>, E>, where FUtc: Fn(&str) -> Result<rustc_serialize::TsSeconds<Utc>, E>,
FFixed: Fn(&str) -> Result<rustc_serialize::TsSeconds<FixedOffset>, E>, FFixed: Fn(&str) -> Result<rustc_serialize::TsSeconds<FixedOffset>, E>,
FLocal: Fn(&str) -> Result<rustc_serialize::TsSeconds<Local>, E>, FLocal: Fn(&str) -> Result<rustc_serialize::TsSeconds<Local>, E>,
E: ::std::fmt::Debug E: ::core::fmt::Debug
{ {
fn norm<Tz: TimeZone>(dt: &Option<DateTime<Tz>>) -> Option<(&DateTime<Tz>, &Tz::Offset)> { fn norm<Tz: TimeZone>(dt: &Option<DateTime<Tz>>) -> Option<(&DateTime<Tz>, &Tz::Offset)> {
dt.as_ref().map(|dt| (dt, dt.offset())) dt.as_ref().map(|dt| (dt, dt.offset()))
@ -778,8 +793,8 @@ fn test_decodable_json_timestamps<FUtc, FFixed, FLocal, E>(utc_from_str: FUtc,
#[cfg(feature = "rustc-serialize")] #[cfg(feature = "rustc-serialize")]
pub mod rustc_serialize { pub mod rustc_serialize {
use std::fmt; use core::fmt;
use std::ops::Deref; use core::ops::Deref;
use super::DateTime; use super::DateTime;
#[cfg(feature="clock")] #[cfg(feature="clock")]
use offset::Local; use offset::Local;
@ -907,12 +922,13 @@ pub mod rustc_serialize {
/// documented at re-export site /// documented at re-export site
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
pub mod serde { pub mod serde {
use std::fmt; use core::fmt;
use super::DateTime; use super::DateTime;
#[cfg(feature="clock")] #[cfg(feature="clock")]
use offset::Local; use offset::Local;
use offset::{LocalResult, TimeZone, Utc, FixedOffset}; use offset::{LocalResult, TimeZone, Utc, FixedOffset};
use serdelib::{ser, de}; use serdelib::{ser, de};
use {SerdeError, ne_timestamp};
#[doc(hidden)] #[doc(hidden)]
#[derive(Debug)] #[derive(Debug)]
@ -928,16 +944,16 @@ pub mod serde {
// try!-like function to convert a LocalResult into a serde-ish Result // try!-like function to convert a LocalResult into a serde-ish Result
fn serde_from<T, E, V>(me: LocalResult<T>, ts: &V) -> Result<T, E> fn serde_from<T, E, V>(me: LocalResult<T>, ts: &V) -> Result<T, E>
where E: de::Error, where
V: fmt::Display, E: de::Error,
T: fmt::Display, V: fmt::Display,
T: fmt::Display,
{ {
match me { match me {
LocalResult::None => Err(E::custom( LocalResult::None => Err(E::custom(
format!("value is not a legal timestamp: {}", ts))), ne_timestamp(ts))),
LocalResult::Ambiguous(min, max) => Err(E::custom( LocalResult::Ambiguous(min, max) => Err(E::custom(
format!("value is an ambiguous timestamp: {}, could be either of {}, {}", SerdeError::Ambiguous { timestamp: ts, min: min, max: max })),
ts, min, max))),
LocalResult::Single(val) => Ok(val) LocalResult::Single(val) => Ok(val)
} }
} }
@ -979,7 +995,7 @@ pub mod serde {
/// # fn main() { example().unwrap(); } /// # fn main() { example().unwrap(); }
/// ``` /// ```
pub mod ts_nanoseconds { pub mod ts_nanoseconds {
use std::fmt; use core::fmt;
use serdelib::{ser, de}; use serdelib::{ser, de};
use {DateTime, Utc}; use {DateTime, Utc};
@ -1270,7 +1286,7 @@ pub mod serde {
/// # fn main() { example().unwrap(); } /// # fn main() { example().unwrap(); }
/// ``` /// ```
pub mod ts_milliseconds { pub mod ts_milliseconds {
use std::fmt; use core::fmt;
use serdelib::{ser, de}; use serdelib::{ser, de};
use {DateTime, Utc}; use {DateTime, Utc};
@ -1561,7 +1577,7 @@ pub mod serde {
/// # fn main() { example().unwrap(); } /// # fn main() { example().unwrap(); }
/// ``` /// ```
pub mod ts_seconds { pub mod ts_seconds {
use std::fmt; use core::fmt;
use serdelib::{ser, de}; use serdelib::{ser, de};
use {DateTime, Utc}; use {DateTime, Utc};
@ -1847,7 +1863,7 @@ pub mod serde {
fn visit_str<E>(self, value: &str) -> Result<DateTime<FixedOffset>, E> fn visit_str<E>(self, value: &str) -> Result<DateTime<FixedOffset>, E>
where E: de::Error where E: de::Error
{ {
value.parse().map_err(|err| E::custom(format!("{}", err))) value.parse().map_err(|err: ::format::ParseError| E::custom(err))
} }
} }

View File

@ -17,20 +17,30 @@
#![allow(ellipsis_inclusive_range_patterns)] #![allow(ellipsis_inclusive_range_patterns)]
use std::fmt; use core::fmt;
use std::str::FromStr; use core::str::FromStr;
#[cfg(any(feature = "std", test))]
use std::error::Error; use std::error::Error;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
#[cfg(feature = "alloc")]
use alloc::string::{String, ToString};
use {Datelike, Timelike, Weekday, ParseWeekdayError}; #[cfg(any(feature = "alloc", feature = "std", test))]
use {Datelike, Timelike};
use {Weekday, ParseWeekdayError};
#[cfg(any(feature = "alloc", feature = "std", test))]
use div::{div_floor, mod_floor}; use div::{div_floor, mod_floor};
#[cfg(any(feature = "alloc", feature = "std", test))]
use offset::{Offset, FixedOffset}; use offset::{Offset, FixedOffset};
#[cfg(any(feature = "alloc", feature = "std", test))]
use naive::{NaiveDate, NaiveTime}; use naive::{NaiveDate, NaiveTime};
pub use self::strftime::StrftimeItems; pub use self::strftime::StrftimeItems;
pub use self::parsed::Parsed; pub use self::parsed::Parsed;
pub use self::parse::parse; pub use self::parse::parse;
/// An unhabitated type used for `InternalNumeric` and `InternalFixed` below. /// An uninhabited type used for `InternalNumeric` and `InternalFixed` below.
#[derive(Clone, PartialEq, Eq)] #[derive(Clone, PartialEq, Eq)]
enum Void {} enum Void {}
@ -55,7 +65,7 @@ pub enum Pad {
/// ///
/// The **parsing width** is the maximal width to be scanned. /// The **parsing width** is the maximal width to be scanned.
/// The parser only tries to consume from one to given number of digits (greedily). /// The parser only tries to consume from one to given number of digits (greedily).
/// It also trims the preceding whitespaces if any. /// It also trims the preceding whitespace if any.
/// It cannot parse the negative number, so some date and time cannot be formatted then /// It cannot parse the negative number, so some date and time cannot be formatted then
/// parsed with the same formatting items. /// parsed with the same formatting items.
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
@ -185,13 +195,13 @@ pub enum Fixed {
TimezoneName, TimezoneName,
/// Offset from the local time to UTC (`+09:00` or `-04:00` or `+00:00`). /// Offset from the local time to UTC (`+09:00` or `-04:00` or `+00:00`).
/// ///
/// In the parser, the colon can be omitted and/or surrounded with any amount of whitespaces. /// In the parser, the colon can be omitted and/or surrounded with any amount of whitespace.
/// The offset is limited from `-24:00` to `+24:00`, /// The offset is limited from `-24:00` to `+24:00`,
/// which is same to [`FixedOffset`](../offset/struct.FixedOffset.html)'s range. /// which is same to [`FixedOffset`](../offset/struct.FixedOffset.html)'s range.
TimezoneOffsetColon, TimezoneOffsetColon,
/// Offset from the local time to UTC (`+09:00` or `-04:00` or `Z`). /// Offset from the local time to UTC (`+09:00` or `-04:00` or `Z`).
/// ///
/// In the parser, the colon can be omitted and/or surrounded with any amount of whitespaces, /// In the parser, the colon can be omitted and/or surrounded with any amount of whitespace,
/// and `Z` can be either in upper case or in lower case. /// and `Z` can be either in upper case or in lower case.
/// The offset is limited from `-24:00` to `+24:00`, /// The offset is limited from `-24:00` to `+24:00`,
/// which is same to [`FixedOffset`](../offset/struct.FixedOffset.html)'s range. /// which is same to [`FixedOffset`](../offset/struct.FixedOffset.html)'s range.
@ -245,10 +255,12 @@ pub enum Item<'a> {
/// A literally printed and parsed text. /// A literally printed and parsed text.
Literal(&'a str), Literal(&'a str),
/// Same to `Literal` but with the string owned by the item. /// Same to `Literal` but with the string owned by the item.
#[cfg(any(feature = "alloc", feature = "std", test))]
OwnedLiteral(Box<str>), OwnedLiteral(Box<str>),
/// Whitespace. Prints literally but reads zero or more whitespace. /// Whitespace. Prints literally but reads zero or more whitespace.
Space(&'a str), Space(&'a str),
/// Same to `Space` but with the string owned by the item. /// Same to `Space` but with the string owned by the item.
#[cfg(any(feature = "alloc", feature = "std", test))]
OwnedSpace(Box<str>), OwnedSpace(Box<str>),
/// Numeric item. Can be optionally padded to the maximal length (if any) when formatting; /// Numeric item. Can be optionally padded to the maximal length (if any) when formatting;
/// the parser simply ignores any padded whitespace and zeroes. /// the parser simply ignores any padded whitespace and zeroes.
@ -305,13 +317,7 @@ enum ParseErrorKind {
/// Same to `Result<T, ParseError>`. /// Same to `Result<T, ParseError>`.
pub type ParseResult<T> = Result<T, ParseError>; pub type ParseResult<T> = Result<T, ParseError>;
impl fmt::Display for ParseError { impl ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.description().fmt(f)
}
}
impl Error for ParseError {
fn description(&self) -> &str { fn description(&self) -> &str {
match self.0 { match self.0 {
ParseErrorKind::OutOfRange => "input is out of range", ParseErrorKind::OutOfRange => "input is out of range",
@ -325,6 +331,19 @@ impl Error for ParseError {
} }
} }
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.description().fmt(f)
}
}
#[cfg(any(feature = "std", test))]
impl Error for ParseError {
fn description(&self) -> &str {
self.description()
}
}
// to be used in this module and submodules // to be used in this module and submodules
const OUT_OF_RANGE: ParseError = ParseError(ParseErrorKind::OutOfRange); const OUT_OF_RANGE: ParseError = ParseError(ParseErrorKind::OutOfRange);
const IMPOSSIBLE: ParseError = ParseError(ParseErrorKind::Impossible); const IMPOSSIBLE: ParseError = ParseError(ParseErrorKind::Impossible);
@ -336,6 +355,7 @@ const BAD_FORMAT: ParseError = ParseError(ParseErrorKind::BadFormat);
/// Tries to format given arguments with given formatting items. /// Tries to format given arguments with given formatting items.
/// Internally used by `DelayedFormat`. /// Internally used by `DelayedFormat`.
#[cfg(any(feature = "alloc", feature = "std", test))]
pub fn format<'a, I>( pub fn format<'a, I>(
w: &mut fmt::Formatter, w: &mut fmt::Formatter,
date: Option<&NaiveDate>, date: Option<&NaiveDate>,
@ -356,12 +376,13 @@ pub fn format<'a, I>(
static LONG_WEEKDAYS: [&'static str; 7] = static LONG_WEEKDAYS: [&'static str; 7] =
["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]; ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
use std::fmt::Write; use core::fmt::Write;
let mut result = String::new(); let mut result = String::new();
for item in items { for item in items {
match item { match item {
Item::Literal(s) | Item::Space(s) => result.push_str(s), Item::Literal(s) | Item::Space(s) => result.push_str(s),
#[cfg(any(feature = "alloc", feature = "std", test))]
Item::OwnedLiteral(ref s) | Item::OwnedSpace(ref s) => result.push_str(s), Item::OwnedLiteral(ref s) | Item::OwnedSpace(ref s) => result.push_str(s),
Item::Numeric(spec, pad) => { Item::Numeric(spec, pad) => {
@ -598,6 +619,7 @@ pub mod strftime;
/// A *temporary* object which can be used as an argument to `format!` or others. /// 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. /// This is normally constructed via `format` methods of each date and time type.
#[cfg(any(feature = "alloc", feature = "std", test))]
#[derive(Debug)] #[derive(Debug)]
pub struct DelayedFormat<I> { pub struct DelayedFormat<I> {
/// The date view, if any. /// The date view, if any.
@ -610,6 +632,7 @@ pub struct DelayedFormat<I> {
items: I, items: I,
} }
#[cfg(any(feature = "alloc", feature = "std", test))]
impl<'a, I: Iterator<Item=Item<'a>> + Clone> DelayedFormat<I> { impl<'a, I: Iterator<Item=Item<'a>> + Clone> DelayedFormat<I> {
/// Makes a new `DelayedFormat` value out of local date and time. /// Makes a new `DelayedFormat` value out of local date and time.
pub fn new(date: Option<NaiveDate>, time: Option<NaiveTime>, items: I) -> DelayedFormat<I> { pub fn new(date: Option<NaiveDate>, time: Option<NaiveTime>, items: I) -> DelayedFormat<I> {
@ -625,6 +648,7 @@ impl<'a, I: Iterator<Item=Item<'a>> + Clone> DelayedFormat<I> {
} }
} }
#[cfg(any(feature = "alloc", feature = "std", test))]
impl<'a, I: Iterator<Item=Item<'a>> + Clone> fmt::Display for DelayedFormat<I> { impl<'a, I: Iterator<Item=Item<'a>> + Clone> fmt::Display for DelayedFormat<I> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
format(f, self.date.as_ref(), self.time.as_ref(), self.off.as_ref(), self.items.clone()) format(f, self.date.as_ref(), self.time.as_ref(), self.off.as_ref(), self.items.clone())

View File

@ -6,7 +6,7 @@
#![allow(deprecated)] #![allow(deprecated)]
use std::usize; use core::usize;
use Weekday; use Weekday;
@ -218,13 +218,19 @@ pub fn parse<'a, I>(parsed: &mut Parsed, mut s: &str, items: I) -> ParseResult<(
s = &s[prefix.len()..]; s = &s[prefix.len()..];
} }
#[cfg(any(feature = "alloc", feature = "std", test))]
Item::OwnedLiteral(ref prefix) => { Item::OwnedLiteral(ref prefix) => {
if s.len() < prefix.len() { return Err(TOO_SHORT); } if s.len() < prefix.len() { return Err(TOO_SHORT); }
if !s.starts_with(&prefix[..]) { return Err(INVALID); } if !s.starts_with(&prefix[..]) { return Err(INVALID); }
s = &s[prefix.len()..]; s = &s[prefix.len()..];
} }
Item::Space(_) | Item::OwnedSpace(_) => { Item::Space(_) => {
s = s.trim_left();
}
#[cfg(any(feature = "alloc", feature = "std", test))]
Item::OwnedSpace(_) => {
s = s.trim_left(); s = s.trim_left();
} }

View File

@ -387,6 +387,8 @@
#![deny(missing_docs)] #![deny(missing_docs)]
#![deny(missing_debug_implementations)] #![deny(missing_debug_implementations)]
#![cfg_attr(not(any(feature = "std", test)), no_std)]
// The explicit 'static lifetimes are still needed for rustc 1.13-16 // The explicit 'static lifetimes are still needed for rustc 1.13-16
// backward compatibility, and this appeases clippy. If minimum rustc // backward compatibility, and this appeases clippy. If minimum rustc
// becomes 1.17, should be able to remove this, those 'static lifetimes, // becomes 1.17, should be able to remove this, those 'static lifetimes,
@ -403,6 +405,13 @@
trivially_copy_pass_by_ref, trivially_copy_pass_by_ref,
))] ))]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(any(feature = "std", test))]
extern crate std as core;
#[cfg(all(feature = "std", not(feature="alloc")))]
extern crate std as alloc;
#[cfg(feature="clock")] #[cfg(feature="clock")]
extern crate time as oldtime; extern crate time as oldtime;
extern crate num_integer; extern crate num_integer;
@ -513,6 +522,41 @@ pub mod serde {
pub use super::datetime::serde::*; 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 day of week.
/// ///
/// The order of the days of week depends on the context. /// The order of the days of week depends on the context.
@ -647,6 +691,20 @@ impl Weekday {
} }
} }
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 /// 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. /// [`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. /// Do not heavily depend on this though; use explicit methods whenever possible.
@ -680,7 +738,7 @@ impl num_traits::FromPrimitive for Weekday {
} }
} }
use std::fmt; use core::fmt;
/// An error resulting from reading `Weekday` value with `FromStr`. /// An error resulting from reading `Weekday` value with `FromStr`.
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
@ -699,14 +757,14 @@ impl fmt::Debug for ParseWeekdayError {
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
mod weekday_serde { mod weekday_serde {
use super::Weekday; use super::Weekday;
use std::fmt; use core::fmt;
use serdelib::{ser, de}; use serdelib::{ser, de};
impl ser::Serialize for Weekday { impl ser::Serialize for Weekday {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 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)
} }
} }

View File

@ -3,8 +3,8 @@
//! ISO 8601 calendar date without timezone. //! ISO 8601 calendar date without timezone.
use std::{str, fmt}; use core::{str, fmt};
use std::ops::{Add, Sub, AddAssign, SubAssign}; use core::ops::{Add, Sub, AddAssign, SubAssign};
use num_traits::ToPrimitive; use num_traits::ToPrimitive;
use oldtime::Duration as OldDuration; use oldtime::Duration as OldDuration;
@ -12,7 +12,9 @@ use {Weekday, Datelike};
use div::div_mod_floor; use div::div_mod_floor;
use naive::{NaiveTime, NaiveDateTime, IsoWeek}; use naive::{NaiveTime, NaiveDateTime, IsoWeek};
use format::{Item, Numeric, Pad}; use format::{Item, Numeric, Pad};
use format::{parse, Parsed, ParseError, ParseResult, DelayedFormat, StrftimeItems}; use format::{parse, Parsed, ParseError, ParseResult, StrftimeItems};
#[cfg(any(feature = "alloc", feature = "std", test))]
use format::DelayedFormat;
use super::isoweek; use super::isoweek;
use super::internals::{self, DateImpl, Of, Mdf, YearFlags}; use super::internals::{self, DateImpl, Of, Mdf, YearFlags};
@ -916,6 +918,7 @@ impl NaiveDate {
/// # let d = NaiveDate::from_ymd(2015, 9, 5); /// # let d = NaiveDate::from_ymd(2015, 9, 5);
/// assert_eq!(format!("{}", d.format_with_items(fmt)), "2015-09-05"); /// assert_eq!(format!("{}", d.format_with_items(fmt)), "2015-09-05");
/// ~~~~ /// ~~~~
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline] #[inline]
pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I> pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I>
where I: Iterator<Item=Item<'a>> + Clone { where I: Iterator<Item=Item<'a>> + Clone {
@ -954,6 +957,7 @@ impl NaiveDate {
/// assert_eq!(format!("{}", d.format("%Y-%m-%d")), "2015-09-05"); /// assert_eq!(format!("{}", d.format("%Y-%m-%d")), "2015-09-05");
/// assert_eq!(format!("{}", d.format("%A, %-d %B, %C%y")), "Saturday, 5 September, 2015"); /// assert_eq!(format!("{}", d.format("%A, %-d %B, %C%y")), "Saturday, 5 September, 2015");
/// ~~~~ /// ~~~~
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline] #[inline]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> { pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt)) self.format_with_items(StrftimeItems::new(fmt))
@ -1387,7 +1391,7 @@ impl SubAssign<OldDuration> for NaiveDate {
/// Subtracts another `NaiveDate` from the current date. /// Subtracts another `NaiveDate` from the current date.
/// Returns a `Duration` of integral numbers. /// Returns a `Duration` of integral numbers.
/// ///
/// This does not overflow or underflow at all, /// This does not overflow or underflow at all,
/// as all possible output fits in the range of `Duration`. /// as all possible output fits in the range of `Duration`.
/// ///
@ -1600,7 +1604,7 @@ mod rustc_serialize {
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
mod serde { mod serde {
use std::fmt; use core::fmt;
use super::NaiveDate; use super::NaiveDate;
use serdelib::{ser, de}; use serdelib::{ser, de};
@ -1629,15 +1633,23 @@ mod serde {
impl<'de> de::Visitor<'de> for NaiveDateVisitor { impl<'de> de::Visitor<'de> for NaiveDateVisitor {
type Value = NaiveDate; type Value = NaiveDate;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result
{ {
write!(formatter, "a formatted date string") write!(formatter, "a formatted date string")
} }
#[cfg(any(feature = "std", test))]
fn visit_str<E>(self, value: &str) -> Result<NaiveDate, E> fn visit_str<E>(self, value: &str) -> Result<NaiveDate, E>
where E: de::Error where E: de::Error
{ {
value.parse().map_err(|err| E::custom(format!("{}", err))) value.parse().map_err(E::custom)
}
#[cfg(not(any(feature = "std", test)))]
fn visit_str<E>(self, value: &str) -> Result<NaiveDate, E>
where E: de::Error
{
value.parse().map_err(E::custom)
} }
} }

View File

@ -3,8 +3,8 @@
//! ISO 8601 date and time without timezone. //! ISO 8601 date and time without timezone.
use std::{str, fmt, hash}; use core::{str, fmt, hash};
use std::ops::{Add, Sub, AddAssign, SubAssign}; use core::ops::{Add, Sub, AddAssign, SubAssign};
use num_traits::ToPrimitive; use num_traits::ToPrimitive;
use oldtime::Duration as OldDuration; use oldtime::Duration as OldDuration;
@ -12,7 +12,9 @@ use {Weekday, Timelike, Datelike};
use div::div_mod_floor; use div::div_mod_floor;
use naive::{NaiveTime, NaiveDate, IsoWeek}; use naive::{NaiveTime, NaiveDate, IsoWeek};
use format::{Item, Numeric, Pad, Fixed}; use format::{Item, Numeric, Pad, Fixed};
use format::{parse, Parsed, ParseError, ParseResult, DelayedFormat, StrftimeItems}; use format::{parse, Parsed, ParseError, ParseResult, StrftimeItems};
#[cfg(any(feature = "alloc", feature = "std", test))]
use format::DelayedFormat;
/// The tight upper bound guarantees that a duration with `|Duration| >= 2^MAX_SECS_BITS` /// The tight upper bound guarantees that a duration with `|Duration| >= 2^MAX_SECS_BITS`
/// will always overflow the addition with any date and time type. /// will always overflow the addition with any date and time type.
@ -645,6 +647,7 @@ impl NaiveDateTime {
/// # let dt = NaiveDate::from_ymd(2015, 9, 5).and_hms(23, 56, 4); /// # let dt = NaiveDate::from_ymd(2015, 9, 5).and_hms(23, 56, 4);
/// assert_eq!(format!("{}", dt.format_with_items(fmt)), "2015-09-05 23:56:04"); /// assert_eq!(format!("{}", dt.format_with_items(fmt)), "2015-09-05 23:56:04");
/// ~~~~ /// ~~~~
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline] #[inline]
pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I> pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I>
where I: Iterator<Item=Item<'a>> + Clone { where I: Iterator<Item=Item<'a>> + Clone {
@ -683,6 +686,7 @@ impl NaiveDateTime {
/// assert_eq!(format!("{}", dt.format("%Y-%m-%d %H:%M:%S")), "2015-09-05 23:56:04"); /// assert_eq!(format!("{}", dt.format("%Y-%m-%d %H:%M:%S")), "2015-09-05 23:56:04");
/// assert_eq!(format!("{}", dt.format("around %l %p on %b %-d")), "around 11 PM on Sep 5"); /// assert_eq!(format!("{}", dt.format("around %l %p on %b %-d")), "around 11 PM on Sep 5");
/// ~~~~ /// ~~~~
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline] #[inline]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> { pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt)) self.format_with_items(StrftimeItems::new(fmt))
@ -1663,7 +1667,7 @@ pub mod rustc_serialize {
/// Tools to help serializing/deserializing `NaiveDateTime`s /// Tools to help serializing/deserializing `NaiveDateTime`s
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
pub mod serde { pub mod serde {
use std::fmt; use core::fmt;
use super::{NaiveDateTime}; use super::{NaiveDateTime};
use serdelib::{ser, de}; use serdelib::{ser, de};
@ -1702,7 +1706,7 @@ pub mod serde {
fn visit_str<E>(self, value: &str) -> Result<NaiveDateTime, E> fn visit_str<E>(self, value: &str) -> Result<NaiveDateTime, E>
where E: de::Error where E: de::Error
{ {
value.parse().map_err(|err| E::custom(format!("{}", err))) value.parse().map_err(E::custom)
} }
} }
@ -1750,10 +1754,10 @@ pub mod serde {
/// # fn main() { example().unwrap(); } /// # fn main() { example().unwrap(); }
/// ``` /// ```
pub mod ts_nanoseconds { pub mod ts_nanoseconds {
use std::fmt; use core::fmt;
use serdelib::{ser, de}; use serdelib::{ser, de};
use NaiveDateTime; use {NaiveDateTime, ne_timestamp};
/// Serialize a UTC datetime into an integer number of nanoseconds since the epoch /// Serialize a UTC datetime into an integer number of nanoseconds since the epoch
/// ///
@ -1846,7 +1850,7 @@ pub mod serde {
{ {
NaiveDateTime::from_timestamp_opt(value / 1_000_000_000, NaiveDateTime::from_timestamp_opt(value / 1_000_000_000,
(value % 1_000_000_000) as u32) (value % 1_000_000_000) as u32)
.ok_or_else(|| E::custom(format!("value is not a legal timestamp: {}", value))) .ok_or_else(|| E::custom(ne_timestamp(value)))
} }
fn visit_u64<E>(self, value: u64) -> Result<NaiveDateTime, E> fn visit_u64<E>(self, value: u64) -> Result<NaiveDateTime, E>
@ -1854,7 +1858,7 @@ pub mod serde {
{ {
NaiveDateTime::from_timestamp_opt(value as i64 / 1_000_000_000, NaiveDateTime::from_timestamp_opt(value as i64 / 1_000_000_000,
(value as i64 % 1_000_000_000) as u32) (value as i64 % 1_000_000_000) as u32)
.ok_or_else(|| E::custom(format!("value is not a legal timestamp: {}", value))) .ok_or_else(|| E::custom(ne_timestamp(value)))
} }
} }
} }
@ -1895,10 +1899,10 @@ pub mod serde {
/// # fn main() { example().unwrap(); } /// # fn main() { example().unwrap(); }
/// ``` /// ```
pub mod ts_milliseconds { pub mod ts_milliseconds {
use std::fmt; use core::fmt;
use serdelib::{ser, de}; use serdelib::{ser, de};
use NaiveDateTime; use {NaiveDateTime, ne_timestamp};
/// Serialize a UTC datetime into an integer number of milliseconds since the epoch /// Serialize a UTC datetime into an integer number of milliseconds since the epoch
/// ///
@ -1991,7 +1995,7 @@ pub mod serde {
{ {
NaiveDateTime::from_timestamp_opt(value / 1000, NaiveDateTime::from_timestamp_opt(value / 1000,
((value % 1000) * 1_000_000) as u32) ((value % 1000) * 1_000_000) as u32)
.ok_or_else(|| E::custom(format!("value is not a legal timestamp: {}", value))) .ok_or_else(|| E::custom(ne_timestamp(value)))
} }
fn visit_u64<E>(self, value: u64) -> Result<NaiveDateTime, E> fn visit_u64<E>(self, value: u64) -> Result<NaiveDateTime, E>
@ -1999,7 +2003,7 @@ pub mod serde {
{ {
NaiveDateTime::from_timestamp_opt((value / 1000) as i64, NaiveDateTime::from_timestamp_opt((value / 1000) as i64,
((value % 1000) * 1_000_000) as u32) ((value % 1000) * 1_000_000) as u32)
.ok_or_else(|| E::custom(format!("value is not a legal timestamp: {}", value))) .ok_or_else(|| E::custom(ne_timestamp(value)))
} }
} }
} }
@ -2040,10 +2044,10 @@ pub mod serde {
/// # fn main() { example().unwrap(); } /// # fn main() { example().unwrap(); }
/// ``` /// ```
pub mod ts_seconds { pub mod ts_seconds {
use std::fmt; use core::fmt;
use serdelib::{ser, de}; use serdelib::{ser, de};
use NaiveDateTime; use {NaiveDateTime, ne_timestamp};
/// Serialize a UTC datetime into an integer number of seconds since the epoch /// Serialize a UTC datetime into an integer number of seconds since the epoch
/// ///
@ -2135,14 +2139,14 @@ pub mod serde {
where E: de::Error where E: de::Error
{ {
NaiveDateTime::from_timestamp_opt(value, 0) NaiveDateTime::from_timestamp_opt(value, 0)
.ok_or_else(|| E::custom(format!("value is not a legal timestamp: {}", value))) .ok_or_else(|| E::custom(ne_timestamp(value)))
} }
fn visit_u64<E>(self, value: u64) -> Result<NaiveDateTime, E> fn visit_u64<E>(self, value: u64) -> Result<NaiveDateTime, E>
where E: de::Error where E: de::Error
{ {
NaiveDateTime::from_timestamp_opt(value as i64, 0) NaiveDateTime::from_timestamp_opt(value as i64, 0)
.ok_or_else(|| E::custom(format!("value is not a legal timestamp: {}", value))) .ok_or_else(|| E::custom(ne_timestamp(value)))
} }
} }
} }

View File

@ -15,7 +15,7 @@
#![allow(dead_code)] // some internal methods have been left for consistency #![allow(dead_code)] // some internal methods have been left for consistency
use std::{i32, fmt}; use core::{i32, fmt};
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
use Weekday; use Weekday;
use div::{div_rem, mod_floor}; use div::{div_rem, mod_floor};

View File

@ -3,7 +3,7 @@
//! ISO 8601 week. //! ISO 8601 week.
use std::fmt; use core::fmt;
use super::internals::{DateImpl, Of, YearFlags}; use super::internals::{DateImpl, Of, YearFlags};

View File

@ -3,14 +3,16 @@
//! ISO 8601 time without timezone. //! ISO 8601 time without timezone.
use std::{str, fmt, hash}; use core::{str, fmt, hash};
use std::ops::{Add, Sub, AddAssign, SubAssign}; use core::ops::{Add, Sub, AddAssign, SubAssign};
use oldtime::Duration as OldDuration; use oldtime::Duration as OldDuration;
use Timelike; use Timelike;
use div::div_mod_floor; use div::div_mod_floor;
use format::{Item, Numeric, Pad, Fixed}; use format::{Item, Numeric, Pad, Fixed};
use format::{parse, Parsed, ParseError, ParseResult, DelayedFormat, StrftimeItems}; use format::{parse, Parsed, ParseError, ParseResult, StrftimeItems};
#[cfg(any(feature = "alloc", feature = "std", test))]
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.
@ -681,7 +683,7 @@ impl NaiveTime {
// `rhs.frac`|========================================>| // `rhs.frac`|========================================>|
// | | | `self - rhs` | | // | | | `self - rhs` | |
use std::cmp::Ordering; use core::cmp::Ordering;
let secs = i64::from(self.secs) - i64::from(rhs.secs); let secs = i64::from(self.secs) - i64::from(rhs.secs);
let frac = i64::from(self.frac) - i64::from(rhs.frac); let frac = i64::from(self.frac) - i64::from(rhs.frac);
@ -723,6 +725,7 @@ impl NaiveTime {
/// # let t = NaiveTime::from_hms(23, 56, 4); /// # let t = NaiveTime::from_hms(23, 56, 4);
/// assert_eq!(format!("{}", t.format_with_items(fmt)), "23:56:04"); /// assert_eq!(format!("{}", t.format_with_items(fmt)), "23:56:04");
/// ~~~~ /// ~~~~
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline] #[inline]
pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I> pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I>
where I: Iterator<Item=Item<'a>> + Clone { where I: Iterator<Item=Item<'a>> + Clone {
@ -763,6 +766,7 @@ impl NaiveTime {
/// assert_eq!(format!("{}", t.format("%H:%M:%S%.6f")), "23:56:04.012345"); /// assert_eq!(format!("{}", t.format("%H:%M:%S%.6f")), "23:56:04.012345");
/// assert_eq!(format!("{}", t.format("%-I:%M %p")), "11:56 PM"); /// assert_eq!(format!("{}", t.format("%-I:%M %p")), "11:56 PM");
/// ~~~~ /// ~~~~
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline] #[inline]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> { pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt)) self.format_with_items(StrftimeItems::new(fmt))
@ -1411,7 +1415,7 @@ mod rustc_serialize {
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
mod serde { mod serde {
use std::fmt; use core::fmt;
use super::NaiveTime; use super::NaiveTime;
use serdelib::{ser, de}; use serdelib::{ser, de};
@ -1431,7 +1435,7 @@ mod serde {
impl<'de> de::Visitor<'de> for NaiveTimeVisitor { impl<'de> de::Visitor<'de> for NaiveTimeVisitor {
type Value = NaiveTime; type Value = NaiveTime;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result
{ {
write!(formatter, "a formatted time string") write!(formatter, "a formatted time string")
} }
@ -1439,7 +1443,7 @@ mod serde {
fn visit_str<E>(self, value: &str) -> Result<NaiveTime, E> fn visit_str<E>(self, value: &str) -> Result<NaiveTime, E>
where E: de::Error where E: de::Error
{ {
value.parse().map_err(|err| E::custom(format!("{}", err))) value.parse().map_err(E::custom)
} }
} }

View File

@ -3,8 +3,8 @@
//! The time zone which has a fixed offset from UTC. //! The time zone which has a fixed offset from UTC.
use std::ops::{Add, Sub}; use core::ops::{Add, Sub};
use std::fmt; use core::fmt;
use oldtime::Duration as OldDuration; use oldtime::Duration as OldDuration;
use Timelike; use Timelike;

View File

@ -18,7 +18,7 @@
//! and provides implementations for 1 and 3. //! and provides implementations for 1 and 3.
//! An `TimeZone` instance can be reconstructed from the corresponding `Offset` instance. //! An `TimeZone` instance can be reconstructed from the corresponding `Offset` instance.
use std::fmt; use core::fmt;
use format::{parse, ParseResult, Parsed, StrftimeItems}; use format::{parse, ParseResult, Parsed, StrftimeItems};
use naive::{NaiveDate, NaiveDateTime, NaiveTime}; use naive::{NaiveDate, NaiveDateTime, NaiveTime};

View File

@ -3,7 +3,7 @@
//! The UTC (Coordinated Universal Time) time zone. //! The UTC (Coordinated Universal Time) time zone.
use std::fmt; use core::fmt;
#[cfg(all(feature="clock", not(all(target_arch = "wasm32", feature = "wasmbind"))))] #[cfg(all(feature="clock", not(all(target_arch = "wasm32", feature = "wasmbind"))))]
use oldtime; use oldtime;

View File

@ -10,10 +10,11 @@
//! Temporal quantification //! Temporal quantification
use std::{fmt, i64}; use core::{fmt, i64};
#[cfg(any(feature = "std", test))]
use std::error::Error; use std::error::Error;
use std::ops::{Add, Sub, Mul, Div, Neg}; use core::ops::{Add, Sub, Mul, Div, Neg};
use std::time::Duration as StdDuration; use core::time::Duration as StdDuration;
/// The number of nanoseconds in a microsecond. /// The number of nanoseconds in a microsecond.
const NANOS_PER_MICRO: i32 = 1000; const NANOS_PER_MICRO: i32 = 1000;
@ -392,15 +393,22 @@ impl fmt::Display for Duration {
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OutOfRangeError(()); pub struct OutOfRangeError(());
impl OutOfRangeError {
fn description(&self) -> &str {
"Source duration value is out of range for the target type"
}
}
impl fmt::Display for OutOfRangeError { impl fmt::Display for OutOfRangeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.description()) write!(f, "{}", self.description())
} }
} }
#[cfg(any(feature = "std", test))]
impl Error for OutOfRangeError { impl Error for OutOfRangeError {
fn description(&self) -> &str { fn description(&self) -> &str {
"Source duration value is out of range for the target type" self.description()
} }
} }

View File

@ -2,7 +2,7 @@
// See README.md and LICENSE.txt for details. // See README.md and LICENSE.txt for details.
use Timelike; use Timelike;
use std::ops::{Add, Sub}; use core::ops::{Add, Sub};
use oldtime::Duration; use oldtime::Duration;
/// Extension trait for subsecond rounding or truncation to a maximum number /// Extension trait for subsecond rounding or truncation to a maximum number