Skip to content

Commit

Permalink
Create, use API for magic constants
Browse files Browse the repository at this point in the history
  • Loading branch information
jhpratt committed Apr 12, 2023
1 parent 216d872 commit 79ca269
Show file tree
Hide file tree
Showing 19 changed files with 409 additions and 242 deletions.
88 changes: 88 additions & 0 deletions time-core/src/convert.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#![allow(clippy::missing_docs_in_private_items)] // TODO temporary

macro_rules! declare_structs {
($($t:ident)*) => {$(
#[derive(Debug, Copy, Clone)]
pub struct $t;

impl $t {
pub const fn per<T>(self, _: T) -> <(Self, T) as Per>::Output
where
(Self, T): Per,
T: Copy,
{
<(Self, T)>::VALUE
}
}
)*};
}

declare_structs! {
Nanosecond
Microsecond
Millisecond
Second
Minute
Hour
Day
Week
}

mod sealed {
pub trait Sealed {}
}

pub trait Per: sealed::Sealed {
type Output;

const VALUE: Self::Output;
}

macro_rules! impl_per {
($($t:ty : $x:ident in $y:ident = $val:expr)*) => {$(
impl sealed::Sealed for ($x, $y) {}

impl Per for ($x, $y) {
type Output = $t;

const VALUE: $t = $val;
}
)*};
}

impl_per! {
u16: Nanosecond in Microsecond = 1_000
u32: Nanosecond in Millisecond = 1_000_000
u32: Nanosecond in Second = 1_000_000_000
u64: Nanosecond in Minute = 60_000_000_000
u64: Nanosecond in Hour = 3_600_000_000_000
u64: Nanosecond in Day = 86_400_000_000_000
u64: Nanosecond in Week = 604_800_000_000_000

u16: Microsecond in Millisecond = 1_000
u32: Microsecond in Second = 1_000_000
u32: Microsecond in Minute = 60_000_000
u32: Microsecond in Hour = 3_600_000_000
u64: Microsecond in Day = 86_400_000_000
u64: Microsecond in Week = 604_800_000_000

u16: Millisecond in Second = 1_000
u16: Millisecond in Minute = 60_000
u32: Millisecond in Hour = 3_600_000
u32: Millisecond in Day = 86_400_000
u32: Millisecond in Week = 604_800_000

u8: Second in Minute = 60
u16: Second in Hour = 3_600
u32: Second in Day = 86_400
u32: Second in Week = 604_800

u8: Minute in Hour = 60
u16: Minute in Day = 1_440
u16: Minute in Week = 10_080

u8: Hour in Day = 24
u8: Hour in Week = 168

u8: Day in Week = 7
}
1 change: 1 addition & 0 deletions time-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,5 @@
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/55999857")]
#![doc(test(attr(deny(warnings))))]

pub mod convert;
pub mod util;
5 changes: 3 additions & 2 deletions time-macros/src/offset.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::iter::Peekable;

use proc_macro::{token_stream, Span, TokenTree};
use time_core::convert::*;

