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"
[features]
default = ["clock"]
clock = ["time"]
default = ["clock", "std"]
alloc = []
std = []
clock = ["time", "std"]
wasmbind = ["wasm-bindgen", "js-sys"]
[dependencies]
libc = { version = "0.2", default-features = false }
time = { version = "0.1.39", optional = true }
num-integer = { version = "0.1.36", default-features = false }
num-traits = { version = "0.2", default-features = false }
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]
wasm-bindgen = { version = "0.2", optional = true }
js-sys = { version = "0.3", optional = true } # contains FFI bindings for the JS Date API
[dev-dependencies]
serde_json = { version = "1" }
serde_derive = { version = "1" }
serde_json = { version = "1", default-features = false }
serde_derive = { version = "1", default-features = false }
bincode = { version = "0.8.0" }
num-iter = { version = "0.1.35", default-features = false }
doc-comment = "0.3"

View File

@ -1,6 +1,8 @@
# this Makefile is mostly for the packaging convenience.
# casual users should use `cargo` to retrieve the appropriate version of Chrono.
CHANNEL=stable
.PHONY: all
all:
@echo 'Try `cargo build` instead.'
@ -20,11 +22,8 @@ README.md: src/lib.rs
.PHONY: test
test:
TZ=UTC0 cargo test --features 'serde rustc-serialize bincode' --lib
TZ=ACST-9:30 cargo test --features 'serde rustc-serialize bincode' --lib
TZ=EST4 cargo test --features 'serde rustc-serialize bincode'
CHANNEL=$(CHANNEL) ./ci/travis.sh
.PHONY: doc
doc: authors readme
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
# 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
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
channel() {
if [ -n "${TRAVIS}" ]; then
if [ "${TRAVIS_RUST_VERSION}" = "${CHANNEL}" ]; then
pwd
(set -x; cargo "$@")
fi
elif [ -n "${APPVEYOR}" ]; then
if [ "${APPVEYOR_RUST_CHANNEL}" = "${CHANNEL}" ]; then
pwd
(set -x; cargo "$@")
main() {
if [[ -n "$CHANNEL" ]] ; then
if [[ "$CHANNEL" == 1.13.0 ]]; then
banner "Building $CHANNEL"
build_only
else
banner "Building/testing $CHANNEL"
build_and_test
banner "Testing Core $CHANNEL"
build_core_test
fi
else
pwd
(set -x; cargo "+${CHANNEL}" "$@")
CHANNEL=nightly
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
}
@ -54,14 +79,20 @@ build_and_test_nonwasm() {
TZ=Asia/Katmandu channel test -v --features serde,rustc-serialize
# 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
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
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
channel build -v --no-default-features --features serde,rustc-serialize
TZ=Asia/Katmandu channel test -v --no-default-features --features serde,rustc-serialize --lib
channel build -v --no-default-features --features std,serde,rustc-serialize
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() {
@ -81,8 +112,16 @@ build_only() {
cargo clean
channel build -v
channel build -v --features rustc-serialize
channel build -v --features 'serde bincode'
channel build -v --no-default-features
channel build -v --features serde
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() {
@ -92,7 +131,7 @@ run_clippy() {
exit
fi
cargo clippy --features 'serde bincode rustc-serialize' -- -Dclippy
cargo clippy --features 'serde rustc-serialize' -- -Dclippy
}
check_readme() {
@ -100,22 +139,70 @@ check_readme() {
(set -x; git diff --exit-code -- README.md) ; echo $?
}
rustc --version
cargo --version
node --version
# script helpers
CHANNEL=nightly
if [ "x${CLIPPY}" = xy ] ; then
run_clippy
else
build_and_test
fi
banner() {
echo "======================================================================"
echo "$*"
echo "======================================================================"
}
CHANNEL=beta
build_and_test
underline() {
echo "$*"
echo "${*//?/^}"
}
CHANNEL=stable
build_and_test
matching_banner() {
if channel_matches || ! is_ci ; then
banner "$*"
echo_versions
fi
}
CHANNEL=1.13.0
build_only
echo_versions() {
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.
use std::{fmt, hash};
use std::cmp::Ordering;
use std::ops::{Add, Sub};
use core::{fmt, hash};
use core::cmp::Ordering;
use core::ops::{Add, Sub};
use oldtime::Duration as OldDuration;
use {Weekday, Datelike};
use offset::{TimeZone, Utc};
use naive::{self, NaiveDate, NaiveTime, IsoWeek};
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.
///
@ -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 {
/// Formats the date with the specified formatting items.
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline]
pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I>
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.
/// See the [`format::strftime` module](./format/strftime/index.html)
/// on the supported escape sequences.
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt))

View File

@ -3,12 +3,18 @@
//! ISO 8601 date and time with time zone.
use std::{str, fmt, hash};
use std::cmp::Ordering;
use std::ops::{Add, Sub};
use core::{str, fmt, hash};
use core::cmp::Ordering;
use core::ops::{Add, Sub};
#[cfg(any(feature = "std", test))]
use std::time::{SystemTime, UNIX_EPOCH};
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};
#[cfg(feature="clock")]
use offset::Local;
@ -16,7 +22,9 @@ use offset::{TimeZone, Offset, Utc, FixedOffset};
use naive::{NaiveTime, NaiveDateTime, IsoWeek};
use Date;
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
/// 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 {
/// 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 {
const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC2822)];
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`.
#[cfg(any(feature = "alloc", feature = "std", test))]
pub fn to_rfc3339(&self) -> String {
const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC3339)];
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),
/// "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 {
use format::Numeric::*;
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.
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline]
pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I>
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.
/// See the [`format::strftime` module](./format/strftime/index.html)
/// on the supported escape sequences.
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
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> {
fn from(t: SystemTime) -> DateTime<Utc> {
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 {
fn from(dt: DateTime<Tz>) -> SystemTime {
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)
where FUtc: Fn(&DateTime<Utc>) -> 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(),
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>,
FFixed: Fn(&str) -> Result<DateTime<FixedOffset>, 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)
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>,
FFixed: Fn(&str) -> Result<rustc_serialize::TsSeconds<FixedOffset>, 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)> {
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")]
pub mod rustc_serialize {
use std::fmt;
use std::ops::Deref;
use core::fmt;
use core::ops::Deref;
use super::DateTime;
#[cfg(feature="clock")]
use offset::Local;
@ -907,12 +922,13 @@ pub mod rustc_serialize {
/// documented at re-export site
#[cfg(feature = "serde")]
pub mod serde {
use std::fmt;
use core::fmt;
use super::DateTime;
#[cfg(feature="clock")]
use offset::Local;
use offset::{LocalResult, TimeZone, Utc, FixedOffset};
use serdelib::{ser, de};
use {SerdeError, ne_timestamp};
#[doc(hidden)]
#[derive(Debug)]
@ -928,16 +944,16 @@ pub mod serde {
// 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>
where E: de::Error,
V: fmt::Display,
T: fmt::Display,
where
E: de::Error,
V: fmt::Display,
T: fmt::Display,
{
match me {
LocalResult::None => Err(E::custom(
format!("value is not a legal timestamp: {}", ts))),
ne_timestamp(ts))),
LocalResult::Ambiguous(min, max) => Err(E::custom(
format!("value is an ambiguous timestamp: {}, could be either of {}, {}",
ts, min, max))),
SerdeError::Ambiguous { timestamp: ts, min: min, max: max })),
LocalResult::Single(val) => Ok(val)
}
}
@ -979,7 +995,7 @@ pub mod serde {
/// # fn main() { example().unwrap(); }
/// ```
pub mod ts_nanoseconds {
use std::fmt;
use core::fmt;
use serdelib::{ser, de};
use {DateTime, Utc};
@ -1270,7 +1286,7 @@ pub mod serde {
/// # fn main() { example().unwrap(); }
/// ```
pub mod ts_milliseconds {
use std::fmt;
use core::fmt;
use serdelib::{ser, de};
use {DateTime, Utc};
@ -1561,7 +1577,7 @@ pub mod serde {
/// # fn main() { example().unwrap(); }
/// ```
pub mod ts_seconds {
use std::fmt;
use core::fmt;
use serdelib::{ser, de};
use {DateTime, Utc};
@ -1847,7 +1863,7 @@ pub mod serde {
fn visit_str<E>(self, value: &str) -> Result<DateTime<FixedOffset>, E>
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)]
use std::fmt;
use std::str::FromStr;
use core::fmt;
use core::str::FromStr;
#[cfg(any(feature = "std", test))]
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};
#[cfg(any(feature = "alloc", feature = "std", test))]
use offset::{Offset, FixedOffset};
#[cfg(any(feature = "alloc", feature = "std", test))]
use naive::{NaiveDate, NaiveTime};
pub use self::strftime::StrftimeItems;
pub use self::parsed::Parsed;
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)]
enum Void {}
@ -55,7 +65,7 @@ pub enum Pad {
///
/// The **parsing width** is the maximal width to be scanned.
/// 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
/// parsed with the same formatting items.
#[derive(Clone, PartialEq, Eq, Debug)]
@ -185,13 +195,13 @@ pub enum Fixed {
TimezoneName,
/// 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`,
/// which is same to [`FixedOffset`](../offset/struct.FixedOffset.html)'s range.
TimezoneOffsetColon,
/// 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.
/// The offset is limited from `-24:00` to `+24:00`,
/// 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.
Literal(&'a str),
/// Same to `Literal` but with the string owned by the item.
#[cfg(any(feature = "alloc", feature = "std", test))]
OwnedLiteral(Box<str>),
/// Whitespace. Prints literally but reads zero or more whitespace.
Space(&'a str),
/// Same to `Space` but with the string owned by the item.
#[cfg(any(feature = "alloc", feature = "std", test))]
OwnedSpace(Box<str>),
/// Numeric item. Can be optionally padded to the maximal length (if any) when formatting;
/// the parser simply ignores any padded whitespace and zeroes.
@ -305,13 +317,7 @@ enum ParseErrorKind {
/// Same to `Result<T, ParseError>`.
pub type ParseResult<T> = Result<T, ParseError>;
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.description().fmt(f)
}
}
impl Error for ParseError {
impl ParseError {
fn description(&self) -> &str {
match self.0 {
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
const OUT_OF_RANGE: ParseError = ParseError(ParseErrorKind::OutOfRange);
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.
/// Internally used by `DelayedFormat`.
#[cfg(any(feature = "alloc", feature = "std", test))]
pub fn format<'a, I>(
w: &mut fmt::Formatter,
date: Option<&NaiveDate>,
@ -356,12 +376,13 @@ pub fn format<'a, I>(
static LONG_WEEKDAYS: [&'static str; 7] =
["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
use std::fmt::Write;
use core::fmt::Write;
let mut result = String::new();
for item in items {
match item {
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::Numeric(spec, pad) => {
@ -598,6 +619,7 @@ pub mod strftime;
/// 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.
#[cfg(any(feature = "alloc", feature = "std", test))]
#[derive(Debug)]
pub struct DelayedFormat<I> {
/// The date view, if any.
@ -610,6 +632,7 @@ pub struct DelayedFormat<I> {
items: I,
}
#[cfg(any(feature = "alloc", feature = "std", test))]
impl<'a, I: Iterator<Item=Item<'a>> + Clone> DelayedFormat<I> {
/// Makes a new `DelayedFormat` value out of local date and time.
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> {
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())

View File

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

View File

@ -387,6 +387,8 @@
#![deny(missing_docs)]
#![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
// backward compatibility, and this appeases clippy. If minimum rustc
// becomes 1.17, should be able to remove this, those 'static lifetimes,
@ -403,6 +405,13 @@
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")]
extern crate time as oldtime;
extern crate num_integer;
@ -513,6 +522,41 @@ pub mod 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 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
/// [`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.
@ -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`.
#[derive(Clone, PartialEq)]
@ -699,14 +757,14 @@ impl fmt::Debug for ParseWeekdayError {
#[cfg(feature = "serde")]
mod weekday_serde {
use super::Weekday;
use std::fmt;
use core::fmt;
use serdelib::{ser, de};
impl ser::Serialize for Weekday {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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.
use std::{str, fmt};
use std::ops::{Add, Sub, AddAssign, SubAssign};
use core::{str, fmt};
use core::ops::{Add, Sub, AddAssign, SubAssign};
use num_traits::ToPrimitive;
use oldtime::Duration as OldDuration;
@ -12,7 +12,9 @@ use {Weekday, Datelike};
use div::div_mod_floor;
use naive::{NaiveTime, NaiveDateTime, IsoWeek};
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::internals::{self, DateImpl, Of, Mdf, YearFlags};
@ -916,6 +918,7 @@ impl NaiveDate {
/// # let d = NaiveDate::from_ymd(2015, 9, 5);
/// assert_eq!(format!("{}", d.format_with_items(fmt)), "2015-09-05");
/// ~~~~
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline]
pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I>
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("%A, %-d %B, %C%y")), "Saturday, 5 September, 2015");
/// ~~~~
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt))
@ -1387,7 +1391,7 @@ impl SubAssign<OldDuration> for NaiveDate {
/// Subtracts another `NaiveDate` from the current date.
/// Returns a `Duration` of integral numbers.
///
///
/// This does not overflow or underflow at all,
/// as all possible output fits in the range of `Duration`.
///
@ -1600,7 +1604,7 @@ mod rustc_serialize {
#[cfg(feature = "serde")]
mod serde {
use std::fmt;
use core::fmt;
use super::NaiveDate;
use serdelib::{ser, de};
@ -1629,15 +1633,23 @@ mod serde {
impl<'de> de::Visitor<'de> for NaiveDateVisitor {
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")
}
#[cfg(any(feature = "std", test))]
fn visit_str<E>(self, value: &str) -> Result<NaiveDate, E>
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.
use std::{str, fmt, hash};
use std::ops::{Add, Sub, AddAssign, SubAssign};
use core::{str, fmt, hash};
use core::ops::{Add, Sub, AddAssign, SubAssign};
use num_traits::ToPrimitive;
use oldtime::Duration as OldDuration;
@ -12,7 +12,9 @@ use {Weekday, Timelike, Datelike};
use div::div_mod_floor;
use naive::{NaiveTime, NaiveDate, IsoWeek};
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`
/// 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);
/// assert_eq!(format!("{}", dt.format_with_items(fmt)), "2015-09-05 23:56:04");
/// ~~~~
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline]
pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I>
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("around %l %p on %b %-d")), "around 11 PM on Sep 5");
/// ~~~~
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt))
@ -1663,7 +1667,7 @@ pub mod rustc_serialize {
/// Tools to help serializing/deserializing `NaiveDateTime`s
#[cfg(feature = "serde")]
pub mod serde {
use std::fmt;
use core::fmt;
use super::{NaiveDateTime};
use serdelib::{ser, de};
@ -1702,7 +1706,7 @@ pub mod serde {
fn visit_str<E>(self, value: &str) -> Result<NaiveDateTime, E>
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(); }
/// ```
pub mod ts_nanoseconds {
use std::fmt;
use core::fmt;
use serdelib::{ser, de};
use NaiveDateTime;
use {NaiveDateTime, ne_timestamp};
/// 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,
(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>
@ -1854,7 +1858,7 @@ pub mod serde {
{
NaiveDateTime::from_timestamp_opt(value as i64 / 1_000_000_000,
(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(); }
/// ```
pub mod ts_milliseconds {
use std::fmt;
use core::fmt;
use serdelib::{ser, de};
use NaiveDateTime;
use {NaiveDateTime, ne_timestamp};
/// 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,
((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>
@ -1999,7 +2003,7 @@ pub mod serde {
{
NaiveDateTime::from_timestamp_opt((value / 1000) as i64,
((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(); }
/// ```
pub mod ts_seconds {
use std::fmt;
use core::fmt;
use serdelib::{ser, de};
use NaiveDateTime;
use {NaiveDateTime, ne_timestamp};
/// Serialize a UTC datetime into an integer number of seconds since the epoch
///
@ -2135,14 +2139,14 @@ pub mod serde {
where E: de::Error
{
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>
where E: de::Error
{
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
use std::{i32, fmt};
use core::{i32, fmt};
use num_traits::FromPrimitive;
use Weekday;
use div::{div_rem, mod_floor};

View File

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

View File

@ -3,14 +3,16 @@
//! ISO 8601 time without timezone.
use std::{str, fmt, hash};
use std::ops::{Add, Sub, AddAssign, SubAssign};
use core::{str, fmt, hash};
use core::ops::{Add, Sub, AddAssign, SubAssign};
use oldtime::Duration as OldDuration;
use Timelike;
use div::div_mod_floor;
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.
/// Allows for the nanosecond precision and optional leap second representation.
@ -681,7 +683,7 @@ impl NaiveTime {
// `rhs.frac`|========================================>|
// | | | `self - rhs` | |
use std::cmp::Ordering;
use core::cmp::Ordering;
let secs = i64::from(self.secs) - i64::from(rhs.secs);
let frac = i64::from(self.frac) - i64::from(rhs.frac);
@ -723,6 +725,7 @@ impl NaiveTime {
/// # let t = NaiveTime::from_hms(23, 56, 4);
/// assert_eq!(format!("{}", t.format_with_items(fmt)), "23:56:04");
/// ~~~~
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline]
pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I>
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("%-I:%M %p")), "11:56 PM");
/// ~~~~
#[cfg(any(feature = "alloc", feature = "std", test))]
#[inline]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt))
@ -1411,7 +1415,7 @@ mod rustc_serialize {
#[cfg(feature = "serde")]
mod serde {
use std::fmt;
use core::fmt;
use super::NaiveTime;
use serdelib::{ser, de};
@ -1431,7 +1435,7 @@ mod serde {
impl<'de> de::Visitor<'de> for NaiveTimeVisitor {
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")
}
@ -1439,7 +1443,7 @@ mod serde {
fn visit_str<E>(self, value: &str) -> Result<NaiveTime, E>
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.
use std::ops::{Add, Sub};
use std::fmt;
use core::ops::{Add, Sub};
use core::fmt;
use oldtime::Duration as OldDuration;
use Timelike;

View File

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

View File

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

View File

@ -10,10 +10,11 @@
//! Temporal quantification
use std::{fmt, i64};
use core::{fmt, i64};
#[cfg(any(feature = "std", test))]
use std::error::Error;
use std::ops::{Add, Sub, Mul, Div, Neg};
use std::time::Duration as StdDuration;
use core::ops::{Add, Sub, Mul, Div, Neg};
use core::time::Duration as StdDuration;
/// The number of nanoseconds in a microsecond.
const NANOS_PER_MICRO: i32 = 1000;
@ -392,15 +393,22 @@ impl fmt::Display for Duration {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
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 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.description())
}
}
#[cfg(any(feature = "std", test))]
impl Error for OutOfRangeError {
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.
use Timelike;
use std::ops::{Add, Sub};
use core::ops::{Add, Sub};
use oldtime::Duration;
/// Extension trait for subsecond rounding or truncation to a maximum number