OSM文件特定时间数据读取报错:时区不兼容问题排查
解决OSM数据特定时间读取的时区兼容问题及警告
问题分析
- 警告原因:函数内部变量名
datedelems与函数名重名,造成变量遮蔽;代码检测工具误判date参数未使用(实际在query中通过@date调用),核心问题是命名冲突。 - 报错原因:从OSM读取的
ts字段是带UTC时区的datetime类型(datetime64[ns, UTC]),而传入的日期字符串转换后是无时区的datetime对象,两者无法直接比较。
解决方案
1. 处理变量遮蔽警告
修改函数内部变量名,避免与函数名重复,消除遮蔽警告:
def datedelems(history, date): # 将变量名从datedelems改为temp_df,避免与函数名冲突 temp_df = (history.query("ts <= @date") .groupby(['type','id'])['version'] .max() .reset_index()) return pandas.merge(temp_df, history, on=['type','id','version'])
2. 解决时区不兼容报错
以下两种方案任选其一即可:
方案A:将传入的日期转换为带UTC时区的Timestamp
把查询日期转换成与ts字段时区一致的对象:
# 生成带UTC时区的目标日期 target_date = pandas.Timestamp("2008-02-01", tz='UTC') oldelem = datedelems(elements, target_date) oldelem.head()
方案B:移除DataFrame中ts字段的时区信息
如果业务不需要保留时区,可以将ts字段转换为无时区datetime:
在创建elements DataFrame后添加一行代码:
# 移除ts字段的时区信息 elements['ts'] = elements['ts'].dt.tz_localize(None)
之后直接传入字符串日期即可:
oldelem = datedelems(elements, "2008-02-01") oldelem.head()
完整修正代码示例
整合所有修改后的完整代码:
import osmium import pandas class TimelineHandler(osmium.SimpleHandler): def __init__(self): osmium.SimpleHandler.__init__(self) self.elemtimeline = [] def relation(self, n): self.elemtimeline.append(["relation", n.id, n.version, n.visible, pandas.Timestamp(n.timestamp), n.uid, n.changeset, len(n.tags)]) tlhandler = TimelineHandler() tlhandler.apply_file('/.../.../.../koeln-regbez-internal.osh.pbf') colnames = ['type', 'id', 'version', 'visible', 'ts', 'uid', 'chgset', 'ntags'] elements = pandas.DataFrame(tlhandler.elemtimeline, columns=colnames) # 方案B:移除时区信息(选方案A则注释此行) elements['ts'] = elements['ts'].dt.tz_localize(None) elements = elements.sort_values(by=['type', 'id', 'ts']) print(elements.head()) elements.to_csv("Köln-metropole.csv", date_format='%Y-%m-%d %H:%M:%S') def updatedelem(data): updata = data.groupby(['type', 'id'])['version'].max().reset_index() return pandas.merge(updata, data, on=['id', 'version']) uptodate_elem = updatedelem(elements) print(uptodate_elem.head()) elements.to_csv("Köln-metropole.csv", date_format='%Y-%m-%d %H:%M:%S') # 修正后的datedelems函数 def datedelems(history, date): temp_df = (history.query("ts <= @date") .groupby(['type','id'])['version'] .max() .reset_index()) return pandas.merge(temp_df, history, on=['type','id','version']) # 方案A调用(选方案B则注释此段,改用下方方案B调用) # target_date = pandas.Timestamp("2008-02-01", tz='UTC') # oldelem = datedelems(elements, target_date) # 方案B调用 oldelem = datedelems(elements, "2008-02-01") print(oldelem.head())
内容的提问来源于stack exchange,提问作者Mustermax
相关产品推荐
相关产品推荐

