@@ -5,7 +5,7 @@ use std::fmt::{Debug, Formatter};
5
5
use std:: hash:: Hash ;
6
6
use std:: num:: NonZeroU8 ;
7
7
use time:: macros:: format_description;
8
- use time:: { Duration , UtcOffset } ;
8
+ use time:: UtcOffset ;
9
9
10
10
#[ derive( Hash , PartialEq , Eq , Clone ) ]
11
11
#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
@@ -91,39 +91,42 @@ impl DateTime {
91
91
}
92
92
93
93
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
94
96
let format = format_description ! ( "[year]-[month]-[day]" ) ;
95
97
let date = time:: Date :: parse ( date, & format) . expect ( "valid date string" ) ;
96
98
DateTime :: Date ( date)
97
99
}
98
100
99
101
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]] ]" ) ;
101
103
let time = time:: Time :: parse ( time, & format) . expect ( "valid time string" ) ;
102
104
DateTime :: Time ( time, * precision)
103
105
}
104
106
105
107
pub fn from_hh_mm_ss_time_zone ( time : & str , precision : & Option < u32 > ) -> Self {
106
108
let time_format = format_description ! (
107
- "[hour]:[minute]:[second].[subsecond][offset_hour]:[offset_minute]"
109
+ "[hour]:[minute]:[second][optional [ .[subsecond]] ][offset_hour]:[offset_minute]"
108
110
) ;
109
111
let time_part = time:: Time :: parse ( time, & time_format) . expect ( "valid time with time zone" ) ;
110
112
let time_format = format_description ! (
111
- "[hour]:[minute]:[second].[subsecond][offset_hour]:[offset_minute]"
113
+ "[hour]:[minute]:[second][optional [ .[subsecond]] ][offset_hour]:[offset_minute]"
112
114
) ;
113
115
let offset_part = time:: UtcOffset :: parse ( time, & time_format) . expect ( "valid time zone" ) ;
114
116
DateTime :: TimeWithTz ( time_part, * precision, offset_part)
115
117
}
116
118
117
119
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
+ ) ;
120
123
let time =
121
124
time:: PrimitiveDateTime :: parse ( timestamp, & format) . expect ( "valid timestamp string" ) ;
122
125
DateTime :: Timestamp ( time, * precision)
123
126
}
124
127
125
128
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]" ) ;
127
130
let time = time:: OffsetDateTime :: parse ( timestamp, & format)
128
131
. expect ( "valid timestamp string with time zone" ) ;
129
132
DateTime :: TimestampWithTz ( time, * precision)
@@ -174,29 +177,30 @@ impl Ord for DateTime {
174
177
( DateTime :: Date ( _) , _) => Ordering :: Less ,
175
178
( _, DateTime :: Date ( _) ) => Ordering :: Greater ,
176
179
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 ) ,
179
182
( DateTime :: Time ( _, _) , _) => Ordering :: Less ,
180
183
( _, DateTime :: Time ( _, _) ) => Ordering :: Greater ,
181
184
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) ,
190
187
( DateTime :: TimeWithTz ( _, _, _) , _) => Ordering :: Less ,
191
188
( _, DateTime :: TimeWithTz ( _, _, _) ) => Ordering :: Greater ,
192
189
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) ,
195
192
( DateTime :: Timestamp ( _, _) , _) => Ordering :: Less ,
196
193
( _, DateTime :: Timestamp ( _, _) ) => Ordering :: Greater ,
197
194
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
+ }
200
204
}
201
205
}
202
206
}
0 commit comments