refactor: switch from chrono to jiff

This commit is contained in:
Robert Perce 2026-04-03 11:54:36 -05:00
parent 79a054ab40
commit 3ffdf8f0d7
12 changed files with 205 additions and 161 deletions

View file

@ -7,19 +7,19 @@ use axum::{
};
use axum_extra::extract::Form;
use cache_bust::asset;
use chrono::DateTime;
use jiff::{Timestamp, Unit, tz::TimeZone};
use maud::{Markup, html};
use serde::Deserialize;
use serde_json::json;
use slug::slugify;
use sqlx::{QueryBuilder, Sqlite};
use sqlx::QueryBuilder;
use super::Layout;
use super::home::journal_section;
use crate::db::DbId;
use crate::models::user::AuthSession;
use crate::models::{HydratedContact, JournalEntry};
use crate::switchboard::{MentionHost, MentionHostType, insert_mentions, Switchboard};
use crate::switchboard::{MentionHost, MentionHostType, Switchboard, insert_mentions};
use crate::{AppError, AppState};
pub mod fields;
@ -40,22 +40,22 @@ pub fn router() -> Router<AppState> {
.route("/contact/{contact_id}/edit", get(self::get::contact_edit))
}
fn human_delta(delta: &chrono::TimeDelta) -> String {
if delta.num_days() == 0 {
return "today".to_string();
}
fn human_delta(span: &jiff::Span) -> String {
let todate = Timestamp::now().to_zoned(TimeZone::UTC).date();
let span = span
.round(
jiff::SpanRound::new()
.largest(Unit::Year)
.smallest(Unit::Day)
.relative(todate),
)
.unwrap();
let mut result = "in ".to_string();
let mut rem = delta.clone();
if rem.num_days().abs() >= 7 {
let weeks = rem.num_days() / 7;
rem -= chrono::TimeDelta::days(weeks * 7);
result.push_str(&format!("{}w ", weeks));
if span.is_zero() {
"today".to_string()
} else {
format!("in {:#}", span)
}
if rem.num_days().abs() > 0 {
result.push_str(&format!("{}d ", rem.num_days()));
}
result.trim().to_string()
}
mod get {
@ -88,7 +88,9 @@ mod get {
.await?;
let freshened = std::cmp::max(
contact.manually_freshened_at.map(|when| when.date_naive()),
contact
.manually_freshened_at
.map(|when| when.to_zoned(jiff::tz::TimeZone::UTC).date()),
entries.get(0).map(|entry| entry.date),
);
@ -213,7 +215,7 @@ mod get {
let mfresh_str = contact
.manually_freshened_at
.clone()
.map_or("".to_string(), |m| m.to_rfc3339());
.map_or("".to_string(), |m| m.to_string());
let text_body: String =
sqlx::query!("select text_body from contacts where id = $1", contact_id)
@ -224,7 +226,7 @@ mod get {
Ok(layout.render(
format!("Edit: {}", contact.names.get(0).unwrap_or(&String::from("(unknown)"))),
Some(vec![asset!("contact.css")]),
Some(vec![asset!("contact.css")]),
html! {
form hx-ext="response-targets" {
div {
@ -351,14 +353,15 @@ mod put {
Some(payload.birthday)
};
let manually_freshened_at = if payload.manually_freshened_at.is_empty() {
let manually_freshened_at: Option<String> = if payload.manually_freshened_at.is_empty() {
None
} else {
Some(
DateTime::parse_from_str(&payload.manually_freshened_at, "%+")
payload
.manually_freshened_at
.parse::<Timestamp>()
.map_err(|_| anyhow::Error::msg("Could not parse freshened-at string"))?
.to_utc()
.to_rfc3339(),
.to_string(),
)
};
@ -386,9 +389,6 @@ mod put {
.execute(pool)
.await?;
if old_contact.text_body != text_body {
}
// these blocks are not in functions because payload gets progressively
// partially moved as we handle each field and i don't want to deal with it
@ -488,25 +488,21 @@ mod put {
let old_names: Vec<String> = old_names.into_iter().map(|(s,)| s).collect();
if old_names != new_names {
sqlx::query!(
"delete from names where contact_id = $1",
contact_id
)
.execute(pool)
.await?;
if !new_names.is_empty() {
QueryBuilder::new(
"insert into names (contact_id, sort, name) "
).push_values(new_names.iter().enumerate(), |mut b, (sort, name)| {
b
.push_bind(contact_id)
.push_bind(DbId::try_from(sort).unwrap())
.push_bind(name);
}).build()
.persistent(false)
sqlx::query!("delete from names where contact_id = $1", contact_id)
.execute(pool)
.await?;
if !new_names.is_empty() {
QueryBuilder::new("insert into names (contact_id, sort, name) ")
.push_values(new_names.iter().enumerate(), |mut b, (sort, name)| {
b.push_bind(contact_id)
.push_bind(DbId::try_from(sort).unwrap())
.push_bind(name);
})
.build()
.persistent(false)
.execute(pool)
.await?;
}
}
@ -524,12 +520,9 @@ mod put {
let old_groups: Vec<String> = old_groups.into_iter().map(|(s,)| s).collect();
if new_groups != old_groups {
sqlx::query!(
"delete from groups where contact_id = $1",
contact_id
)
.execute(pool)
.await?;
sqlx::query!("delete from groups where contact_id = $1", contact_id)
.execute(pool)
.await?;
if new_groups.len() > 0 {
QueryBuilder::new("insert into groups (contact_id, name, slug) ")
@ -566,7 +559,6 @@ mod put {
.await?;
}
if regen_text_body {
sqlx::query!(
"delete from mentions where entity_id = $1 and entity_type = $2",