在转换为日期时间的列上使用 timedelta 和 strftime

Posted

技术标签:

【中文标题】在转换为日期时间的列上使用 timedelta 和 strftime【英文标题】:Using timedelta and strftime on column converted to datetime 【发布时间】:2021-08-16 03:13:13 【问题描述】:

目标: 将 *.csv 读取到数据框后,我想将出生日期列转换为这种格式:%m-%d-%Y。然后把它们写成excel。 *.csv 有 600K+ 记录。

总结:我有 20 世纪和 21 世纪的日期,而且这些年份有时会重叠。例如,我可以从 1901 年到 2001 年有四位数的年份。因此,我不得不使用从 this answer 借来的代码 sn-p。

我的尝试和预期: 我最初将该列转换为日期时间,并使用strftime('%m-%d-%Y')。但是,那么 1970 年及之前的年份将被写为 20--。例如,这里的 2070 年和 2068 年应该分别是 1970 年和 1968 年。如果重要的话,生日列是dtype object

import pandas as pd
from datetime import timedelta
from datetime import datetime

#birthdate column
birthdate = 'PATIENT_BIRTH_DATE'
#after reading the *.csv to a dataframe, convert the birthdate column to %m-%d-%Y format
df[birthdate] = pd.to_datetime(df[birthdate]).dt.strftime("%m-%d-%Y")

#prints
0    08-24-1996
1    10-16-1971
2    02-19-2070
3    09-25-2068

所以,我使用上面提到的代码 sn-p 来解决这个问题。但是,现在我似乎无法从写入 Excel 的日期中删除时间。如果我打印到终端,我没有时间,但是当我写到 Excel 时,我会。看起来像这样:1996-08-24 00:00:00

df[birthdate] = pd.to_datetime(df[birthdate])

future = df[birthdate] > datetime.today()
df.loc[future, birthdate] -= timedelta(days=365.25*100)

如果我在这里使用df[birthdate] = pd.to_datetime(df[birthdate]).dt.strftime("%m-%d-%Y"),我会得到一个错误:TypeError: '>' not supported between instances of 'str' and 'datetime.datetime'

【问题讨论】:

澄清一下:基本上你的问题是你的数据源 (csv) 中有 2 位数的年份? @MrFuppes 这令人困惑。例如,*.csv 中的公式栏显示 6/7/1943。但字段值显示 7-Jun-43。所以,我不知道如何准确地回答你的问题。 但是您有 csv 格式的数据?还是 xls(x) 文件? - 如果是 csv,您可以在文本编辑器中打开它(例如,notepad++ 在 Windows 上很好)并检查“真实”格式,而不是 Excel 告诉您的格式。 Excel 喜欢为你考虑,这并不总是聪明的^^ 是的,源文件是*.csv格式。我用记事本++打开它,日期显示为 7-Jun-43。你到底在说什么? 这并不是说出来的那么简单。我只是好奇你用 2 位数的年份去哪里。 【参考方案1】:

Excel 正在对其进行格式化,但您可以在写入工作簿时更新该选择。

您可以使用 xlsxwriter 引擎来指定给定列的格式。

https://xlsxwriter.readthedocs.io/example_pandas_column_formats.html

这里也是使用 xlsxwriter 格式化日期的指南,但我提供了一个解决方案,可以从下面推断出来

https://xlsxwriter.readthedocs.io/working_with_dates_and_time.html?highlight=date%20format

这仅在列是日期时间格式时才有效,因此可能需要验证使用此 sn-p

df['date1'] = df['date1'].dt.strftime('%m-%d-%Y')

然后运行以下命令,注意应用格式的列将根据数据框中的哪一列具有日期时间而改变。

df.to_excel(writer, sheet_name='Sheet1')

writer = pd.ExcelWriter("output.xlsx", engine='xlsxwriter')

# Get the xlsxwriter workbook and worksheet objects.
workbook  = writer.book
worksheet = writer.sheets['Sheet1']
# %m-%d-%Y
format = workbook.add_format('num_format': 'mm-dd-yyyy')

# Set the column width and format.
worksheet.set_column('B:B', 18, format)

writer.save()

【讨论】:

我使用 df[birthdate] = pd.to_datetime(df[birthdate], errors='coerce') 将该列转换为日期时间。然后我用了你的df['date1'] = df['date1'].dt.strftime('%m-%d-%Y')。但是,我仍然无法通过TypeError: '>' not supported between instances of 'str' and 'Timestamp',它指的是这一行:df.loc[df[birthdate] > pd.Timestamp('now'), birthdate] -= pd.tseries.offsets.DateOffset(years=100) 所以听起来df.loc[df[birthdate] > pd.Timestamp('now'), birthdate] -= pd.tseries.offsets.DateOffset(years=100) 导致了错误。在您完成抵消过程后,我会转换 df['date1'] = df['date1'].dt.strftime('%m-%d-%Y')【参考方案2】:

我建议添加一个小补充,以说明 100 年的偏移量

import pandas as pd

birthdate = 'PATIENT_BIRTH_DATE'
df = pd.DataFrame(birthdate: pd.to_datetime(["08-24-1996", "10-16-1971", "02-19-2070", "09-25-2068"]))

df.loc[df[birthdate] > pd.Timestamp('now'), birthdate] -= pd.tseries.offsets.DateOffset(years=100)

df
  PATIENT_BIRTH_DATE
0         1996-08-24
1         1971-10-16
2         1970-02-19
3         1968-09-25

而不是使用每年的平均天数。


“从不使用两位数年” 存储桶

+1。

【讨论】:

以上是关于在转换为日期时间的列上使用 timedelta 和 strftime的主要内容,如果未能解决你的问题,请参考以下文章

在 Oracle apex 中的列上设置自定义验证

从 T-SQL 导出到 Excel 的问题,包括列名和未导出的列上的排序

JPA 或 Hibernate - 在不同类型的列上连接表

将具有日期格式的列中的所有行转换为文本格式

熊猫将带有年份整数的列转换为日期时间

使用 sequelize 将 datetime 转换为 where 条件下的列的日期