Implement Support for no_std
This adds a new `std` feature to chrono that is enabled by default. By deactivating this feature via `default-features = false` you can now use chrono in applications that don't use the standard library. The `serde` feature is supported as well. Resolves #336
This commit is contained in:
parent
bbfcfad44f
commit
9dc91f78ed
|
@ -24,17 +24,17 @@ appveyor = { repository = "chronotope/chrono" }
|
|||
name = "chrono"
|
||||
|
||||
[features]
|
||||
default = ["clock"]
|
||||
clock = ["time"]
|
||||
default = ["clock", "std"]
|
||||
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 }
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
[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"] }
|
|
@ -0,0 +1 @@
|
|||
#![no_std]
|
10
ci/travis.sh
10
ci/travis.sh
|
@ -85,6 +85,13 @@ build_only() {
|
|||
channel build -v --no-default-features
|
||||
}
|
||||
|
||||
build_core_test() {
|
||||
rustup target add thumbv6m-none-eabi --toolchain $CHANNEL
|
||||
cd ci/core-test
|
||||
channel build -v --target thumbv6m-none-eabi
|
||||
cd ../..
|
||||
}
|
||||
|
||||
run_clippy() {
|
||||
# cached installation will not work on a later nightly
|
||||
if [ -n "${TRAVIS}" ] && ! cargo install clippy --debug --force; then
|
||||
|
@ -119,3 +126,6 @@ build_and_test
|
|||
|
||||
CHANNEL=1.13.0
|
||||
build_only
|
||||
|
||||
CHANNEL=stable
|
||||
build_core_test
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
//! 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};
|
||||
|
|
|
@ -3,12 +3,16 @@
|
|||
|
||||
//! 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(not(any(feature = "std", test)))]
|
||||
use alloc::string::{String, ToString};
|
||||
|
||||
use {Weekday, Timelike, Datelike};
|
||||
#[cfg(feature="clock")]
|
||||
use offset::Local;
|
||||
|
@ -647,6 +651,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 +677,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 +705,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 +723,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 +760,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 +784,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,7 +913,9 @@ pub mod rustc_serialize {
|
|||
/// documented at re-export site
|
||||
#[cfg(feature = "serde")]
|
||||
pub mod serde {
|
||||
use std::fmt;
|
||||
use core::fmt;
|
||||
#[cfg(not(any(feature = "std", test)))]
|
||||
use alloc::format;
|
||||
use super::DateTime;
|
||||
#[cfg(feature="clock")]
|
||||
use offset::Local;
|
||||
|
@ -967,7 +975,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};
|
||||
|
@ -1114,7 +1122,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};
|
||||
|
@ -1261,7 +1269,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};
|
||||
|
|
|
@ -17,9 +17,13 @@
|
|||
|
||||
#![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;
|
||||
use alloc::boxed::Box;
|
||||
#[cfg(not(any(feature = "std", test)))]
|
||||
use alloc::string::{String, ToString};
|
||||
|
||||
use {Datelike, Timelike, Weekday, ParseWeekdayError};
|
||||
use div::{div_floor, mod_floor};
|
||||
|
@ -30,7 +34,7 @@ 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 +59,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 +189,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.
|
||||
|
@ -305,13 +309,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 +323,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);
|
||||
|
@ -356,7 +367,7 @@ 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 {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#![allow(deprecated)]
|
||||
|
||||
use std::usize;
|
||||
use core::usize;
|
||||
|
||||
use Weekday;
|
||||
|
||||
|
|
15
src/lib.rs
15
src/lib.rs
|
@ -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(not(any(feature = "std", test)))]
|
||||
extern crate alloc;
|
||||
#[cfg(any(feature = "std", test))]
|
||||
extern crate std as core;
|
||||
#[cfg(any(feature = "std", test))]
|
||||
extern crate std as alloc;
|
||||
|
||||
#[cfg(feature="clock")]
|
||||
extern crate time as oldtime;
|
||||
extern crate num_integer;
|
||||
|
@ -678,7 +687,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)]
|
||||
|
@ -697,7 +706,9 @@ impl fmt::Debug for ParseWeekdayError {
|
|||
#[cfg(feature = "serde")]
|
||||
mod weekday_serde {
|
||||
use super::Weekday;
|
||||
use std::fmt;
|
||||
use core::fmt;
|
||||
#[cfg(not(any(feature = "std", test)))]
|
||||
use alloc::format;
|
||||
use serdelib::{ser, de};
|
||||
|
||||
impl ser::Serialize for Weekday {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -1600,7 +1600,9 @@ mod rustc_serialize {
|
|||
|
||||
#[cfg(feature = "serde")]
|
||||
mod serde {
|
||||
use std::fmt;
|
||||
use core::fmt;
|
||||
#[cfg(not(any(feature = "std", test)))]
|
||||
use alloc::format;
|
||||
use super::NaiveDate;
|
||||
use serdelib::{ser, de};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -1663,7 +1663,9 @@ pub mod rustc_serialize {
|
|||
/// Tools to help serializing/deserializing `NaiveDateTime`s
|
||||
#[cfg(feature = "serde")]
|
||||
pub mod serde {
|
||||
use std::fmt;
|
||||
use core::fmt;
|
||||
#[cfg(not(any(feature = "std", test)))]
|
||||
use alloc::format;
|
||||
use super::{NaiveDateTime};
|
||||
use serdelib::{ser, de};
|
||||
|
||||
|
@ -1750,7 +1752,9 @@ pub mod serde {
|
|||
/// # fn main() { example().unwrap(); }
|
||||
/// ```
|
||||
pub mod ts_nanoseconds {
|
||||
use std::fmt;
|
||||
use core::fmt;
|
||||
#[cfg(not(any(feature = "std", test)))]
|
||||
use alloc::format;
|
||||
use serdelib::{ser, de};
|
||||
|
||||
use NaiveDateTime;
|
||||
|
@ -1895,7 +1899,9 @@ pub mod serde {
|
|||
/// # fn main() { example().unwrap(); }
|
||||
/// ```
|
||||
pub mod ts_milliseconds {
|
||||
use std::fmt;
|
||||
use core::fmt;
|
||||
#[cfg(not(any(feature = "std", test)))]
|
||||
use alloc::format;
|
||||
use serdelib::{ser, de};
|
||||
|
||||
use NaiveDateTime;
|
||||
|
@ -2040,7 +2046,9 @@ pub mod serde {
|
|||
/// # fn main() { example().unwrap(); }
|
||||
/// ```
|
||||
pub mod ts_seconds {
|
||||
use std::fmt;
|
||||
use core::fmt;
|
||||
#[cfg(not(any(feature = "std", test)))]
|
||||
use alloc::format;
|
||||
use serdelib::{ser, de};
|
||||
|
||||
use NaiveDateTime;
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
//! ISO 8601 week.
|
||||
|
||||
use std::fmt;
|
||||
use core::fmt;
|
||||
|
||||
use super::internals::{DateImpl, Of, YearFlags};
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
//! 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;
|
||||
|
@ -681,7 +681,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);
|
||||
|
@ -1411,7 +1411,9 @@ mod rustc_serialize {
|
|||
|
||||
#[cfg(feature = "serde")]
|
||||
mod serde {
|
||||
use std::fmt;
|
||||
use core::fmt;
|
||||
#[cfg(not(any(feature = "std", test)))]
|
||||
use alloc::format;
|
||||
use super::NaiveTime;
|
||||
use serdelib::{ser, de};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue