[英]What is the standard way to add N seconds to datetime.time in Python?
給定 Python 中的datetime.time
值,是否有標准方法向其添加 integer 秒數,例如11:34:59
+ 3 = 11:35:02
?
這些顯而易見的想法行不通:
>>> datetime.time(11, 34, 59) + 3
TypeError: unsupported operand type(s) for +: 'datetime.time' and 'int'
>>> datetime.time(11, 34, 59) + datetime.timedelta(0, 3)
TypeError: unsupported operand type(s) for +: 'datetime.time' and 'datetime.timedelta'
>>> datetime.time(11, 34, 59) + datetime.time(0, 0, 3)
TypeError: unsupported operand type(s) for +: 'datetime.time' and 'datetime.time'
最后我寫了這樣的函數:
def add_secs_to_time(timeval, secs_to_add):
secs = timeval.hour * 3600 + timeval.minute * 60 + timeval.second
secs += secs_to_add
return datetime.time(secs // 3600, (secs % 3600) // 60, secs % 60)
我不禁想到我錯過了一種更簡單的方法來做到這一點。
您可以將完整的datetime
時間變量與timedelta
一起使用,並通過提供虛擬日期然后使用time
來獲取時間值。
例如:
import datetime
a = datetime.datetime(100,1,1,11,34,59)
b = a + datetime.timedelta(0,3) # days, seconds, then other fields.
print(a.time())
print(b.time())
結果是相隔三秒的兩個值:
11:34:59
11:35:02
您還可以選擇更具可讀性
b = a + datetime.timedelta(seconds=3)
如果你願意的話。
如果您正在尋找可以執行此操作的 function,您可以使用下面的addSecs
:
import datetime
def addSecs(tm, secs):
fulldate = datetime.datetime(100, 1, 1, tm.hour, tm.minute, tm.second)
fulldate = fulldate + datetime.timedelta(seconds=secs)
return fulldate.time()
a = datetime.datetime.now().time()
b = addSecs(a, 300)
print(a)
print(b)
這輸出:
09:11:55.775695
09:16:55
正如這里的其他人所說,您可以在整個過程中使用完整的日期時間對象:
from datetime import datetime, date, time, timedelta
sometime = time(8,00) # 8am
later = (datetime.combine(date.today(), sometime) + timedelta(seconds=3)).time()
但是,我認為有必要解釋一下為什么需要完整的日期時間對象。 考慮一下如果我在晚上 11 點增加 2 小時會發生什么。 什么是正確的行為? 一個例外,因為你的時間不能超過晚上 11:59? 它應該繞回去嗎?
不同的程序員會有不同的期望,所以無論他們選擇哪個結果都會讓很多人感到驚訝。 更糟糕的是,程序員編寫的代碼在最初測試時工作得很好,然后由於一些意想不到的事情而導致代碼崩潰。 這非常糟糕,這就是為什么不允許將 timedelta 對象添加到時間對象的原因。
一件小事,可能會增加清晰度以覆蓋秒數的默認值
>>> b = a + datetime.timedelta(seconds=3000)
>>> b
datetime.datetime(1, 1, 1, 12, 24, 59)
感謝@Pax Diablo、@bvmou 和@Arachnid 建議在整個過程中使用完整的日期時間。 如果我必須接受來自外部源的 datetime.time 對象,那么這似乎是一個替代add_secs_to_time()
function:
def add_secs_to_time(timeval, secs_to_add):
dummy_date = datetime.date(1, 1, 1)
full_datetime = datetime.datetime.combine(dummy_date, timeval)
added_datetime = full_datetime + datetime.timedelta(seconds=secs_to_add)
return added_datetime.time()
這段冗長的代碼可以壓縮成一行代碼:
(datetime.datetime.combine(datetime.date(1, 1, 1), timeval) + datetime.timedelta(seconds=secs_to_add)).time()
但我想無論如何我都想將其包裝在 function 中以確保代碼清晰。
您不能簡單地將數字添加到datetime
時間,因為不清楚使用的是什么單位:秒、小時、周......
有timedelta
class 用於日期和時間的操作。 datetime
減去datetime
得到timedelta
, datetime
加上timedelta
得到datetime
,兩個datetime
對象不能相加,盡管兩個timedelta
可以。
使用要添加的秒數創建timedelta
object,並將其添加到datetime
時間 object:
>>> from datetime import datetime, timedelta
>>> t = datetime.now() + timedelta(seconds=3000)
>>> print(t)
datetime.datetime(2018, 1, 17, 21, 47, 13, 90244)
C++ 中有相同的概念: std::chrono::duration
。
如果值得向您的項目添加另一個文件/依賴項,我剛剛編寫了一個小的 class,它擴展了datetime.time
並具有計算能力。 當你在午夜 go 時,它會繞零。 現在,“What time will it will be, 24 hours from now”有很多corner cases,包括夏令時、閏秒、歷史時區變化等等。 但有時您確實需要簡單的案例,這就是它要做的。
你的例子會寫成:
>>> import datetime
>>> import nptime
>>> nptime.nptime(11, 34, 59) + datetime.timedelta(0, 3)
nptime(11, 35, 2)
nptime
繼承自datetime.time
,因此這些方法中的任何一個也應該可用。
它可以從 PyPi 作為nptime
(“非迂腐時間”)獲得,或在 GitHub 上獲得: https://github.com/tgs/nptime
為了完整起見,這里是使用arrow
的方法(Python 的更好的日期和時間):
sometime = arrow.now()
abitlater = sometime.shift(seconds=3)
在現實世界的環境中,只使用time
從來都不是一個好主意,總是使用datetime
,甚至更好utc
,以避免像隔夜、夏令時、用戶和服務器之間的不同時區等沖突。
所以我推薦這種方法:
import datetime as dt
_now = dt.datetime.now() # or dt.datetime.now(dt.timezone.utc)
_in_5_sec = _now + dt.timedelta(seconds=5)
# get '14:39:57':
_in_5_sec.strftime('%H:%M:%S')
如果您還沒有 timedelta object,另一種可能性是只使用舊時間的屬性初始化一個新時間 object 並在需要的地方添加值:
new_time:time = time(
hour=curr_time.hour + n_hours,
minute=curr_time.minute + n_minutes,
seconds=curr_time.second + n_seconds
)
不可否認,這只有在您對您的值做出一些假設時才有效,因為這里沒有處理溢出。 但我只是認為值得記住這一點,因為它可以節省一兩行
嘗試將datetime.datetime
添加到datetime.timedelta
。 如果你只想要時間部分,你可以在結果datetime.datetime
object 上調用time()
方法來獲取它。
老問題,但我想我會拋出一個 function 來處理時區。 關鍵部分是將datetime.time
對象的tzinfo
屬性傳遞給 combine,然后在生成的虛擬日期時間上使用timetz()
而不是time()
。 該答案部分受到此處其他答案的啟發。
def add_timedelta_to_time(t, td):
"""Add a timedelta object to a time object using a dummy datetime.
:param t: datetime.time object.
:param td: datetime.timedelta object.
:returns: datetime.time object, representing the result of t + td.
NOTE: Using a gigantic td may result in an overflow. You've been
warned.
"""
# Create a dummy date object.
dummy_date = date(year=100, month=1, day=1)
# Combine the dummy date with the given time.
dummy_datetime = datetime.combine(date=dummy_date, time=t, tzinfo=t.tzinfo)
# Add the timedelta to the dummy datetime.
new_datetime = dummy_datetime + td
# Return the resulting time, including timezone information.
return new_datetime.timetz()
這是一個非常簡單的測試用例 class(使用內置的unittest
):
import unittest
from datetime import datetime, timezone, timedelta, time
class AddTimedeltaToTimeTestCase(unittest.TestCase):
"""Test add_timedelta_to_time."""
def test_wraps(self):
t = time(hour=23, minute=59)
td = timedelta(minutes=2)
t_expected = time(hour=0, minute=1)
t_actual = add_timedelta_to_time(t=t, td=td)
self.assertEqual(t_expected, t_actual)
def test_tz(self):
t = time(hour=4, minute=16, tzinfo=timezone.utc)
td = timedelta(hours=10, minutes=4)
t_expected = time(hour=14, minute=20, tzinfo=timezone.utc)
t_actual = add_timedelta_to_time(t=t, td=td)
self.assertEqual(t_expected, t_actual)
if __name__ == '__main__':
unittest.main()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.