如何在Pandas中更改日期时间格式

233

我的数据帧有一个 DOB 列(例如格式为 1/1/2016),默认情况下会转换为 Pandas 的 'object' 数据类型。

使用 df['DOB'] = pd.to_datetime(df['DOB']) 将其转换为日期格式,日期将被转换为:2016-01-26,且其 dtypedatetime64[ns]

现在我想将该日期格式转换为 01/26/2016 或任何其他一般日期格式。 我该怎么做?

(无论我尝试什么方法,它总是显示日期的格式为 2016-01-26。)


你是在寻找只能在Jupyter笔记本下运行的解决方案吗?(在这种情况下,请使用每列“样式化程序”)还是适用于普通Python控制台和iPython? - smci
1
注意: datetime 作为一个保存日期和时间信息的数据结构没有格式 - 它只是一个数据结构。它的内容可以以一定的方式 /“格式”进行显示。或者如果您有表示日期/时间的字符串,则可以以一定的方式 /“格式”在其中表达。 - FObersteiner
@MrFuppes 这是真的,但它确实有一个默认格式与__str __()方法。我只是提醒一下以防有新手感到困惑。 - wjandrea
有没有办法实现格式更改(即样式)和数据类型更改?例如,如果原始列包含格式为 yyyy-mm-dd 的字符串格式数据。有没有办法将日期转换为日期时间数据类型,并使用 dd/mm/yyyy 格式? - Josh_BI_UK
01/26/2016 不是一般的日期格式。它是美国特定的,如果日期小于等于12,它也可能是英国的dd/mm/yyyy格式,因此含糊不清。在任何可以的地方,请使用YYYY-MM-DD格式,其他任何格式都会带来很多麻烦。唯一不应该使用这种格式的地方是用户界面本身,当需要以适合用户文化的方式显示时。 - dsz
9个回答

409

如果您需要将datetime格式转换为其他格式,可以使用dt.strftime(但请注意,此时列的dtype将是objectstring)):

import pandas as pd

df = pd.DataFrame({'DOB': {0: '26/1/2016', 1: '26/1/2016'}})
print (df)
         DOB
0  26/1/2016 
1  26/1/2016

df['DOB'] = pd.to_datetime(df.DOB)
print (df)
         DOB
0 2016-01-26
1 2016-01-26

df['DOB1'] = df['DOB'].dt.strftime('%m/%d/%Y')
print (df)
         DOB        DOB1
0 2016-01-26  01/26/2016
1 2016-01-26  01/26/2016

53
“strftime” 将日期时间列转换为 Unicode 格式,为了在 DOB1 上执行操作,我们需要将其再次转换为日期时间格式。有没有其他的格式化方式可以在不丢失数据类型的情况下进行? - M.Zaman
让我们在聊天中继续这个讨论 - jezrael

48

改变格式但不改变类型:

df['date'] = pd.to_datetime(df["date"].dt.strftime('%Y-%m'))

4
请记住,在执行此操作之前,df["date"] 应为 datetime64。 - adhg
29
不!假设“date”列中某个项目的初始值为“2019年11月26日”。strftime()意味着“时间字符串”,因此对于该项,df["date"].dt.strftime('%Y-%m')将成为一个字符串“2019-11”。然后,pd.to_datetime()将把这个字符串转换回datetime64格式,但现在是“2019年11月1日”!所以结果将是:没有格式更改,但日期值本身发生了变化! - MarianD
12
@MarianD:您对每个答案的评论都很有用,但您能否总结一下它们,并在回答底部提供一个“陷阱/不要这样做”的摘要?此外,您需要明确说明每个问题的问题所在:如果任何输入日期不是预期格式之一,则可能会引发异常或混淆日期。仅仅到处写“不行!”并不能表达清楚。 - smci

44

数据框单元格的内容(二进制值)和其呈现方式(供人类查看)之间存在差异。

因此,问题是:如何在不改变数据/数据类型本身的情况下达到适当的呈现方式

这里是答案:

  • 如果您使用 Jupyter笔记本来显示您的数据框,或者
  • 如果您想要以HTML文件的形式呈现(甚至带有许多准备好的多余idclass属性以进行进一步CSS样式设置 - 您可以使用它们,也可以不使用它们),

请使用样式样式不会更改数据/数据框列的数据/数据类型。

现在我向您展示如何在Jupyter笔记本中实现它 - 如果要以HTML文件形式进行演示,请参见本答案末尾的注释。

我假设您的列DOB已经具有datetime64类型(您已经展示了您知道如何实现它)。 我准备了一个简单的数据框(仅有一列),以向您展示一些基本样式:

  • 未设置样式:

    df
    
          DOB
0  2019-07-03
1  2019-08-03
2  2019-09-03
3  2019-10-03
  • 将其格式化为 mm/dd/yyyy

    df.style.format({"DOB": lambda t: t.strftime("%m/%d/%Y")})
    
          DOB
0  07/03/2019
1  08/03/2019
2  09/03/2019
3  10/03/2019
  • 将其样式设置为dd-mm-yyyy

    df.style.format({"DOB": lambda t: t.strftime("%d-%m-%Y")}) 
    
          DOB
0  03-07-2019
1  03-08-2019
2  03-09-2019
3  03-10-2019

小心!
返回的对象不是数据框,而是Styler类的对象,所以不要将其赋回给df

不要这样做:

df = df.style.format({"DOB": lambda t: t.strftime("%m/%d/%Y")})    # Don't do this!

每个数据框都可以通过其.style属性访问其Styler对象,我们更改的是df.style对象,而不是数据框本身。

