@@ -5,7 +5,7 @@ use std::fmt::{Debug, Formatter};
55use std:: hash:: Hash ;
66use std:: num:: NonZeroU8 ;
77use time:: macros:: format_description;
8- use time:: { Duration , UtcOffset } ;
8+ use time:: UtcOffset ;
99
1010#[ derive( Hash , PartialEq , Eq , Clone ) ]
1111#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
@@ -91,39 +91,42 @@ impl DateTime {
9191 }
9292
9393 pub fn from_yyyy_mm_dd ( date : & str ) -> Self {
94+ // TODO: for better error mesaging, perhaps could include in our parser or create separate
95+ // parser for these date, time, and timestamp strings
9496 let format = format_description ! ( "[year]-[month]-[day]" ) ;
9597 let date = time:: Date :: parse ( date, & format) . expect ( "valid date string" ) ;
9698 DateTime :: Date ( date)
9799 }
98100
99101 pub fn from_hh_mm_ss ( time : & str , precision : & Option < u32 > ) -> Self {
100- let format = format_description ! ( "[hour]:[minute]:[second].[subsecond]" ) ;
102+ let format = format_description ! ( "[hour]:[minute]:[second][optional [ .[subsecond]] ]" ) ;
101103 let time = time:: Time :: parse ( time, & format) . expect ( "valid time string" ) ;
102104 DateTime :: Time ( time, * precision)
103105 }
104106
105107 pub fn from_hh_mm_ss_time_zone ( time : & str , precision : & Option < u32 > ) -> Self {
106108 let time_format = format_description ! (
107- "[hour]:[minute]:[second].[subsecond][offset_hour]:[offset_minute]"
109+ "[hour]:[minute]:[second][optional [ .[subsecond]] ][offset_hour]:[offset_minute]"
108110 ) ;
109111 let time_part = time:: Time :: parse ( time, & time_format) . expect ( "valid time with time zone" ) ;
110112 let time_format = format_description ! (
111- "[hour]:[minute]:[second].[subsecond][offset_hour]:[offset_minute]"
113+ "[hour]:[minute]:[second][optional [ .[subsecond]] ][offset_hour]:[offset_minute]"
112114 ) ;
113115 let offset_part = time:: UtcOffset :: parse ( time, & time_format) . expect ( "valid time zone" ) ;
114116 DateTime :: TimeWithTz ( time_part, * precision, offset_part)
115117 }
116118
117119 pub fn from_yyyy_mm_dd_hh_mm_ss ( timestamp : & str , precision : & Option < u32 > ) -> Self {
118- let format =
119- format_description ! ( "[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]" ) ;
120+ let format = format_description ! (
121+ "[year]-[month]-[day] [hour]:[minute]:[second][optional [.[subsecond]]]"
122+ ) ;
120123 let time =
121124 time:: PrimitiveDateTime :: parse ( timestamp, & format) . expect ( "valid timestamp string" ) ;
122125 DateTime :: Timestamp ( time, * precision)
123126 }
124127
125128 pub fn from_yyyy_mm_dd_hh_mm_ss_time_zone ( timestamp : & str , precision : & Option < u32 > ) -> Self {
126- let format = format_description ! ( "[year]-[month]-[day] [hour]:[minute]:[second].[subsecond][offset_hour]:[offset_minute]" ) ;
129+ let format = format_description ! ( "[year]-[month]-[day] [hour]:[minute]:[second][optional [ .[subsecond]] ][offset_hour]:[offset_minute]" ) ;
127130 let time = time:: OffsetDateTime :: parse ( timestamp, & format)
128131 . expect ( "valid timestamp string with time zone" ) ;
129132 DateTime :: TimestampWithTz ( time, * precision)
@@ -174,29 +177,30 @@ impl Ord for DateTime {
174177 ( DateTime :: Date ( _) , _) => Ordering :: Less ,
175178 ( _, DateTime :: Date ( _) ) => Ordering :: Greater ,
176179
177- ( DateTime :: Time ( l , _lp ) , DateTime :: Time ( r , _rp ) ) => l . cmp ( r ) ,
178- // TODO: sorting using the time precisions
180+ // follow convention of timestamp mentioned in section 12.2 to ignore precision and local utc offset
181+ ( DateTime :: Time ( l , _ ) , DateTime :: Time ( r , _ ) ) => l . cmp ( r ) ,
179182 ( DateTime :: Time ( _, _) , _) => Ordering :: Less ,
180183 ( _, DateTime :: Time ( _, _) ) => Ordering :: Greater ,
181184
182- ( DateTime :: TimeWithTz ( l, _lp, lo) , DateTime :: TimeWithTz ( r, _rp, ro) ) => {
183- // TODO: sorting using the time precisions
184- let lod = Duration :: new ( lo. whole_seconds ( ) as i64 , 0 ) ;
185- let rod = Duration :: new ( ro. whole_seconds ( ) as i64 , 0 ) ;
186- let l_adjusted = * l + lod;
187- let r_adjusted = * r + rod;
188- l_adjusted. cmp ( & r_adjusted)
189- }
185+ // follow convention of timestamp mentioned in section 12.2 to ignore precision and local utc offset
186+ ( DateTime :: TimeWithTz ( l, _, _) , DateTime :: TimeWithTz ( r, _, _) ) => l. cmp ( r) ,
190187 ( DateTime :: TimeWithTz ( _, _, _) , _) => Ordering :: Less ,
191188 ( _, DateTime :: TimeWithTz ( _, _, _) ) => Ordering :: Greater ,
192189
193- // TODO: sorting using the timestamp precisions
194- ( DateTime :: Timestamp ( l, _lp ) , DateTime :: Timestamp ( r, _rp ) ) => l. cmp ( r) ,
190+ // per section 12.2 of spec, timestamp values are compared irrespective of precision or local UTC offset
191+ ( DateTime :: Timestamp ( l, _ ) , DateTime :: Timestamp ( r, _ ) ) => l. cmp ( r) ,
195192 ( DateTime :: Timestamp ( _, _) , _) => Ordering :: Less ,
196193 ( _, DateTime :: Timestamp ( _, _) ) => Ordering :: Greater ,
197194
198- // TODO: sorting using the timestamp precisions
199- ( DateTime :: TimestampWithTz ( l, _lp) , DateTime :: TimestampWithTz ( r, _rp) ) => l. cmp ( r) ,
195+ // per section 12.2 of spec, timestamp values are compared irrespective of precision or local UTC offset
196+ ( DateTime :: TimestampWithTz ( l, _) , DateTime :: TimestampWithTz ( r, _) ) => {
197+ let date_ord = l. date ( ) . cmp ( & r. date ( ) ) ;
198+ if date_ord != Ordering :: Equal {
199+ date_ord
200+ } else {
201+ l. time ( ) . cmp ( & r. time ( ) )
202+ }
203+ }
200204 }
201205 }
202206}
0 commit comments