use crate::helpers::{consume_any_ident, consume_number, consume_punct};
use crate::to_tokens::ToTokenTree;
Expand Down Expand Up @@ -58,14 +59,14 @@ pub(crate) fn parse(chars: &mut Peekable<token_stream::IntoIter>) -> Result<Offs
span_start: Some(hours_span),
span_end: Some(hours_span),
})
} else if minutes >= 60 {
} else if minutes >= Minute.per(Hour) as _ {
Err(Error::InvalidComponent {
name: "minute",
value: minutes.to_string(),
span_start: Some(minutes_span),
span_end: Some(minutes_span),
})
} else if seconds >= 60 {
} else if seconds >= Second.per(Minute) as _ {
Err(Error::InvalidComponent {
name: "second",
value: seconds.to_string(),
Expand Down
9 changes: 5 additions & 4 deletions time-macros/src/time.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::iter::Peekable;

use proc_macro::{token_stream, Span, TokenTree};
use time_core::convert::*;

use crate::helpers::{consume_any_ident, consume_number, consume_punct};
use crate::to_tokens::ToTokenTree;
Expand Down Expand Up @@ -72,21 +73,21 @@ pub(crate) fn parse(chars: &mut Peekable<token_stream::IntoIter>) -> Result<Time
(hour, Period::Pm) => hour + 12,
};

if hour >= 24 {
if hour >= Hour.per(Day) {
Err(Error::InvalidComponent {
name: "hour",
value: hour.to_string(),
span_start: Some(hour_span),
span_end: Some(period_span.unwrap_or(hour_span)),
})
} else if minute >= 60 {
} else if minute >= Minute.per(Hour) {
Err(Error::InvalidComponent {
name: "minute",
value: minute.to_string(),
span_start: Some(minute_span),
span_end: Some(minute_span),
})
} else if second >= 60. {
} else if second >= Second.per(Minute) as _ {
Err(Error::InvalidComponent {
name: "second",
value: second.to_string(),
Expand All @@ -98,7 +99,7 @@ pub(crate) fn parse(chars: &mut Peekable<token_stream::IntoIter>) -> Result<Time
hour,
minute,
second: second.trunc() as _,
nanosecond: (second.fract() * 1_000_000_000.).round() as _,
nanosecond: (second.fract() * Nanosecond.per(Second) as f64).round() as _,
})
}
}
Expand Down
13 changes: 9 additions & 4 deletions time/src/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use core::time::Duration as StdDuration;
#[cfg(feature = "formatting")]
use std::io;

use crate::convert::*;
#[cfg(feature = "formatting")]
use crate::formatting::Formattable;
#[cfg(feature = "parsing")]
Expand Down Expand Up @@ -1013,8 +1014,10 @@ impl Add<StdDuration> for Date {
type Output = Self;

fn add(self, duration: StdDuration) -> Self::Output {
Self::from_julian_day(self.to_julian_day() + (duration.as_secs() / 86_400) as i32)
.expect("overflow adding duration to date")
Self::from_julian_day(
self.to_julian_day() + (duration.as_secs() / Second.per(Day) as u64) as i32,
)
.expect("overflow adding duration to date")
}
}

Expand All @@ -1033,8 +1036,10 @@ impl Sub<StdDuration> for Date {
type Output = Self;

fn sub(self, duration: StdDuration) -> Self::Output {
Self::from_julian_day(self.to_julian_day() - (duration.as_secs() / 86_400) as i32)
.expect("overflow subtracting duration from date")
Self::from_julian_day(
self.to_julian_day() - (duration.as_secs() / Second.per(Day) as u64) as i32,
)
.expect("overflow subtracting duration from date")
}
}

Expand Down
46 changes: 25 additions & 21 deletions time/src/date_time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use std::io;
#[cfg(feature = "std")]
use std::time::SystemTime;

use crate::convert::*;
use crate::date::{MAX_YEAR, MIN_YEAR};
#[cfg(feature = "formatting")]
use crate::formatting::Formattable;
Expand Down Expand Up @@ -257,14 +258,14 @@ impl<O: MaybeOffset> DateTime<O> {

// Use the unchecked method here, as the input validity has already been verified.
let date = Date::from_julian_day_unchecked(
UNIX_EPOCH_JULIAN_DAY + div_floor!(timestamp, 86_400) as i32,
UNIX_EPOCH_JULIAN_DAY + div_floor!(timestamp, Second.per(Day) as i64) as i32,
);

let seconds_within_day = timestamp.rem_euclid(86_400);
let seconds_within_day = timestamp.rem_euclid(Second.per(Day) as _);
let time = Time::__from_hms_nanos_unchecked(
(seconds_within_day / 3_600) as _,
((seconds_within_day % 3_600) / 60) as _,
(seconds_within_day % 60) as _,
(seconds_within_day / Second.per(Hour) as i64) as _,
((seconds_within_day % Second.per(Hour) as i64) / Minute.per(Hour) as i64) as _,
(seconds_within_day % Second.per(Minute) as i64) as _,
0,
);

Expand All @@ -279,17 +280,18 @@ impl<O: MaybeOffset> DateTime<O> {
where
O: HasLogicalOffset,
{
let datetime = const_try!(Self::from_unix_timestamp(
div_floor!(timestamp, 1_000_000_000) as i64
));
let datetime = const_try!(Self::from_unix_timestamp(div_floor!(
timestamp,
Nanosecond.per(Second) as i128
) as i64));

Ok(Self {
date: datetime.date,
time: Time::__from_hms_nanos_unchecked(
datetime.hour(),
datetime.minute(),
datetime.second(),
timestamp.rem_euclid(1_000_000_000) as u32,
timestamp.rem_euclid(Nanosecond.per(Second) as _) as u32,
),
offset: maybe_offset_from_offset::<O>(UtcOffset::UTC),
})
Expand Down Expand Up @@ -450,9 +452,10 @@ impl<O: MaybeOffset> DateTime<O> {
{
let offset = maybe_offset_as_offset::<O>(self.offset).whole_seconds() as i64;

let days = (self.to_julian_day() as i64 - UNIX_EPOCH_JULIAN_DAY as i64) * 86_400;
let hours = self.hour() as i64 * 3_600;
let minutes = self.minute() as i64 * 60;
let days =
(self.to_julian_day() as i64 - UNIX_EPOCH_JULIAN_DAY as i64) * Second.per(Day) as i64;
let hours = self.hour() as i64 * Second.per(Hour) as i64;
let minutes = self.minute() as i64 * Second.per(Minute) as i64;
let seconds = self.second() as i64;
days + hours + minutes + seconds - offset
}
Expand All @@ -461,7 +464,7 @@ impl<O: MaybeOffset> DateTime<O> {
where
O: HasLogicalOffset,
{
self.unix_timestamp() as i128 * 1_000_000_000 + self.nanosecond() as i128
self.unix_timestamp() as i128 * Nanosecond.per(Second) as i128 + self.nanosecond() as i128
}
// endregion unix timestamp getters
// endregion: getters
Expand Down Expand Up @@ -543,12 +546,12 @@ impl<O: MaybeOffset> DateTime<O> {
let mut ordinal = ordinal as i16;

// Cascade the values twice. This is needed because the values are adjusted twice above.
cascade!(second in 0..60 => minute);
cascade!(second in 0..60 => minute);
cascade!(minute in 0..60 => hour);
cascade!(minute in 0..60 => hour);
cascade!(hour in 0..24 => ordinal);
cascade!(hour in 0..24 => ordinal);
cascade!(second in 0..Second.per(Minute) as i16 => minute);
cascade!(second in 0..Second.per(Minute) as i16 => minute);
cascade!(minute in 0..Minute.per(Hour) as i16 => hour);
cascade!(minute in 0..Minute.per(Hour) as i16 => hour);
cascade!(hour in 0..Hour.per(Day) as i8 => ordinal);
cascade!(hour in 0..Hour.per(Day) as i8 => ordinal);
cascade!(ordinal => year);

debug_assert!(ordinal > 0);
Expand Down Expand Up @@ -1137,7 +1140,7 @@ impl From<DateTime<offset_kind::Fixed>> for SystemTime {
impl From<js_sys::Date> for DateTime<offset_kind::Fixed> {
fn from(js_date: js_sys::Date) -> Self {
// get_time() returns milliseconds
let timestamp_nanos = (js_date.get_time() * 1_000_000.0) as i128;
let timestamp_nanos = (js_date.get_time() * Nanosecond.per(Millisecond) as f64) as i128;
Self::from_unix_timestamp_nanos(timestamp_nanos)
.expect("invalid timestamp: Timestamp cannot fit in range")
}
Expand All @@ -1151,7 +1154,8 @@ impl From<js_sys::Date> for DateTime<offset_kind::Fixed> {
impl From<DateTime<offset_kind::Fixed>> for js_sys::Date {
fn from(datetime: DateTime<offset_kind::Fixed>) -> Self {
// new Date() takes milliseconds
let timestamp = (datetime.unix_timestamp_nanos() / 1_000_000) as f64;
let timestamp =
(datetime.unix_timestamp_nanos() / Nanosecond.per(Millisecond) as i128) as f64;
js_sys::Date::new(&timestamp.into())
}
}
Expand Down
Loading

0 comments on commit 79ca269

Please sign in to comment.