it-swarm.com.de

Wie fügt man in Python standardmäßig N Sekunden zu datetime.time hinzu?

Angenommen datetime.time In Python gibt es eine Standardmethode zum Hinzufügen einer Ganzzahl von Sekunden, sodass 11:34:59 + 3 = 11:35:02, beispielsweise?

Diese offensichtlichen Ideen funktionieren nicht:

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

Am Ende habe ich Funktionen wie diese geschrieben:

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)

Ich kann nicht anders, als zu glauben, dass mir ein einfacherer Weg fehlt, dies zu tun.

Verbunden

315
Paul Stephenson

Sie können mit datetime vollständige timedelta -Variablen verwenden, und indem Sie ein Dummy-Datum angeben und dann time verwenden, um nur den Zeitwert abzurufen.

Zum Beispiel:

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

ergibt die zwei Werte im Abstand von drei Sekunden:

11:34:59
11:35:02

Sie können sich auch für die besser lesbare Version entscheiden

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

wenn du so geneigt bist.


Wenn Sie nach einer Funktion suchen, die dies ermöglicht, können Sie mit addSecs nachsehen:

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

Dies gibt aus:

 09:11:55.775695
 09:16:55
445
paxdiablo

Wie andere hier bereits ausgeführt haben, können Sie nur ganze Datetime-Objekte verwenden:

sometime = get_some_time() # the time to which you want to add 3 seconds
later = (datetime.combine(date.today(), sometime) + timedelta(seconds=3)).time()

Ich denke jedoch, dass es sich lohnt zu erklären, warum Objekte mit vollständiger Datumsangabe erforderlich sind. Überlegen Sie, was passieren würde, wenn ich 2 Stunden bis 23 Uhr hinzufügen würde. Was ist das richtige Verhalten? Eine Ausnahme, weil Sie keine Zeit größer als 23:59 Uhr haben können? Sollte es sich zurückziehen?

Verschiedene Programmierer werden unterschiedliche Dinge erwarten, so dass das Ergebnis, das sie ausgewählt haben, viele Leute überraschen wird. Schlimmer noch, Programmierer schrieben Code, der beim ersten Testen einwandfrei funktionierte, und brachen ihn später, indem sie etwas Unerwartetes taten. Dies ist sehr schlecht, weshalb Sie Timedelta-Objekte nicht zu Zeitobjekten hinzufügen dürfen.

45
Eli Courtwright

Eine Kleinigkeit, könnte Klarheit hinzufügen, um den Standardwert für Sekunden zu überschreiben

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

Vielen Dank an @Pax Diablo, @bvmou und @Arachnid für den Vorschlag, die gesamten Datenzeiten zu verwenden. Wenn ich datetime.time-Objekte von einer externen Quelle akzeptieren muss, scheint dies eine alternative add_secs_to_time() -Funktion zu sein:

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

Dieser ausführliche Code kann auf diesen Einzeiler komprimiert werden:

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

aber ich denke, ich würde das sowieso in eine Funktion für Code-Klarheit einschließen wollen.

11
Paul Stephenson

Wenn es sich lohnt, Ihrem Projekt eine weitere Datei/Abhängigkeit hinzuzufügen, habe ich gerade eine kleine Klasse geschrieben, die datetime.time mit der Fähigkeit zu rechnen. Wenn Sie nach Mitternacht gehen, wird es um Null gewickelt. In "Wie spät ist es in 24 Stunden?" Gibt es viele Eckfälle, einschließlich Sommerzeit, Schaltsekunden, Änderungen der historischen Zeitzone und so weiter. Aber manchmal braucht man wirklich den einfachen Fall, und das ist es, was dies tun wird.

Ihr Beispiel wäre geschrieben:

>>> import datetime
>>> import nptime
>>> nptime.nptime(11, 34, 59) + datetime.timedelta(0, 3)
nptime(11, 35, 2)

nptime erbt von datetime.time, daher sollte auch jede dieser Methoden verwendbar sein.

Es ist von PyPi als nptime ("nicht pedantische Zeit") oder auf GitHub verfügbar: https://github.com/tgs/nptime

8
rescdsk

Sie können nicht einfach eine Zahl zu datetime hinzufügen, da unklar ist, welche Einheit verwendet wird: Sekunden, Stunden, Wochen ...

Es gibt die Klasse timedelta für Manipulationen mit Datum und Uhrzeit. datetime minus datetime ergibt timedelta, datetime plus timedelta ergibt datetime, zwei datetime Objekte kann nicht hinzugefügt werden, obwohl zwei timedelta können.

Erstelle timedelta Objekt in wie vielen Sekunden du es hinzufügen willst und füge es zu datetime Objekt hinzu:

>>> from datetime import datetime, timedelta
>>> t = datetime.now() + timedelta(seconds=3000)
>>> print(t)
datetime.datetime(2018, 1, 17, 21, 47, 13, 90244)

In C++ gibt es dasselbe Konzept: std::chrono::duration.

5
user2387567

Der Vollständigkeit halber, hier ist der Weg, um es mit arrow (bessere Daten und Zeiten für Python) zu tun:

sometime = arrow.now()
abitlater = sometime.shift(seconds=3)
3
Bart Van Loon

Versuchen Sie, einen datetime.datetime Zu einem datetime.timedelta Hinzuzufügen. Wenn Sie nur den Zeitabschnitt benötigen, können Sie die Methode time() für das resultierende Objekt datetime.datetime Aufrufen, um ihn abzurufen.

1
Nick Johnson

Alte Frage, aber ich dachte, ich würde eine Funktion einbauen, die Zeitzonen behandelt. Die Schlüsselteile übergeben das tzinfo-Attribut des datetime.time - Objekts in die Kombination und verwenden dann timetz() anstelle von time() für die resultierende Dummy-Datetime. Diese Antwort ist teilweise von den anderen Antworten hier inspiriert.

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

Und hier ist eine wirklich einfache Testfallklasse (mit eingebautem 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 __== '__main__':
    unittest.main()
0
blthayer