在Python中将日期转换为日期时间

973

在Python中,是否有内置方法可以将date转换为datetime,例如获取给定日期午夜的datetime?相反的转换很容易: datetime有一个.date()方法。

我真的必须手动调用datetime(d.year, d.month, d.day)吗?


210
这并不是一个愚蠢的问题;日期对象应该有一个.datetime()方法,而愚蠢的是它们没有这样的方法。 - Zags
25
@Zags: 或者使用 datetime.from_date() 构造函数。 - jfs
15
不应该。日期是日期时间的子集(甚至名称中都有)。从日期时间中清楚地知道日期是什么。但反过来,一个日期是一天的时间块(通常是这样),因此它可能有许多日期时间。从日期推出什么日期时间?你不能总是写成00:00,因为如果那个时间不存在,例如夏令时跳过了它,那怎么办呢?不是很容易。 - dalore
7
夏令时在凌晨1点至2点之间进行,以避免你所描述的问题。 - Zags
3
@zags 这完全取决于源和目标时区,你可能会在凌晨1点进行夏令时更改,但这将对其他某个时区的午夜更改相应。如果你正在编程,你使用的是哪个时区?你很可能最终会尝试获取不存在的时间。我的观点仍然成立,给日期添加时间并不是一件简单的事情。然后你还要考虑你的新日期时间是否也具有时区感知性或者是天真的。 - dalore
显示剩余2条评论
14个回答

1220
你可以使用 datetime.combine(date, time) 来实现;对于时间,你需要创建一个初始化为午夜的 datetime.time 对象。
from datetime import date
from datetime import datetime

dt = datetime.combine(date.today(), datetime.min.time())

117
谢谢。结合time()返回(0,0)的事实,我认为这是最简洁的写法:datetime.combine(d, time()) - EMP
46
请注意不要混淆datetime.time()和time.time()。有资格的名称胜利! - Dustin
10
好的,没问题。幸运的是,如果传入的不是datetime.time而是time.time或其他类型数据,combine()函数会引发一个异常。 - EMP
23
对于午夜(即当天的 00:00),在 Python 中有一个常量,可以使用 datetime.time.min(适用于 2.7.1 及以上版本)或 datetime.min.time()(较旧版本的 Python)来表示。 - larham1
27
方案不错,但我认为datetime.min.time()并不是获取00:00:00时间的最简洁方式。这是因为它首先检索datetime可表示的最小值,然后获取其时间部分。顺便提一下,datetime.min = datetime(MINYEAR, 1, 1, tzinfo=None),并且有一个00:00:00的时间。然而,我认为更清晰的方法是通过time.min或time(0, 0, 0, 0)显式创建00:00:00时间。 - Florin Dumitrescu
显示剩余6条评论

206

有几种方法,虽然我相信你提到的那个(并且不喜欢的)是最易读的。

>>> import datetime
>>> t=datetime.date.today()
>>> datetime.datetime.fromordinal(t.toordinal())
datetime.datetime(2009, 12, 20, 0, 0)

>>> datetime.datetime(t.year, t.month, t.day)
datetime.datetime(2009, 12, 20, 0, 0)

>>> datetime.datetime(*t.timetuple()[:-4])
datetime.datetime(2009, 12, 20, 0, 0)

等等其他操作——但基本上它们都依赖于从date对象中适当提取信息,并将其重新插入到适合datetime的构造函数或类函数中。


