@@ -102,13 +102,40 @@ def md5_as_hex(self, s: str) -> str:
102102 return f"md5({ s } )"
103103
104104 def normalize_timestamp (self , value : str , coltype : TemporalType ) -> str :
105+ def _add_padding (coltype : TemporalType , timestamp6 : str ):
106+ return f"RPAD(LEFT({ timestamp6 } , { TIMESTAMP_PRECISION_POS + coltype .precision } ), { TIMESTAMP_PRECISION_POS + 6 } , '0')"
107+
105108 if coltype .rounds :
106- return f"to_char({ value } ::timestamp({ coltype .precision } ), 'YYYY-mm-dd HH24:MI:SS.US')"
109+ # NULL value expected to return NULL after normalization
110+ null_case_begin = f"CASE WHEN { value } IS NULL THEN NULL ELSE "
111+ null_case_end = "END"
112+
113+ # 294277 or 4714 BC would be out of range, make sure we can't round to that
114+ # TODO test timezones for overflow?
115+ max_timestamp = "294276-12-31 23:59:59.0000"
116+ min_timestamp = "4713-01-01 00:00:00.00 BC"
117+ timestamp = f"least('{ max_timestamp } '::timestamp(6), { value } ::timestamp(6))"
118+ timestamp = f"greatest('{ min_timestamp } '::timestamp(6), { timestamp } )"
119+
120+ interval = format ((0.5 * (10 ** (- coltype .precision ))), f".{ coltype .precision + 1 } f" )
121+
122+ rounded_timestamp = (
123+ f"left(to_char(least('{ max_timestamp } '::timestamp, { timestamp } )"
124+ f"+ interval '{ interval } ', 'YYYY-mm-dd HH24:MI:SS.US'),"
125+ f"length(to_char(least('{ max_timestamp } '::timestamp, { timestamp } )"
126+ f"+ interval '{ interval } ', 'YYYY-mm-dd HH24:MI:SS.US')) - (6-{ coltype .precision } ))"
127+ )
107128
108- timestamp6 = f"to_char({ value } ::timestamp(6), 'YYYY-mm-dd HH24:MI:SS.US')"
109- return (
110- f"RPAD(LEFT({ timestamp6 } , { TIMESTAMP_PRECISION_POS + coltype .precision } ), { TIMESTAMP_PRECISION_POS + 6 } , '0')"
111- )
129+ padded = _add_padding (coltype , rounded_timestamp )
130+ return f"{ null_case_begin } { padded } { null_case_end } "
131+
132+ # TODO years with > 4 digits not padded correctly
133+ # current w/ precision 6: 294276-12-31 23:59:59.0000
134+ # should be 294276-12-31 23:59:59.000000
135+ else :
136+ rounded_timestamp = f"to_char({ value } ::timestamp(6), 'YYYY-mm-dd HH24:MI:SS.US')"
137+ padded = _add_padding (coltype , rounded_timestamp )
138+ return padded
112139
113140 def normalize_number (self , value : str , coltype : FractionalType ) -> str :
114141 return self .to_string (f"{ value } ::decimal(38, { coltype .precision } )" )
0 commit comments