PythonでN秒をdatetime.timeに追加する標準的な方法は何ですか?


369

datetime.timePythonで値が与えられた場合、整数の秒数を追加する標準的な方法があるので、たとえば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)

しかし、これを行う簡単な方法がないと思わずにはいられません。

関連した


関連するPythonの問題:「+」と「-」のdatetime.timeサポート
jfs

回答:


499

で完全な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())

3秒間隔の2つの値になります。

11:34:59
11:35:02

より読みやすくすることもできます

b = a + datetime.timedelta(seconds=3)

あなたがそんなに傾いているなら


これを実行できる関数を探している場合は、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

6
OverflowErrorsを回避するには、たとえば2年後の別のダミー日付を使用することをお勧めします:datetime(101,1,1,11,34,59)。上記の日付から大きなtimedeltaを減算しようとすると、日時オブジェクトの年は1より小さくできないため、「OverflowError:date value out of range」エラーが発生します
pheelicks

2
@pheelicks、完了、少し遅れますが、正確なアジャイル応答時間ではありません:-)私はコードの別のバグを修正する必要があったので、私は同時にあなたの提案を組み込むと思いました。
paxdiablo 2013年

53

ここで他の人が述べたように、全体を通して完全な日時オブジェクトを使用できます:

from datetime import datetime, date, time, timedelta
sometime = time(8,00) # 8am
later = (datetime.combine(date.today(), sometime) + timedelta(seconds=3)).time()

ただし、完全な日時オブジェクトが必要な理由を説明する価値があると思います。午後2時に2時間追加するとどうなるか考えてみてください。正しい動作は何ですか?例外ですが、午後11時59分を超える時間を設定することはできません。折り返す必要がありますか?

プログラマーが異なれば期待することも異なるため、選択した結果が多くの人を驚かせるでしょう。さらに悪いことに、プログラマーは最初にテストしたときに問題なく動作するコードを記述し、その後、予期しない何かを行うことによってそれを中断させます。これは非常に悪いことです。そのため、timedeltaオブジェクトをtimeオブジェクトに追加することはできません。


22

1つの小さなことは、秒のデフォルト値をオーバーライドするために明快さを追加するかもしれません

>>> b = a + datetime.timedelta(seconds=3000)
>>> b
datetime.datetime(1, 1, 1, 12, 24, 59)

4
私はこれが好きです。指定された引数を使用すると、わかりやすく明確です。
Vigrond 2014

12

全体で完全な日時を使用することを提案してくれた@Pax Diablo、@ bvmou、および@Arachnidに感謝します。外部ソースからdatetime.timeオブジェクトを受け入れる必要がある場合、これは代替add_secs_to_time()関数のようです:

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()

この冗長なコードは、次の1行に圧縮できます。

(datetime.datetime.combine(datetime.date(1, 1, 1), timeval) + datetime.timedelta(seconds=secs_to_add)).time()

とにかく、コードを明確にするために、それを関数にまとめたいと思います。


ありがとう-素晴らしいアイデア
Anupam

9

プロジェクトに別のファイル/依存関係を追加する価値がある場合datetime.timeは、算術演算機能を拡張する小さな小さなクラスを作成しました。真夜中を過ぎると、ラップはゼロになります。現在、「何時ですか、24時間後」には、夏時間、うるう秒、過去のタイムゾーンの変更など、多くのコーナーケースがあります。しかし、単純なケースが本当に必要な場合もあります。

あなたの例は次のようになります:

>>> 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


6

datetime使用されている単位が明確でないため、単純に数値を追加することはできません:秒、時間、週...

timedelta日付と時刻を操作するためのクラスがあります。datetimeマイナスdatetimeを与えるtimedeltadatetimeプラスtimedeltaを与えるdatetime、2つのdatetimeオブジェクトは追加できますが、2 つtimedeltaは追加できません。

timedelta追加する秒数を指定してオブジェクトを作成し、オブジェクトに追加しdatetimeます。

>>> 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


4
常に説明を追加してください。新規参入者はあなたがここで何をしているかわかりません。
ゲルハルトバーナード

3

完全を期すために、これを使用する方法を次にarrow示します(Pythonのより良い日付と時刻)。

sometime = arrow.now()
abitlater = sometime.shift(seconds=3)

1

をに追加しdatetime.datetimeてみてくださいdatetime.timedelta。時間部分だけが必要な場合time()は、結果のdatetime.datetimeオブジェクトでメソッドを呼び出して取得できます。


0

古い質問ですが、タイムゾーンを処理する関数を投入すると思いました。重要な部分は、datetime.timeオブジェクトのtzinfo属性を結合に渡し、結果のダミーの日時では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()

そして、これは本当に組み込みのテストケースクラスです(組み込みを使用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()
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.