Skip to content

Commit 0615cd2

Browse files
committed
Cleanup utils module
1 parent bca9957 commit 0615cd2

File tree

5 files changed

+177
-192
lines changed

5 files changed

+177
-192
lines changed

src/builtins/core/year_month.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! This module implements `YearMonth` and any directly related algorithms.
22
3-
use alloc::string::String;
3+
use alloc::{format, string::String};
44
use core::{cmp::Ordering, str::FromStr};
55

66
use tinystr::TinyAsciiStr;
@@ -9,7 +9,6 @@ use crate::{
99
iso::{year_month_within_limits, IsoDate},
1010
options::{ArithmeticOverflow, DifferenceOperation, DifferenceSettings, DisplayCalendar},
1111
parsers::{FormattableCalendar, FormattableDate, FormattableYearMonth},
12-
utils::pad_iso_year,
1312
Calendar, MonthCode, TemporalError, TemporalResult, TemporalUnwrap,
1413
};
1514

@@ -103,11 +102,19 @@ impl PlainYearMonth {
103102
self.iso.year
104103
}
105104

106-
/// Returns the padded ISO year string
105+
/// 3.5.11 PadISOYear ( y )
106+
///
107+
/// Returns a String representation of y suitable for inclusion in an ISO 8601 string.
107108
#[inline]
108109
#[must_use]
109110
pub fn padded_iso_year_string(&self) -> String {
110-
pad_iso_year(self.iso.year)
111+
let year = self.iso.year;
112+
if (0..9999).contains(&year) {
113+
return format!("{:04}", year);
114+
}
115+
let year_sign = if year > 0 { "+" } else { "-" };
116+
let year_string = format!("{:06}", year.abs());
117+
format!("{year_sign}{year_string}",)
111118
}
112119

113120
/// Returns the iso month value for this `YearMonth`.

