Fix timezone bug in event creation

Events were appearing 4 hours earlier than selected time due to incorrect
timezone handling in backend. The issue was treating frontend local time
as if it was already in UTC.

- Fix parse_event_datetime() in events.rs to properly convert local time to UTC
- Fix all datetime conversions in series.rs to use Local timezone conversion
- Replace Utc.from_utc_datetime() with proper Local.from_local_datetime()
- Add timezone conversion using with_timezone(&Utc) for accurate UTC storage

Now when user selects 5:00 AM, it correctly stores as UTC equivalent
and displays back at 5:00 AM local time.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Connor Johnstone
2025-09-03 16:17:32 -04:00
parent dce82d5f7d
commit 0609a99839
2 changed files with 47 additions and 11 deletions

View File

@@ -845,7 +845,7 @@ fn parse_event_datetime(
time_str: &str,
all_day: bool,
) -> Result<chrono::DateTime<chrono::Utc>, String> {
use chrono::{NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
use chrono::{Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
// Parse the date
let date = NaiveDate::parse_from_str(date_str, "%Y-%m-%d")
@@ -865,7 +865,11 @@ fn parse_event_datetime(
// Combine date and time
let datetime = NaiveDateTime::new(date, time);
// Assume local time and convert to UTC (in a real app, you'd want timezone support)
Ok(Utc.from_utc_datetime(&datetime))
// Treat the datetime as local time and convert to UTC
let local_datetime = Local.from_local_datetime(&datetime)
.single()
.ok_or_else(|| "Ambiguous local datetime".to_string())?;
Ok(local_datetime.with_timezone(&Utc))
}
}

View File

@@ -130,9 +130,17 @@ pub async fn create_event_series(
.and_hms_opt(23, 59, 59)
.ok_or_else(|| ApiError::BadRequest("Invalid end date".to_string()))?;
// Convert from local time to UTC
let start_local = chrono::Local.from_local_datetime(&start_dt)
.single()
.ok_or_else(|| ApiError::BadRequest("Ambiguous start datetime".to_string()))?;
let end_local = chrono::Local.from_local_datetime(&end_dt)
.single()
.ok_or_else(|| ApiError::BadRequest("Ambiguous end datetime".to_string()))?;
(
chrono::Utc.from_utc_datetime(&start_dt),
chrono::Utc.from_utc_datetime(&end_dt),
start_local.with_timezone(&chrono::Utc),
end_local.with_timezone(&chrono::Utc),
)
} else {
// Parse times for timed events
@@ -163,9 +171,17 @@ pub async fn create_event_series(
start_date.and_time(end_time)
};
// Convert from local time to UTC
let start_local = chrono::Local.from_local_datetime(&start_dt)
.single()
.ok_or_else(|| ApiError::BadRequest("Ambiguous start datetime".to_string()))?;
let end_local = chrono::Local.from_local_datetime(&end_dt)
.single()
.ok_or_else(|| ApiError::BadRequest("Ambiguous end datetime".to_string()))?;
(
chrono::Utc.from_utc_datetime(&start_dt),
chrono::Utc.from_utc_datetime(&end_dt),
start_local.with_timezone(&chrono::Utc),
end_local.with_timezone(&chrono::Utc),
)
};
@@ -401,9 +417,17 @@ pub async fn update_event_series(
.and_hms_opt(23, 59, 59)
.ok_or_else(|| ApiError::BadRequest("Invalid end date".to_string()))?;
// Convert from local time to UTC
let start_local = chrono::Local.from_local_datetime(&start_dt)
.single()
.ok_or_else(|| ApiError::BadRequest("Ambiguous start datetime".to_string()))?;
let end_local = chrono::Local.from_local_datetime(&end_dt)
.single()
.ok_or_else(|| ApiError::BadRequest("Ambiguous end datetime".to_string()))?;
(
chrono::Utc.from_utc_datetime(&start_dt),
chrono::Utc.from_utc_datetime(&end_dt),
start_local.with_timezone(&chrono::Utc),
end_local.with_timezone(&chrono::Utc),
)
} else {
let start_time = if !request.start_time.is_empty() {
@@ -438,9 +462,17 @@ pub async fn update_event_series(
(chrono::Utc.from_utc_datetime(&start_dt) + original_duration).naive_utc()
};
// Convert from local time to UTC
let start_local = chrono::Local.from_local_datetime(&start_dt)
.single()
.ok_or_else(|| ApiError::BadRequest("Ambiguous start datetime".to_string()))?;
let end_local = chrono::Local.from_local_datetime(&end_dt)
.single()
.ok_or_else(|| ApiError::BadRequest("Ambiguous end datetime".to_string()))?;
(
chrono::Utc.from_utc_datetime(&start_dt),
chrono::Utc.from_utc_datetime(&end_dt),
start_local.with_timezone(&chrono::Utc),
end_local.with_timezone(&chrono::Utc),
)
};