【问题标题】:mixed datetime format needs to be in one format混合日期时间格式需要是一种格式
【发布时间】:2020-08-26 02:54:09
【问题描述】:

我有一个包含数百列的大型 CSV,我想将这些列提取到 SQL Server 中。 我正在使用 Pandas 将其作为数据帧读取,并通过 pyodbc 调用存储过程来写入数据。我以前用较小的 CSV 做过很多次。在这种情况下,我有几列代表日期时间值。问题是,在单个列中,我可以拥有使用不同日期格式的行:

'2020-07-08T09:00:01+00:00'
'2020-07-08T05:00:07Z'
'2020-07-08T06:40:23.000Z'

我可以用这个解析所有这些

from dateutil import parser
z1 = parser.isoparse(z)

其中 z 是这些字符串中的任何一个。这是我的困境。如果我只是将这些写为字符串,则对 sql 的调用喜欢格式“2020-07-08T06:40:23.000Z”,而不是其他格式。所以我想用那种格式写。

所以我试试

date_format = "%Y-%m-%dT%H:%M:%S.%fZ"
parser.isoparse(z).strftime(frm)

但是,该格式写入字符串“2012-11-29T16:33:00.000000Z”,而不是“2012-11-29T16:33:00.000Z” 最后一个句点和 Z 之间必须正好有 3 个零。我尝试使用“%3f”,但 strftime() 不喜欢这样。我可以用我自己的函数来“修复它”来提取额外的“0”,但这似乎很俗气。似乎应该有某种方法可以像我想要的那样直接编写它(sql似乎期望的方式)。咒语是什么?

【问题讨论】:

  • This question 是相关的。最好的答案是简单地做你提到的事情并分割字符串。
  • 你也可以考虑嵌套 try/except 块,每个块都有不同的 strptime 格式字符串。诚然不优雅,但任何不匹配的格式都会引发 ValueError。

标签: python datetime pyodbc strftime


【解决方案1】:

似乎解析到日期时间不是这里的问题。 pd.to_datetime 对这些格式做得很好(主要是使用 dateutil.parser.parse)。要获得所需的 3 位小数秒格式,您可以使用 the docs 中所述的正则表达式搜索和替换。例如:

import pandas as pd

df = pd.DataFrame({'date0': ['2020-07-08T09:00:01+00:00'], 
                   'date1': ['2020-07-08T05:00:07Z'], 
                   'date2': ['2020-07-08T06:40:23.000Z']})

# parsing to datetime is no issue:
df = df.applymap(pd.to_datetime)

# now replace the ".ffffffZ" pattern with ".fffZ":
pat = '.[0-9]{6}UTC'
repl = lambda m: m.group(0)[:4] + 'Z'

# e.g. like
df['date0'].dt.strftime("%Y-%m-%dT%H:%M:%S.%f%Z").str.replace(pat, repl)
# 0    2020-07-08T09:00:01.000Z
# Name: date0, dtype: object

注意,这截断到毫秒。如果您想四舍五入,请在此之前进行,例如如here 所述,频率别名为'L'(另见here)。


如果您知道所有日期时间都是 UTC,您当然也可以简单地剪切字符串并添加“Z”,

df['date0'].dt.strftime("%Y-%m-%dT%H:%M:%S.%f").str[:-3] + 'Z'
# 0    2020-07-08T09:00:01.000Z
# Name: date0, dtype: object

有趣的是,这种方法在快速调用timeit时似乎并没有带来性能提升:

%timeit df['date0'].dt.strftime("%Y-%m-%dT%H:%M:%S.%f").str[:-3] + 'Z'
615 µs ± 38.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit df['date0'].dt.strftime("%Y-%m-%dT%H:%M:%S.%f%Z").str.replace(pat, repl)
468 µs ± 13.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

【讨论】:

  • 使用[:-4] + 'Z' 比使用.str.replace(...) 可能更快更清晰。
  • 如果速度有问题,需要四舍五入,也可以加0.0005s再截断;但是,请进行测量以检查它是否实际上更快。
  • @sabik:是的,显式切片会更快。但这并不总是问题 - 在这里,正则表达式替换将特定于“UTC”并使用另一个 tzinfo 跳过字符串。
  • @sabik: 刚刚做了一个小基准测试,replace 方法似乎表现不错
猜你喜欢
  • 1970-01-01
  • 2022-01-19
  • 1970-01-01
  • 2012-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-24
相关资源
最近更新 更多