11use chrono:: { DateTime , Duration , LocalResult , NaiveDate , NaiveDateTime , TimeZone } ;
22use chrono_tz:: Tz ;
33use cubenativeutils:: CubeError ;
4+ use lazy_static:: lazy_static;
45use regex:: Regex ;
6+
57pub struct QueryDateTimeHelper { }
68
7- use lazy_static:: lazy_static;
89lazy_static ! {
910 static ref DATE_TIME_LOCAL_MS_RE : Regex =
1011 Regex :: new( r"^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d\.\d\d\d$" ) . unwrap( ) ;
1112 static ref DATE_TIME_LOCAL_U_RE : Regex =
1213 Regex :: new( r"^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d\.\d\d\d\d\d\d$" ) . unwrap( ) ;
1314 static ref DATE_RE : Regex = Regex :: new( r"^\d\d\d\d-\d\d-\d\d$" ) . unwrap( ) ;
1415}
16+
1517impl QueryDateTimeHelper {
1618 pub fn parse_native_date_time ( date : & str ) -> Result < NaiveDateTime , CubeError > {
19+ // Fall back to naive datetime parsing
1720 let formats = & [
1821 "%Y-%m-%d" ,
1922 "%Y-%m-%d %H:%M:%S" ,
@@ -28,8 +31,9 @@ impl QueryDateTimeHelper {
2831 }
2932 }
3033
31- if let Ok ( d) = NaiveDate :: parse_from_str ( date, "%Y-%m-%d" ) {
32- return Ok ( d. and_hms_opt ( 0 , 0 , 0 ) . unwrap ( ) ) ;
34+ // Fallback as RFC3339/ISO8601 with 'Z' timezone
35+ if let Ok ( dt) = DateTime :: parse_from_rfc3339 ( date) {
36+ return Ok ( dt. naive_utc ( ) ) ;
3337 }
3438
3539 Err ( CubeError :: user ( format ! ( "Can't parse date: '{}'" , date) ) )
@@ -190,5 +194,20 @@ mod tests {
190194 . and_hms_milli_opt( 12 , 10 , 15 , 345 )
191195 . unwrap( )
192196 ) ;
197+ // Test parsing with 'Z' timezone (UTC)
198+ assert_eq ! (
199+ QueryDateTimeHelper :: parse_native_date_time( "2024-01-01T10:15:00Z" ) . unwrap( ) ,
200+ NaiveDate :: from_ymd_opt( 2024 , 1 , 1 )
201+ . unwrap( )
202+ . and_hms_opt( 10 , 15 , 0 )
203+ . unwrap( )
204+ ) ;
205+ assert_eq ! (
206+ QueryDateTimeHelper :: parse_native_date_time( "2024-01-01T10:15:00.123Z" ) . unwrap( ) ,
207+ NaiveDate :: from_ymd_opt( 2024 , 1 , 1 )
208+ . unwrap( )
209+ . and_hms_milli_opt( 10 , 15 , 0 , 123 )
210+ . unwrap( )
211+ ) ;
193212 }
194213}
0 commit comments