PyArrow无法解析带时区的Timestamp?问题排查与解决
问题:带时区偏移的JSON时间戳无法转换为PyArrow的timestamp('s')类型
我有一个包含如下字段的JSON文件:
"BirthDate":"2022-09-05T08:08:46.000+00:00"
我希望基于该文件创建Parquet文件,已为PyArrow准备固定Schema,将BirthDate定义为pa.timestamp('s')。但转换时出现如下错误:
ERROR:root:Failed of conversion of JSON to timestamp[s], couldn't parse:2022-09-05T08:08:46.000+00:00
使用的PyArrow代码如下:
parquet_file = pyarrow_json.read_json(json_file, parse_options=pyarrow_json.ParseOptions( explicit_schema=prepared_schema, unexpected_field_behavior='ignore'))
另外,部分不含"+"的时间戳文件可正常转换,请问该问题的原因是什么?如何解决?
原因分析
PyArrow的pa.timestamp('s')默认是无时区的timestamp类型,而你的时间戳字符串包含+00:00时区偏移标识。PyArrow默认解析逻辑无法将带时区的字符串直接映射到无时区的timestamp类型,因此抛出解析失败错误;不含"+"的时间戳属于标准无时区ISO格式,能与Schema定义匹配,所以可正常解析。
解决方法
方案1:将Schema修改为带时区的timestamp类型
直接调整Schema,把BirthDate定义为带UTC时区的timestamp类型,让PyArrow直接解析带时区偏移的字符串:
import pyarrow as pa prepared_schema = pa.schema([ # 其他字段按需添加 ('BirthDate', pa.timestamp('s', tz='UTC')) ]) # 后续读取代码不变 parquet_file = pyarrow_json.read_json(json_file, parse_options=pyarrow_json.ParseOptions( explicit_schema=prepared_schema, unexpected_field_behavior='ignore'))
方案2:指定时间字符串解析格式(保留无时区Schema)
如果必须使用无时区的timestamp('s'),可通过ParseOptions的timestamp_parsers参数指定包含时区的格式字符串:
import pyarrow as pa import pyarrow.json as pyarrow_json prepared_schema = pa.schema([ ('BirthDate', pa.timestamp('s')) ]) parse_options = pyarrow_json.ParseOptions( explicit_schema=prepared_schema, unexpected_field_behavior='ignore', # 指定匹配带时区偏移的时间格式 timestamp_parsers=['%Y-%m-%dT%H:%M:%S.%f%z'] ) parquet_file = pyarrow_json.read_json(json_file, parse_options=parse_options)
这种方式下,PyArrow会自动将带时区的时间转换为UTC时间后,存储为无时区的timestamp类型,保证数据准确性。
方案3:自定义时间解析函数(灵活处理特殊格式)
如果需要更灵活的处理逻辑(比如截断毫秒、适配多时区偏移),可以自定义解析函数:
import pyarrow as pa import pyarrow.json as pyarrow_json from datetime import datetime def parse_tz_timestamp(s): # 解析带时区的时间字符串 dt = datetime.fromisoformat(s) # 转换为UTC时间(可根据需求调整) dt_utc = dt.astimezone(datetime.timezone.utc) # 返回无时区datetime,匹配Schema的timestamp('s') return dt_utc.replace(tzinfo=None) prepared_schema = pa.schema([ ('BirthDate', pa.timestamp('s')) ]) parse_options = pyarrow_json.ParseOptions( explicit_schema=prepared_schema, unexpected_field_behavior='ignore', timestamp_parsers=[parse_tz_timestamp] ) parquet_file = pyarrow_json.read_json(json_file, parse_options=parse_options)
内容的提问来源于stack exchange,提问作者martin
相关产品推荐
相关产品推荐

