Fix datetime parsing bug in event submission

- Fix timezone detection logic to only consider dashes after 'T' as timezone indicators
- Reorder multipart datetime parsing to try flexible formats before strict RFC3339
- Resolves 400 "Invalid RFC3339 datetime" error for format like "2025-10-07T00:13"
- Event submissions now work correctly with local church time format
This commit is contained in:
Benjamin Slingo 2025-09-08 00:18:47 -04:00
parent 4899c3829c
commit c607aa135c
2 changed files with 21 additions and 15 deletions

View file

@ -67,7 +67,13 @@ pub fn parse_datetime_with_timezone(
) -> Result<DateTimeWithTimezone> {
let timezone = timezone.unwrap_or(DEFAULT_CHURCH_TIMEZONE);
if datetime_str.ends_with('Z') || datetime_str.contains('+') || datetime_str.contains('-') {
// Check if this looks like RFC3339 with timezone info (ends with Z, contains +, or has timezone offset after T)
let has_timezone = datetime_str.ends_with('Z') ||
datetime_str.contains('+') ||
(datetime_str.contains('T') &&
datetime_str.split('T').nth(1).map_or(false, |time_part| time_part.contains('-')));
if has_timezone {
let dt = DateTime::parse_from_rfc3339(datetime_str)
.map_err(|_| ApiError::BadRequest("Invalid RFC3339 datetime".to_string()))?;
DateTimeWithTimezone::new(dt.with_timezone(&Utc), timezone)

View file

@ -71,20 +71,20 @@ impl MultipartProcessor {
pub fn get_datetime(&self, field_name: &str) -> Result<DateTime<Utc>> {
let datetime_str = self.get_required_string(field_name)?;
// First try the shared timezone-aware parsing function
if let Ok(utc_time) = crate::utils::datetime::parse_event_datetime_to_utc(&datetime_str) {
return Ok(utc_time);
// Try parsing as RFC3339 first (already has timezone info)
if let Ok(dt) = DateTime::parse_from_rfc3339(&datetime_str) {
return Ok(dt.to_utc());
}
// Fallback to legacy formats for backward compatibility
// These will now be treated as EST/EDT times and converted to UTC
// Try flexible local formats for backward compatibility
// These will be treated as EST/EDT times and converted to UTC
let formats = [
"%Y-%m-%dT%H:%M",
"%Y-%m-%dT%H:%M:%S",
"%Y-%m-%d %H:%M",
"%Y-%m-%d %H:%M:%S",
"%m/%d/%Y %H:%M",
"%m/%d/%Y %I:%M %p",
"%Y-%m-%dT%H:%M", // 2025-10-08T00:09
"%Y-%m-%dT%H:%M:%S", // 2025-10-08T00:09:00
"%Y-%m-%d %H:%M", // 2025-10-08 00:09
"%Y-%m-%d %H:%M:%S", // 2025-10-08 00:09:00
"%m/%d/%Y %H:%M", // 10/08/2025 00:09
"%m/%d/%Y %I:%M %p", // 10/08/2025 12:09 AM
];
for format in &formats {
@ -95,9 +95,9 @@ impl MultipartProcessor {
}
}
// Try parsing as RFC3339 (already has timezone info)
if let Ok(dt) = DateTime::parse_from_rfc3339(&datetime_str) {
return Ok(dt.to_utc());
// Last resort: try the shared timezone-aware parsing function
if let Ok(utc_time) = crate::utils::datetime::parse_event_datetime_to_utc(&datetime_str) {
return Ok(utc_time);
}
Err(ApiError::ValidationError(format!(