You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

合并数据框时间与时区列时出现时区符号反转问题

合并CSV时间与时区列时时区符号反转问题

问题描述

我有一份包含行程数据的CSV文件,每行记录起点、终点、出发时间、到达时间,其中出发/到达时间为当地时间,对应有时区列。示例数据如下:

origin,destination,depart_time,depart_time_zone,arrival_time,arrival_time_zone
A,B,04/04/2023 08:01,GMT-04:00,04/04/2023 09:02,GMT-04:00
C,D,04/04/2023 09:20,GMT-04:00,04/04/2023 16:48,GMT-05:00

尝试用以下代码合并时间与时区列:

data = pd.read_csv('trips.csv', parse_dates={'depart' : ['depart_time','depart_time_zone'],'arrive' : ['arrival_time','arrival_time_zone']})

但发现解析结果异常:CSV第一行中depart_time=04/04/2023 08:00、depart_time_zone=GMT-04:00,输出的depart字段却显示为2023-04-04 08:00:00+04:00,时区符号从-04变成了+04,这是解析错误吗?


问题原因

这确实是解析错误。当pandas用parse_dates合并depart_time和depart_time_zone时,会生成类似"04/04/2023 08:01 GMT-04:00"的字符串,而pandas依赖的日期解析器(如dateutil.parser)对GMT-xx:xx格式的解读存在逻辑偏差:它错误地将GMT-04:00理解为比UTC早4小时(即UTC+4),但实际上GMT-04:00表示的是比UTC晚4小时(UTC-4),最终导致时区符号反转。


解决方案

不要直接依赖parse_dates合并列,而是手动处理时间与时区的解析,以下是两种可行方案:

方案1:手动拼接为ISO兼容格式解析

通过去掉GMT前缀,将时区格式转换为解析器能正确识别的偏移格式,再统一解析:

import pandas as pd
from dateutil import parser

# 读取CSV,不自动解析日期
df = pd.read_csv('trips.csv')

# 处理出发时间:拼接成"时间 时区偏移"格式(移除GMT前缀)
df['depart'] = df.apply(
    lambda row: parser.parse(f"{row['depart_time']} {row['depart_time_zone'].replace('GMT', '')}"),
    axis=1
)

# 处理到达时间同理
df['arrive'] = df.apply(
    lambda row: parser.parse(f"{row['arrival_time']} {row['arrival_time_zone'].replace('GMT', '')}"),
    axis=1
)

方案2:使用时区对象本地化时间

利用zoneinfo(Python 3.9+)将GMT偏移转换为标准时区对象,再为朴素时间添加时区信息:

import pandas as pd
from zoneinfo import ZoneInfo

# 读取CSV并单独解析时间列
df = pd.read_csv('trips.csv', parse_dates=['depart_time', 'arrival_time'])

# 转换GMT偏移为zoneinfo兼容的时区对象
# 注意:Etc时区命名规则与GMT相反,GMT-4对应Etc/GMT+4,GMT+5对应Etc/GMT-5
def gmt_to_zone(gmt_str):
    offset = gmt_str.lstrip('GMT')
    if offset.startswith('-'):
        return ZoneInfo(f"Etc/GMT{offset[1:]}")
    elif offset.startswith('+'):
        return ZoneInfo(f"Etc/GMT-{offset[1:]}")
    return ZoneInfo("Etc/GMT")

# 为时间列添加时区信息
df['depart'] = df.apply(
    lambda row: row['depart_time'].tz_localize(gmt_to_zone(row['depart_time_zone'])),
    axis=1
)
df['arrive'] = df.apply(
    lambda row: row['arrival_time'].tz_localize(gmt_to_zone(row['arrival_time_zone'])),
    axis=1
)

执行上述方案后,第一行的depart字段会正确显示为2023-04-04 08:01:00-04:00,时区符号与原始数据一致。


内容的提问来源于stack exchange,提问作者Joris Kinable

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 11:38:00