1
- from typing import ClassVar , List , Dict , Type
1
+ from typing import ClassVar , List , Dict , Optional , Type
2
2
3
3
import attrs
4
4
10
10
FractionalType ,
11
11
DbPath ,
12
12
TimestampTZ ,
13
+ UnknownColType ,
13
14
)
14
15
from data_diff .databases .postgresql import (
15
16
BaseDialect ,
@@ -54,6 +55,15 @@ def md5_as_hex(self, s: str) -> str:
54
55
def normalize_timestamp (self , value : str , coltype : TemporalType ) -> str :
55
56
if coltype .rounds :
56
57
timestamp = f"{ value } ::timestamp(6)"
58
+
59
+ # redshift allows some problematic timestamp values, don't normalize those (epoch calcs fail)
60
+ case_start = (
61
+ f"case when "
62
+ + f"({ timestamp } < '1901-01-01 00:00'::timestamp(6) or { timestamp } >= '2038-01-01'::timestamp(6))"
63
+ + f"then { timestamp } ::varchar else"
64
+ )
65
+ case_end = f"end"
66
+
57
67
# Get seconds since epoch. Redshift doesn't support milli- or micro-seconds.
58
68
secs = f"timestamp 'epoch' + round(extract(epoch from { timestamp } )::decimal(38)"
59
69
# Get the milliseconds from timestamp.
@@ -65,8 +75,14 @@ def normalize_timestamp(self, value: str, coltype: TemporalType) -> str:
65
75
timestamp6 = (
66
76
f"to_char({ epoch } , -6+{ coltype .precision } ) * interval '0.000001 seconds', 'YYYY-mm-dd HH24:MI:SS.US')"
67
77
)
78
+ padded = self ._add_padding (coltype , timestamp6 )
79
+ return f"{ case_start } { padded } { case_end } "
68
80
else :
69
81
timestamp6 = f"to_char({ value } ::timestamp(6), 'YYYY-mm-dd HH24:MI:SS.US')"
82
+ padded = self ._add_padding (coltype , timestamp6 )
83
+ return padded
84
+
85
+ def _add_padding (self , coltype : TemporalType , timestamp6 : str ):
70
86
return (
71
87
f"RPAD(LEFT({ timestamp6 } , { TIMESTAMP_PRECISION_POS + coltype .precision } ), { TIMESTAMP_PRECISION_POS + 6 } , '0')"
72
88
)
0 commit comments