src/iso.rs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ impl IsoDateTime {
9191
// 3. Let epochMilliseconds be 𝔽((epochNanoseconds - remainderNs) / 10^6).
9292
let epoch_millis = (mathematical_nanos - remainder_nanos) / 1_000_000;
9393

94-
let (year, month, day) = utils::ymd_from_epoch_milliseconds(epoch_millis);
94+
let (year, month, day) = utils::Epoch::new(epoch_millis).ymd();
9595

9696
// 7. Let hour be ℝ(! HourFromTime(epochMilliseconds)).
9797
let hour = epoch_millis.div_euclid(3_600_000).rem_euclid(24);
@@ -344,8 +344,7 @@ impl IsoDate {
344344
/// Equivalent to `BalanceISODate`.
345345
pub(crate) fn balance(year: i32, month: i32, day: i32) -> Self {
346346
let epoch_days = iso_date_to_epoch_days(year, month, day);
347-
let ms = utils::epoch_days_to_epoch_ms(epoch_days, 0);
348-
let (year, month, day) = utils::ymd_from_epoch_milliseconds(ms);
347+
let (year, month, day) = utils::Epoch::from_days(epoch_days).ymd();
349348
Self::new_unchecked(year, month, day)
350349
}
351350

@@ -367,7 +366,7 @@ impl IsoDate {
367366
/// Equivalent to `IsoDateToEpochDays`
368367
#[inline]
369368
pub(crate) fn to_epoch_days(self) -> i32 {
370-
utils::epoch_days_from_gregorian_date(self.year, self.month, self.day)
369+
utils::Epoch::from_gregorian_date(self.year, self.month, self.day).days()
371370
}
372371

373372
/// Returns if the current `IsoDate` is valid.
@@ -488,12 +487,13 @@ impl IsoDate {
488487

489488
// NOTE: Below is adapted from the polyfill. Preferring this as it avoids looping.
490489
// 11. Let weeks be 0.
491-
let days = utils::epoch_days_from_gregorian_date(other.year, other.month, other.day)
492-
- utils::epoch_days_from_gregorian_date(
490+
let days = utils::Epoch::from_gregorian_date(other.year, other.month, other.day).days()
491+
- utils::Epoch::from_gregorian_date(
493492
constrained.year,
494493
constrained.month,
495494
constrained.day,
496-
);
495+
)
496+
.days();
497497

498498
let (weeks, days) = if largest_unit == TemporalUnit::Week {
499499
(days / 7, days % 7)
@@ -905,8 +905,7 @@ const MAX_EPOCH_DAYS: i32 = 10i32.pow(8) + 1;
905905
#[inline]
906906
/// Utility function to determine if a `DateTime`'s components create a `DateTime` within valid limits
907907
fn iso_dt_within_valid_limits(date: IsoDate, time: &IsoTime) -> bool {
908-
if utils::epoch_days_from_gregorian_date(date.year, date.month, date.day).abs() > MAX_EPOCH_DAYS
909-
{
908+
if utils::Epoch::from_gregorian_date(date.year, date.month, date.day).days() > MAX_EPOCH_DAYS {
910909
return false;
911910
}
912911

@@ -927,7 +926,7 @@ fn utc_epoch_nanos(date: IsoDate, time: &IsoTime) -> TemporalResult<EpochNanosec
927926
#[inline]
928927
fn to_unchecked_epoch_nanoseconds(date: IsoDate, time: &IsoTime) -> i128 {
929928
let ms = time.to_epoch_ms();
930-
let epoch_ms = utils::epoch_days_to_epoch_ms(date.to_epoch_days(), ms);
929+
let epoch_ms = utils::Epoch::from_days(date.to_epoch_days()).millis() + ms;
931930
epoch_ms as i128 * 1_000_000 + time.microsecond as i128 * 1_000 + time.nanosecond as i128
932931
}
933932

@@ -943,10 +942,10 @@ pub(crate) fn iso_date_to_epoch_days(year: i32, month: i32, day: i32) -> i32 {
943942
let resolved_month = month.rem_euclid(12) as u8;
944943
// 3. Find a time t such that EpochTimeToEpochYear(t) is resolvedYear,
945944
// EpochTimeToMonthInYear(t) is resolvedMonth, and EpochTimeToDate(t) is 1.
946-
let epoch_days = utils::epoch_days_from_gregorian_date(resolved_year, resolved_month, 1);
945+
let epoch_days = utils::Epoch::from_gregorian_date(resolved_year, resolved_month, 1);
947946

948947
// 4. Return EpochTimeToDayNumber(t) + date - 1.
949-
epoch_days + day - 1
948+
epoch_days.days() + day - 1
950949
}
951950

952951
#[inline]
@@ -997,13 +996,13 @@ fn balance_iso_year_month(year: i32, month: i32) -> (i32, u8) {
997996
/// Note: month is 1 based.
998997
#[inline]
999998
pub(crate) fn constrain_iso_day(year: i32, month: u8, day: u8) -> u8 {
1000-
let days_in_month = utils::iso_days_in_month(year, month);
999+
let days_in_month = utils::Epoch::from_gregorian_date(year, month, 1).days_in_month();
10011000
day.clamp(1, days_in_month)
10021001
}
10031002

10041003
#[inline]
10051004
pub(crate) fn is_valid_iso_day(year: i32, month: u8, day: u8) -> bool {
1006-
let days_in_month = utils::iso_days_in_month(year, month);
1005+
let days_in_month = utils::Epoch::from_gregorian_date(year, month, 1).days_in_month();
10071006
(1..=days_in_month).contains(&day)
10081007
}
10091008

src/tzdb.rs

Lines changed: 26 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -358,12 +358,11 @@ fn resolve_posix_tz_string_for_epoch_seconds(
358358
// TODO: Resolve safety issue around utils.
359359
// Using f64 is a hold over from early implementation days and should
360360
// be moved away from.
361+
let epoch = utils::Epoch::from_seconds(seconds);
361362

362-
let (is_transition_day, transition) =
363-
cmp_seconds_to_transitions(&start.day, &end.day, seconds)?;
363+
let (is_transition_day, transition) = cmp_seconds_to_transitions(&start.day, &end.day, epoch)?;
364364

365-
let transition =
366-
compute_tz_for_epoch_seconds(is_transition_day, transition, seconds, dst_variant);
365+
let transition = compute_tz_for_epoch(is_transition_day, transition, epoch, dst_variant);
367366
let std_offset = LocalTimeRecord::from_standard_time(&posix_tz_string.std_info).offset;
368367
let dst_offset = LocalTimeRecord::from_daylight_savings_time(&dst_variant.variant_info).offset;
369368
let (old_offset, new_offset) = match transition {
@@ -374,23 +373,20 @@ fn resolve_posix_tz_string_for_epoch_seconds(
374373
TransitionType::Dst => start,
375374
TransitionType::Std => end,
376375
};
377-
let year = utils::epoch_time_to_epoch_year(seconds * 1000);
378-
let year_epoch = utils::epoch_days_for_year(year) * 86400;
379-
let leap_day = utils::mathematical_in_leap_year(seconds * 1000) as u16;
376+
let year_epoch = epoch.year() * 86400;
377+
let leap_day = epoch.in_leap_year();
380378

381379
let days = match transition.day {
382-
TransitionDay::NoLeap(day) if day > 59 => day - 1 + leap_day,
380+
TransitionDay::NoLeap(day) if day > 59 => day - 1 + u16::from(leap_day),
383381
TransitionDay::NoLeap(day) => day - 1,
384382
TransitionDay::WithLeap(day) => day,
385383
TransitionDay::Mwd(month, week, day) => {
386-
let days_to_month = utils::month_to_day((month - 1) as u8, leap_day);
387-
let days_in_month = u16::from(utils::iso_days_in_month(year, month as u8) - 1);
384+
let transition_epoch = utils::Epoch::from_gregorian_date(year_epoch, month as u8, 1);
385+
let days_to_month = transition_epoch.day_of_year_until_start_of_month();
386+
let days_in_month = u16::from(transition_epoch.days_in_month());
388387

389388
// Month starts in the day...
390-
let day_offset =
391-
(u16::from(utils::epoch_seconds_to_day_of_week(i64::from(year_epoch)))
392-
+ days_to_month)
393-
.rem_euclid(7);
389+
let day_offset = (u16::from(epoch.day_in_week()) + days_to_month).rem_euclid(7);
394390

395391
// EXAMPLE:
396392
//
@@ -456,10 +452,11 @@ fn resolve_posix_tz_string(
456452
// NOTE:
457453
// STD -> DST == start
458454
// DST -> STD == end
455+
let epoch = utils::Epoch::from_seconds(seconds);
459456
let (is_transition_day, is_dst) =
460-
cmp_seconds_to_transitions(&dst.start_date.day, &dst.end_date.day, seconds)?;
457+
cmp_seconds_to_transitions(&dst.start_date.day, &dst.end_date.day, epoch)?;
461458
if is_transition_day {
462-
let time = utils::epoch_ms_to_ms_in_day(seconds * 1_000) as i64 / 1_000;
459+
let time = epoch.millis_since_start_of_day() as i64 / 1_000;
463460
let transition_time = if is_dst == TransitionType::Dst {
464461
dst.start_date.time.0
465462
} else {
@@ -493,20 +490,19 @@ fn resolve_posix_tz_string(
493490
}
494491
}
495492

496-
fn compute_tz_for_epoch_seconds(
493+
fn compute_tz_for_epoch(
497494
is_transition_day: bool,
498495
transition: TransitionType,
499-
seconds: i64,
496+
epoch: utils::Epoch,
500497
dst_variant: &DstTransitionInfo,
501498
) -> TransitionType {
499+
let time = epoch.millis_since_start_of_day() / 1000;
502500
if is_transition_day && transition == TransitionType::Dst {
503-
let time = utils::epoch_ms_to_ms_in_day(seconds * 1_000) / 1_000;
504501
let transition_time = dst_variant.start_date.time.0 - dst_variant.variant_info.offset.0;
505502
if i64::from(time) < transition_time {
506503
return TransitionType::Std;
507504
}
508505
} else if is_transition_day {
509-
let time = utils::epoch_ms_to_ms_in_day(seconds * 1_000) / 1_000;
510506
let transition_time = dst_variant.end_date.time.0 - dst_variant.variant_info.offset.0;
511507
if i64::from(time) < transition_time {
512508
return TransitionType::Dst;
@@ -523,26 +519,26 @@ fn compute_tz_for_epoch_seconds(
523519
struct Mwd(u16, u16, u16);
524520

525521
impl Mwd {
526-
fn from_seconds(seconds: i64) -> Self {
527-
let month = utils::epoch_ms_to_month_in_year(seconds * 1_000) as u16;
528-
let day_of_month = utils::epoch_seconds_to_day_of_month(seconds);
522+
fn from_epoch(epoch: utils::Epoch) -> Self {
523+
let month = epoch.month_in_year();
524+
let day_of_month = epoch.day_of_month();
529525
let week_of_month = day_of_month / 7 + 1;
530-
let day_of_week = utils::epoch_seconds_to_day_of_week(seconds);
531-
Self(month, week_of_month, u16::from(day_of_week))
526+
let day_in_week = epoch.day_in_week();
527+
Self(u16::from(month), week_of_month, u16::from(day_in_week))
532528
}
533529
}
534530

535531
fn cmp_seconds_to_transitions(
536532
start: &TransitionDay,
537533
end: &TransitionDay,
538-
seconds: i64,
534+
epoch: utils::Epoch,
539535
) -> TemporalResult<(bool, TransitionType)> {
540536
let cmp_result = match (start, end) {
541537
(
542538
TransitionDay::Mwd(start_month, start_week, start_day),
543539
TransitionDay::Mwd(end_month, end_week, end_day),
544540
) => {
545-
let mwd = Mwd::from_seconds(seconds);
541+
let mwd = Mwd::from_epoch(epoch);
546542
let start = Mwd(*start_month, *start_week, *start_day);
547543
let end = Mwd(*end_month, *end_week, *end_day);
548544

@@ -556,7 +552,7 @@ fn cmp_seconds_to_transitions(
556552
(is_transition, is_dst)
557553
}
558554
(TransitionDay::WithLeap(start), TransitionDay::WithLeap(end)) => {
559-
let day_in_year = utils::epoch_time_to_day_in_year(seconds * 1_000) as u16;
555+
let day_in_year = epoch.days_in_year();
560556
let is_transition = *start == day_in_year || *end == day_in_year;
561557
let is_dst = if start > end {
562558
day_in_year < *end || *start <= day_in_year
@@ -567,7 +563,7 @@ fn cmp_seconds_to_transitions(
567563
}
568564
// TODO: do we need to modify the logic for leap years?
569565
(TransitionDay::NoLeap(start), TransitionDay::NoLeap(end)) => {
570-
let day_in_year = utils::epoch_time_to_day_in_year(seconds * 1_000) as u16;
566+
let day_in_year = epoch.days_in_year();
571567
let is_transition = *start == day_in_year || *end == day_in_year;
572568
let is_dst = if start > end {
573569
day_in_year < *end || *start <= day_in_year
@@ -1082,10 +1078,7 @@ mod tests {
10821078
}
10831079

10841080
#[test]
1085-
fn mwd_transition_epoch() {
1086-
#[cfg(not(target_os = "windows"))]
1087-
let tzif = Tzif::read_tzif("Europe/Berlin").unwrap();
1088-
#[cfg(target_os = "windows")]
1081+
fn mwd_transition_epoch_with_slim_format() {
10891082
let tzif = Tzif::from_bytes(jiff_tzdb::get("Europe/Berlin").unwrap().1).unwrap();
10901083

10911084
let start_date = crate::iso::IsoDate {

0 commit comments

Comments
 (0)