phoenix TZ

This commit is contained in:
aecsocket
2026-08-25 17:34:27 +01:00
parent 87aa698148
commit 8a0afa1bf7
3 changed files with 62 additions and 20 deletions
+5 -11
View File
@@ -54,18 +54,12 @@ async fn fetch_estimates(
let first_period = periods_iter.next().wrap_err("no first period")?;
let last_period = periods_iter.last().unwrap_or(first_period);
let range_start = first_period
.date()
.and_hms_opt(0, 0, 0)
.wrap_err("calculating payout period start")?
.and_utc();
let range_end = last_period
let range_start = aditude::phoenix_midnight(first_period.date());
let range_end_date = last_period
.date()
.checked_add_months(Months::new(1))
.wrap_err("calculating month after payout period end")?
.and_hms_opt(0, 0, 0)
.wrap_err("calculating payout period end")?
.and_utc();
.wrap_err("calculating month after payout period end")?;
let range_end = aditude::phoenix_midnight(range_end_date);
let metrics = aditude
.get_metrics_v2(aditude::v2::GetMetrics {
@@ -92,7 +86,7 @@ async fn fetch_estimates(
continue;
};
let date = row.time.date_naive();
let date = aditude::phoenix_date(row.time);
let period = YearMonth::from_day1(date);
let period_estimate = map.entry(period).or_insert(PeriodEstimate {
+28 -8
View File
@@ -8,9 +8,35 @@ pub mod v2;
use std::borrow::Cow;
use chrono::{DateTime, Duration, Utc};
use chrono::{DateTime, Duration, FixedOffset, NaiveDate, Utc};
use secrecy::SecretString;
const PHOENIX_UTC_OFFSET_SECONDS: i32 = 7 * 60 * 60;
fn phoenix_offset() -> FixedOffset {
FixedOffset::west_opt(PHOENIX_UTC_OFFSET_SECONDS)
.expect("Phoenix UTC offset should be valid")
}
/// Returns the UTC instant at which a calendar day starts in Phoenix.
///
/// Aditude buckets metrics in Phoenix time, which is MST (UTC-7) year-round.
#[must_use]
pub fn phoenix_midnight(date: NaiveDate) -> DateTime<Utc> {
date.and_hms_opt(0, 0, 0)
.expect("midnight should be valid")
.and_local_timezone(phoenix_offset())
.single()
.expect("a fixed offset should have one local midnight")
.with_timezone(&Utc)
}
/// Returns the Phoenix calendar date containing a UTC instant.
#[must_use]
pub fn phoenix_date(time: DateTime<Utc>) -> NaiveDate {
time.with_timezone(&phoenix_offset()).date_naive()
}
/// [Aditude](https://www.aditude.com/) client.
#[derive(Debug)]
pub struct Client {
@@ -70,13 +96,7 @@ impl Client {
/// range.
#[must_use]
pub fn yesterday(now: DateTime<Utc>) -> (DateTime<Utc>, DateTime<Utc>) {
let start = DateTime::<Utc>::from_naive_utc_and_offset(
(now - Duration::days(1))
.date_naive()
.and_hms_nano_opt(0, 0, 0, 0)
.unwrap_or_default(),
Utc,
);
let start = phoenix_midnight(phoenix_date(now - Duration::days(1)));
let end = start + Duration::days(1);
(start, end)
}
+29 -1
View File
@@ -1,7 +1,7 @@
#![expect(missing_docs, reason = "test crate")]
use aditude::{Client, mock::AditudeMock, v1, v2};
use chrono::{DateTime, Utc};
use chrono::{DateTime, NaiveDate, TimeZone, Utc};
use rust_decimal::dec;
#[tokio::test]
@@ -115,3 +115,31 @@ async fn test_yesterday() {
assert_eq!(real_yesterday, our_yesterday);
}
#[test]
fn phoenix_day_boundaries() {
let august_19 = NaiveDate::from_ymd_opt(2026, 8, 19).unwrap();
assert_eq!(
aditude::phoenix_midnight(august_19),
Utc.with_ymd_and_hms(2026, 8, 19, 7, 0, 0).unwrap(),
);
let before_phoenix_midnight =
Utc.with_ymd_and_hms(2026, 8, 20, 6, 59, 59).unwrap();
assert_eq!(
aditude::yesterday(before_phoenix_midnight),
(
Utc.with_ymd_and_hms(2026, 8, 18, 7, 0, 0).unwrap(),
Utc.with_ymd_and_hms(2026, 8, 19, 7, 0, 0).unwrap(),
),
);
let phoenix_midnight = Utc.with_ymd_and_hms(2026, 8, 20, 7, 0, 0).unwrap();
assert_eq!(
aditude::yesterday(phoenix_midnight),
(
Utc.with_ymd_and_hms(2026, 8, 19, 7, 0, 0).unwrap(),
Utc.with_ymd_and_hms(2026, 8, 20, 7, 0, 0).unwrap(),
),
);
}