问题和答案:

  • 问:为什么在Jupyter笔记本单元格中,将您的Styler对象(或返回它的表达式)用作最后一个命令会显示您的(经过样式处理的)表格,而不是Styler对象本身?

  • 答:因为每个Styler对象都有一个回调方法._repr_html_(),该方法返回呈现数据帧(作为漂亮的HTML表格)的HTML代码。

    Jupyter Notebook IDE自动调用此方法以呈现具有该方法的对象。


注意:

你不需要使用Jupyter笔记本来进行样式设置(即,对数据框进行美化而不改变其数据/数据类型)。

如果你想要获得一个包含HTML代码的字符串(例如,将格式化后的数据框发布到Web上,或者仅仅是以HTML格式呈现表格),Styler对象也有一个名为render()的方法:

df_styler = df.style.format({"DOB": lambda t: t.strftime("%m/%d/%Y")})
HTML_string = df_styler.render()

1
值得指出的是,像这样的样式代码旨在在Jupyter笔记本下运行,并且仅在该环境下生效,在控制台或iPython中运行时绝对没有任何影响。OP没有指定“在Jupyter下”,因此根据他们的设置,这可能是可行的解决方案,也可能不是。许多数据科学代码被复制并粘贴,而Jupyter特定的假设没有得到明确说明,然后人们会想知道为什么在(控制台)环境中运行样式代码“无法工作”。 - smci
@smci,我的回答第二段明确提到了吗?以条件“if”语句的形式,这对于每个程序员都是众所周知的吧?尽管如此,感谢您的评论,它可能对某些人有帮助。 - MarianD
否则我可以将其编写为非Jupyter方法中的陷阱总结。 - smci
@smci,如果您能写出那些陷阱的概括就太好了。谢谢。 - MarianD
2
好的,只要你不在下面写“不!”就行 :) - smci
显示剩余2条评论

21

第一个答案相比,我建议首先使用dt.strftime(),然后再使用pd.to_datetime()。这样做的话,仍将得到日期时间数据类型。

例如,

import pandas as pd

df = pd.DataFrame({'DOB': {0: '26/1/2016 ', 1: '26/1/2016 '})
print(df.dtypes)

df['DOB1'] = df['DOB'].dt.strftime('%m/%d/%Y')
print(df.dtypes)

df['DOB1'] = pd.to_datetime(df['DOB1'])
print(df.dtypes)

6
在我的情况下,这并不起作用。具体来说,该列被转换为日期时间数据类型,但值也被转换回原始格式! - Outcast
1
不!语法错误(缺少大括号),在我的Pandas版本(0.25.1)中,另一个语法错误(dt.strftime() - 只能使用.dt访问器与日期时间值),您依赖于固有数据类型,但在不同版本的Pandas中,固有数据类型可能会有所不同,并且奇怪的逻辑-为什么要将日期时间转换为字符串,然后再转换回日期时间?请参见我对rishi jain答案的评论。 - MarianD

8
以下代码对我有用,而不是之前的代码:
df['DOB']=pd.to_datetime(df['DOB'].astype(str), format='%m/%d/%Y')

10
不!你的参数format='%m/%d/%Y'是用于解析字符串的,也就是说,你应该按照这种格式提供字符串(例如 "5/13/2019")。没有其他的格式更改。它仍将显示为 2019-05-13——或者如果df['DOB'].astype(str)包含未采用此种格式(例如采用 "2019-05-13" 格式)的项目,则会引发异常。 - MarianD
1
“the previous one”是什么?它指的是哪篇文章?或者你是指“the previous ones”(所有的)?请通过编辑(更改)您的答案来回复,而不是在评论中回复(不要包含“Edit:”,“Update:”或类似内容 - 答案应该看起来像是今天写的)。 - Peter Mortensen

0
df['variable'] = pd.to_datetime(df['variable'], errors='coerce')

0
你可以尝试这个。它会将日期格式转换为DD-MM-YYYY:
df['DOB'] = pd.to_datetime(df['DOB'], dayfirst = True)

3
不! dayfirst=True 只是日期解析顺序的规定,例如,模棱两可的日期字符串“2-1-2019”将解析为2019年1月2日,而不是2019年2月1日。 没有其他影响,不会改变输出格式。 - MarianD

-2
以下代码将转换为“datetime”类型,并以给定的格式字符串进行格式化。
df['DOB'] = pd.to_datetime(df['DOB'].dt.strftime('%m/%d/%Y'))

2
将其更改为此:df['DOB']=pd.to_datetime(df['DOB']).dt.strftime('%m/%d/%Y') - John Doe
1
不!- 为什么要将日期时间转换为字符串,然后再转回日期时间?请看我对其他答案的评论。 - MarianD

-2
以下是对我有效的代码。我们需要非常小心地处理格式。下面的链接肯定会对了解您现有的格式并将其更改为所需格式(请遵循{{link1:strftime()和strptime()行为}}中的strftime()和strptime()格式代码)非常有用:
data['date_new_format'] = pd.to_datetime(data['date_to_be_changed'] , format='%b-%y')

3
另一个困惑的人和误导性的回答。请阅读其他答案的评论,它们可能会帮助你理解重点。 - MarianD
提供的链接将有助于理解Python中各种日期格式及其用法。我在任何答案中都没有找到这个信息,所以我为了他人的利益而发布了它。我认为这里没有任何混淆。请具体说明您的评论,以便我可以计划更改我的答案。 - Anil Kumar
我已经阅读了所有的答案和评论。它们绝对是有用的。但是,除此之外,提供的链接可以更好地理解不同类型的日期格式和转换(在可能的情况下)。 - Anil Kumar
1
你的回答也很有用。但是有用并不等同于正确。例如,“使用deque进行FIFO”也很有用,但与OP的问题无关。 - MarianD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接