-
Notifications
You must be signed in to change notification settings - Fork 729
[GH-2337] Fix the DateTimeParseException in GeoPackage reader #2339
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -18,22 +18,50 @@ | |||||
*/ | ||||||
package org.apache.sedona.sql.datasources.geopackage.transform | ||||||
|
||||||
import java.time.{Instant, LocalDate} | ||||||
import java.time.{Instant, LocalDate, LocalDateTime, ZoneOffset} | ||||||
import java.time.format.DateTimeFormatter | ||||||
import java.time.format.DateTimeParseException | ||||||
import java.time.temporal.ChronoUnit | ||||||
|
||||||
object DataTypesTransformations { | ||||||
def getDays(dateString: String): Int = { | ||||||
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") | ||||||
|
||||||
val date = LocalDate.parse(dateString, formatter) | ||||||
// Pre-created formatters to avoid repeated object creation | ||||||
private val dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") | ||||||
private val datetimeFormatters = Array( | ||||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS"), // 3 digits | ||||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SS"), // 2 digits | ||||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.S"), // 1 digit | ||||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss") // no milliseconds | ||||||
) | ||||||
|
||||||
def getDays(dateString: String): Int = { | ||||||
val date = LocalDate.parse(dateString, dateFormatter) | ||||||
val epochDate = LocalDate.of(1970, 1, 1) | ||||||
|
||||||
ChronoUnit.DAYS.between(epochDate, date).toInt | ||||||
} | ||||||
|
||||||
def epoch(timestampStr: String): Long = { | ||||||
Instant.parse(timestampStr).toEpochMilli | ||||||
try { | ||||||
// Try parsing as-is first (works for timestamps with timezone info) | ||||||
Instant.parse(timestampStr).toEpochMilli | ||||||
} catch { | ||||||
case _: DateTimeParseException => | ||||||
// If parsing fails, try treating it as UTC (common case for GeoPackage) | ||||||
// Handle various datetime formats without timezone info | ||||||
// Try different patterns to handle various millisecond formats | ||||||
for (formatter <- datetimeFormatters) { | ||||||
try { | ||||||
val localDateTime = LocalDateTime.parse(timestampStr, formatter) | ||||||
return localDateTime.toInstant(ZoneOffset.UTC).toEpochMilli | ||||||
} catch { | ||||||
case _: DateTimeParseException => | ||||||
// Continue to next formatter | ||||||
} | ||||||
} | ||||||
|
||||||
// If all formatters failed, throw a descriptive exception | ||||||
throw new IllegalArgumentException( | ||||||
s"Unable to parse datetime: $timestampStr. " + | ||||||
s"Expected formats: 'yyyy-MM-ddTHH:mm:ss[.S]' or 'yyyy-MM-ddTHH:mm:ss[.S]Z'") | ||||||
|
s"Expected formats: 'yyyy-MM-ddTHH:mm:ss[.S]' or 'yyyy-MM-ddTHH:mm:ss[.S]Z'") | |
s"Expected formats: 'yyyy-MM-ddTHH:mm:ss[.SSS|.SS|.S]' or 'yyyy-MM-ddTHH:mm:ss[.SSS|.SS|.S]Z'") |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Using early return in a for loop is not optimal for functional programming. Consider using
datetimeFormatters.view.map(...)
withfind
orcollectFirst
to make the code more functional and potentially more efficient.Copilot uses AI. Check for mistakes.