31
非常好的观点。datetime(d.year, d.month, d.day) 确实比被接受的答案 datetime.combine(d, datetime.min.time()) 更易读。 - Simon Elms
3
@SimonTewsi 提出的 midnight = datetime.datetime.combine(d, datetime.time.min) 看起来更简洁。(建议来自 @larham1 - jfs
2
@J. F. Sebastian:这样做会更加简洁,但我同意Wes Winham在他的回答中提到的,这需要读者知道datetime.time.min代表什么。而对我来说,datetime(d.year, d.month, d.day)更明显(一个没有时间组件的日期时间)。虽然这只是一个小问题,但使用像“midnight”这样的变量名使得结果很明显,即使读者不知道datetime.time.min代表什么。 - Simon Elms
另一种有趣的变体:datetime.datetime(*(getattr(d,attr)for attr in(“year”,“month”,“day”)))。这样,您可以轻松修改对您重要的属性列表。例如,可以动态添加小时。 - Guimoute
d = d.replace(hour=0, minute=0, second=0, microsecond=0) 这种方法也是可行的,但我不喜欢这种方式,因为它强制你必须知道所有关键字并手动将它们设置为0。对于4个参数来说,这种方法可以工作,但如果有12个参数,我们就会开始质疑这种方法的可行性。 - Guimoute

125

被采纳的答案是正确的,但我更喜欢避免使用datetime.min.time(),因为对我来说不太明显它具体做了什么。如果您觉得很明显,那么就更好了。我对timetuple方法和依赖于排序也有同样的感觉。

在我看来,最可读、最明确的方法是不依赖于读者非常熟悉datetime模块 API:

from datetime import date, datetime
today = date.today()
today_with_time = datetime(
    year=today.year, 
    month=today.month,
    day=today.day,
)

这是我的看法,“明确胜于隐晦”。


致敬Kyle Gibson原创点子的一顶帽子:http://stackoverflow.com/users/513197/kyle-gibson - Wes Winham
1
我同意你的看法。这些含有timetuple和星号以及min.time()的其它答案都需要研究,而且与VBA中微软处理日期和日期时间的简易方式相比,Python处理日期和日期时间的方式也稍显繁琐。在那种语言中,只需要将它们包裹在井号中即可。不过我又岔了话题。 - Bobort
2
d2dt = lambda date: datetime(year=date.year, month=date.month, day=date.day) 是这个答案中的一行函数。 - aliqandil
2
这个代码可以运行,但是如果你需要时区感知的 datetime,那么你可以 import pytz,然后添加 tzinfo=pytz.timezone('Europe/London'),例如。 - alstr

58
你可以使用date.timetuple()方法和解包运算符*
args = d.timetuple()[:6]
datetime.datetime(*args)

5
这对我的情况很有用。我不知道我正在传递的是日期还是日期时间,检查它是哪个类并不是Python风格。这种方法看起来可以同时适用于日期时间和日期对象。 - Gattster
在发现datetime.combine通过@kiamlaluno的回答之前,我曾经使用过这个。我认为它相当符合Python风格,特别是构造一个datetime.time对象可能看起来像datetime.time(*map(int, "H:M:S".split(":"))). - Tom
这段代码在许多其他情境下也很有用,例如通过索引到低至[:3]甚至更低来截断秒、分或小时,如果您使用+ (n,)进行填充,则可以更低,如:dt.datetime(*(dt.datetime.utcnow().timetuple()[:2] + (1, ))) - Thomas Browne
不错的方法,为了方便这里是 timetuple()文档 - Andrew Richards

12

今天是2016年,我认为最干净的解决方案由pandas Timestamp提供:

from datetime import date
import pandas as pd
d = date.today()
pd.Timestamp(d)

Timestamp是pandas中与datetime等价且在大多数情况下可以互换的类型。请检查:

from datetime import datetime
isinstance(pd.Timestamp(d), datetime)

但是如果你真的想要一个普通的日期时间,你仍然可以这样做:

pd.Timestamp(d).to_datetime()

相较于日期时间,在处理时区等方面,时间戳更加强大。事实上,时间戳非常强大,可惜的是它们的文档记录很差...


好的,很棒。我来这里是因为我认为需要一个Python日期时间解决方案来解决Pandas DatetimeIndex问题。可惜Pandas没有DateIndex的概念。 - Little Bobby Tables
40
为什么即使在2016年,我们仍需要一个庞大的包来进行日期时间操作? - cowbert
5
拿熊猫来做这件事情就像是用锤子去敲蚂蚁一样。 - Dee S
使用pandas来解决这个问题是过度杀伤力的。 - Tomasz Giba
1
to_datetime()已被弃用,请使用to_pydatetime()代替。对于那些已经因为某种原因必须使用Pandas并且需要日期时间格式的人来说,这是一个好答案。 - NumesSanguis

11

你也可以使用

date = datetime.utcnow().date()
dt = datetime.fromisoformat(date.isoformat())

print(dt)

datetime.datetime(2021, 11, 15, 0, 0)

日期时间:2021年11月15日,0时0分


2
你甚至可以通过以下方式将时间作为字符串添加进去:datetime.fromisoformat(date.isoformat() + ' 17:32') - Georg Pfolz

7

一种将日期转换为日期时间的方法尚未提及:

from datetime import date, datetime
d = date.today()
datetime.strptime(d.strftime('%Y%m%d'), '%Y%m%d')

3
是的,但是将整数转换为字符串并再次转换回去可能比直接使用整数计算更加昂贵,因此我只会在低容量处理时使用这种方法。 - Egor Kraev

5
您可以使用 easy_date 来简化操作:
import date_converter
my_datetime = date_converter.date_to_datetime(my_date)

4

我真的需要手动调用datetime(d.year, d.month, d.day)吗?

不必这样,您可以直接调用:

date_to_datetime(dt)

您可以在项目中的utils/time.py中实现一次,

from typing import Optional
from datetime import date, datetime

def date_to_datetime(
    dt: date,
    hour: Optional[int] = 0,
    minute: Optional[int] = 0, 
    second: Optional[int] = 0) -> datetime:

    return datetime(dt.year, dt.month, dt.day, hour, minute, second)

可能最好将tz添加到其中。 - JayTurnr
更好的做法是直接操作变量,而不是将其转换为字符串再进行操作,这样会更快。 - Akshay Vijay Jain

3

一个替代 toisoformat/fromisoformat 的方法:你可以使用 date.toordinaldatetime.fromordinal:

import datetime

start_date = datetime.date(1991, 2, 20)
start_date_midnight = datetime.datetime.fromordinal(start_date.toordinal())

我认为这比将其转换为/从字符串进行更有效率。

你可以这样测试这个过程:

def test_datetime_from_date():
    for x in range(1,1000000):
        date_ = datetime.date.fromordinal(x)
        datetime_ = datetime.datetime.fromordinal(date_.toordinal())
        datetime_iso_date, t, datetime_iso_time = datetime_.isoformat().partition("T")
        assert datetime_iso_date == date_.isoformat()

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