1515import java .time .format .DateTimeParseException ;
1616import java .time .temporal .ChronoUnit ;
1717import java .util .Locale ;
18+ import java .util .Optional ;
19+ import java .util .Set ;
1820import lombok .experimental .UtilityClass ;
1921import org .opensearch .sql .data .model .ExprTimeValue ;
2022import org .opensearch .sql .data .model .ExprValue ;
@@ -25,6 +27,11 @@ public class DateTimeUtils {
2527
2628 private static final DateTimeFormatter DIRECT_FORMATTER =
2729 DateTimeFormatter .ofPattern ("MM/dd/yyyy:HH:mm:ss" );
30+ public static final Set <DateTimeFormatter > SUPPORTED_FORMATTERS =
31+ Set .of (
32+ DIRECT_FORMATTER ,
33+ DateTimeFormatters .DATE_TIMESTAMP_FORMATTER ,
34+ DateTimeFormatter .ISO_DATE_TIME );
2835
2936 /**
3037 * Util method to round the date/time with given unit.
@@ -167,22 +174,9 @@ public static LocalDate extractDate(ExprValue value, FunctionProperties function
167174 }
168175
169176 public static ZonedDateTime getRelativeZonedDateTime (String input , ZonedDateTime baseTime ) {
170- try {
171- Instant parsed ;
172- try {
173- parsed = LocalDateTime .parse (input , DIRECT_FORMATTER ).toInstant (ZoneOffset .UTC );
174- } catch (DateTimeParseException ignored ) {
175- try {
176- parsed =
177- LocalDateTime .parse (input , DateTimeFormatters .DATE_TIMESTAMP_FORMATTER )
178- .toInstant (ZoneOffset .UTC );
179- } catch (DateTimeParseException ignored2 ) {
180- ZonedDateTime zdt = ZonedDateTime .parse (input , DateTimeFormatter .ISO_DATE_TIME );
181- parsed = zdt .withZoneSameInstant (ZoneOffset .UTC ).toInstant ();
182- }
183- }
184- return parsed .atZone (baseTime .getZone ());
185- } catch (DateTimeParseException ignored ) {
177+ Optional <ZonedDateTime > parsed = tryParseAbsoluteTime (input );
178+ if (parsed .isPresent ()) {
179+ return parsed .get ().withZoneSameInstant (baseTime .getZone ());
186180 }
187181
188182 if ("now" .equalsIgnoreCase (input ) || "now()" .equalsIgnoreCase (input )) {
@@ -340,7 +334,7 @@ static String resolveTimeModifier(String input, ZonedDateTime nowReference) {
340334 return "now" ;
341335 }
342336
343- String absoluteTime = tryParseAbsoluteTime (input );
337+ String absoluteTime = tryParseAbsoluteTimeAndFormat (input );
344338 if (absoluteTime != null ) {
345339 return absoluteTime ;
346340 }
@@ -354,29 +348,31 @@ static String resolveTimeModifier(String input, ZonedDateTime nowReference) {
354348 * @param input The time string
355349 * @return ISO formatted datetime string or null if parsing fails
356350 */
357- private static String tryParseAbsoluteTime (String input ) {
358- try {
359- try {
360- LocalDate parsedDate = LocalDate .parse (input );
361- return parsedDate .toString ();
362- } catch (DateTimeParseException ignored ) {
363- }
351+ private static String tryParseAbsoluteTimeAndFormat (String input ) {
352+ Optional <ZonedDateTime > parsed = tryParseAbsoluteTime (input );
353+ return parsed
354+ .map (zonedDateTime -> zonedDateTime .format (DateTimeFormatter .ISO_INSTANT ))
355+ .orElse (null );
356+ }
364357
365- LocalDateTime parsed ;
358+ private static Optional <ZonedDateTime > tryParseAbsoluteTime (String input ) {
359+ for (DateTimeFormatter formatter : SUPPORTED_FORMATTERS ) {
366360 try {
367- parsed = LocalDateTime .parse (input , DIRECT_FORMATTER );
368- } catch (DateTimeParseException ignored ) {
369- try {
370- parsed = LocalDateTime .parse (input , DateTimeFormatters .DATE_TIMESTAMP_FORMATTER );
371- } catch (DateTimeParseException ignored2 ) {
372- ZonedDateTime zdt = ZonedDateTime .parse (input , DateTimeFormatter .ISO_DATE_TIME );
373- parsed = zdt .withZoneSameInstant (ZoneOffset .UTC ).toLocalDateTime ();
361+ ZonedDateTime parsed ;
362+ if (formatter == DateTimeFormatter .ISO_DATE_TIME ) {
363+ // ISO_DATE_TIME can handle zone information
364+ parsed = ZonedDateTime .parse (input , formatter );
365+ } else {
366+ // Treat LocalDateTime formatters as UTC
367+ LocalDateTime localDateTime = LocalDateTime .parse (input , formatter );
368+ parsed = localDateTime .atZone (ZoneOffset .UTC );
374369 }
370+ return Optional .of (parsed );
371+ } catch (DateTimeParseException ignored ) {
372+ // Try next formatter
375373 }
376- return parsed .atZone (ZoneOffset .UTC ).format (DateTimeFormatter .ISO_INSTANT );
377- } catch (DateTimeParseException ignored ) {
378- return null ;
379374 }
375+ return Optional .empty ();
380376 }
381377
382378 /**
0 commit comments