从S3加载Parquet数据至Redshift时日期异常问题排查
问题概述
将S3中的Parquet格式数据加载至Redshift表时,原本正常的YYYY-MM-DD日期,加载后变为2377-03-22 02:49:51:703这类异常未来时间。Redshift表字段类型为TIMESTAMP WITHOUT TIME ZONE ENCODE az64,该流程此前运行正常,2024年起出现此问题。
核心原因
Parquet的DATE类型以1970-01-01为起点的天数偏移量存储,而Redshift的TIMESTAMP类型以1970-01-01为起点的毫秒数偏移量存储。若未明确指定类型映射规则,部分场景下会误将DATE的天数偏移量当作毫秒数处理,导致时间被放大(1天=86400000毫秒),最终生成异常的未来时间。
解决方案
1. 明确指定字段类型映射
在wr.redshift.copy_from_files中添加column_types参数,强制指定Parquet日期字段到Redshift TIMESTAMP的映射规则,确保转换逻辑正确:
wr.redshift.copy_from_files( path = path, con = connection, use_threads = True, table = table, schema = schema, mode = 'upsert', primary_keys = pks, iam_role = ROLE_REDSHIFT, # 替换为你的实际日期字段名 column_types = {"target_date_column": "TIMESTAMP"} )
2. 验证Parquet文件的日期字段类型
确认Parquet中的日期字段为标准DATE类型,而非数值类型(比如用INT32存储天数)。可通过Pandas读取验证:
import pandas as pd df = pd.read_parquet("s3://your-bucket/path/to/test-file.parquet") print(df.dtypes)
若字段类型为datetime64[ns]或date则正常;若为数值类型,需先将其转换为日期类型再重新生成Parquet文件。
3. 调整Redshift COPY命令参数
wr.redshift.copy_from_files底层调用Redshift的COPY命令,可通过copy_options指定时间解析规则,确保DATE到TIMESTAMP的转换准确:
wr.redshift.copy_from_files( path = path, con = connection, use_threads = True, table = table, schema = schema, mode = 'upsert', primary_keys = pks, iam_role = ROLE_REDSHIFT, copy_options = [ "FORMAT AS PARQUET", "TIMEFORMAT 'auto'" ] )
TIMEFORMAT 'auto'会让Redshift自动识别时间格式,对Parquet的DATE类型会正确转换为当天0点的TIMESTAMP。
4. 验证转换结果
加载少量测试数据后,对比Parquet原始日期与Redshift表中数据:
-- 在Redshift中执行查询 SELECT target_date_column FROM your_schema.your_table LIMIT 10;
确认转换后的时间应为YYYY-MM-DD 00:00:00.000格式。
内容的提问来源于stack exchange,提问作者tonga

