Fix all-day event end date handling by removing double conversion
Root cause: Both frontend and backend were adding a day for all-day events: - Frontend: Converts inclusive UI dates (9/22-9/25) to exclusive (9/22-9/26) - Backend: Was incorrectly adding another day (9/22-9/27) causing display issues Fixed by: - Remove duplicate day addition in backend handlers (events.rs, series.rs) - Keep frontend conversion for proper RFC 5545 compliance - Add reverse conversion when loading events for editing - Maintain user-friendly inclusive dates in UI while storing exclusive dates Now properly handles: UI 9/22-9/25 ↔ Storage 9/22-9/26 (exclusive per spec) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -456,14 +456,11 @@ pub async fn create_event(
|
||||
parse_event_datetime_local(&request.start_date, &request.start_time, request.all_day)
|
||||
.map_err(|e| ApiError::BadRequest(format!("Invalid start date/time: {}", e)))?;
|
||||
|
||||
let mut end_datetime = parse_event_datetime_local(&request.end_date, &request.end_time, request.all_day)
|
||||
let end_datetime = parse_event_datetime_local(&request.end_date, &request.end_time, request.all_day)
|
||||
.map_err(|e| ApiError::BadRequest(format!("Invalid end date/time: {}", e)))?;
|
||||
|
||||
// For all-day events, add one day to end date for RFC-5545 compliance
|
||||
// RFC-5545 uses exclusive end dates for all-day events
|
||||
if request.all_day {
|
||||
end_datetime = end_datetime + chrono::Duration::days(1);
|
||||
}
|
||||
// Note: Frontend already converts inclusive UI dates to exclusive dates for all-day events
|
||||
// No additional conversion needed here
|
||||
|
||||
// Validate that end is after start (allow equal times for all-day events)
|
||||
if request.all_day {
|
||||
@@ -766,14 +763,11 @@ pub async fn update_event(
|
||||
parse_event_datetime_local(&request.start_date, &request.start_time, request.all_day)
|
||||
.map_err(|e| ApiError::BadRequest(format!("Invalid start date/time: {}", e)))?;
|
||||
|
||||
let mut end_datetime = parse_event_datetime_local(&request.end_date, &request.end_time, request.all_day)
|
||||
let end_datetime = parse_event_datetime_local(&request.end_date, &request.end_time, request.all_day)
|
||||
.map_err(|e| ApiError::BadRequest(format!("Invalid end date/time: {}", e)))?;
|
||||
|
||||
// For all-day events, add one day to end date for RFC-5545 compliance
|
||||
// RFC-5545 uses exclusive end dates for all-day events
|
||||
if request.all_day {
|
||||
end_datetime = end_datetime + chrono::Duration::days(1);
|
||||
}
|
||||
// Note: Frontend already converts inclusive UI dates to exclusive dates for all-day events
|
||||
// No additional conversion needed here
|
||||
|
||||
// Validate that end is after start (allow equal times for all-day events)
|
||||
if request.all_day {
|
||||
|
||||
@@ -137,13 +137,11 @@ pub async fn create_event_series(
|
||||
let start_datetime = parse_event_datetime_local(&request.start_date, &request.start_time, request.all_day)
|
||||
.map_err(|e| ApiError::BadRequest(format!("Invalid start date/time: {}", e)))?;
|
||||
|
||||
let mut end_datetime = parse_event_datetime_local(&request.end_date, &request.end_time, request.all_day)
|
||||
let end_datetime = parse_event_datetime_local(&request.end_date, &request.end_time, request.all_day)
|
||||
.map_err(|e| ApiError::BadRequest(format!("Invalid end date/time: {}", e)))?;
|
||||
|
||||
// For all-day events, add one day to end date for RFC-5545 compliance
|
||||
if request.all_day {
|
||||
end_datetime = end_datetime + chrono::Duration::days(1);
|
||||
}
|
||||
// Note: Frontend already converts inclusive UI dates to exclusive dates for all-day events
|
||||
// No additional conversion needed here
|
||||
|
||||
// Generate a unique UID for the series
|
||||
let uid = format!("series-{}", uuid::Uuid::new_v4().to_string());
|
||||
|
||||
@@ -257,7 +257,13 @@ fn vevent_to_creation_data(event: &crate::models::ical::VEvent, available_calend
|
||||
|
||||
// Timing
|
||||
start_date: start_local.date(),
|
||||
end_date: end_local.date(),
|
||||
end_date: if event.all_day {
|
||||
// For all-day events, subtract one day to convert from exclusive to inclusive end date
|
||||
// (UI expects inclusive dates, but iCalendar stores exclusive end dates)
|
||||
end_local.date() - chrono::Duration::days(1)
|
||||
} else {
|
||||
end_local.date()
|
||||
},
|
||||
start_time: start_local.time(),
|
||||
end_time: end_local.time(),
|
||||
|
||||
|
||||
@@ -156,8 +156,9 @@ impl EventCreationData {
|
||||
) {
|
||||
|
||||
// Use local date/times and timezone - no UTC conversion
|
||||
let effective_end_date = if self.end_time == NaiveTime::from_hms_opt(0, 0, 0).unwrap() {
|
||||
// If end time is midnight (00:00), treat it as beginning of next day
|
||||
let effective_end_date = if self.all_day {
|
||||
// For all-day events, add one day to convert from inclusive to exclusive end date
|
||||
// (iCalendar spec requires exclusive end dates for all-day events)
|
||||
self.end_date + chrono::Duration::days(1)
|
||||
} else {
|
||||
self.end_date
|
||||
|
||||
Reference in New Issue
Block a user