Python'da datetime.time öğesine N saniye eklemenin standart yolu nedir?


369

datetime.timePython'da bir değer verildiğinde , buna tamsayı saniye eklemenin standart bir yolu var mı, örneğin 11:34:59+ 3 = 11:35:02?

Bu bariz fikirler işe yaramıyor:

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

Sonunda böyle fonksiyonlar yazdım:

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)

Yine de bunu yapmanın daha kolay bir yolunu kaçırdığımı düşünemiyorum.

İlişkili


Yanıtlar:


499

Tam datetimedeğişkenleri ile timedeltakukla bir tarih girerek ve sonra timesadece zaman değerini almak için kullanabilirsiniz.

Örneğin:

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

üç saniye arayla iki değerle sonuçlanır:

11:34:59
11:35:02

Daha okunabilir olanı da tercih edebilirsiniz

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

eğer bu kadar eğimliyseniz.


Bunu yapabilen bir işlevin peşindeyseniz, addSecsaşağıdakileri kullanarak inceleyebilirsiniz:

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)

Bu çıktılar:

 09:11:55.775695
 09:16:55

6
OverflowErrors önlemek için, farklı bir kukla tarih kullanmanızı tavsiye ederim, örneğin birkaç yıl sonra: datetime (101,1,1,11,34,59). Yukarıdaki tarihten büyük bir zaman çizelgesi çıkarmayı denerseniz, datetime nesnesinin yılı 1'den küçük olamayacağı için "OverflowError: tarih değeri aralık dışı" hatası
alırsınız

2
@ pheelicks, biraz geç olsa da, tam olarak çevik yanıt süreleri de olsa :-) Kodumdaki başka bir hatayı düzeltmem gerektiğinden, aynı zamanda önerinizi de dahil edeceğimi düşündüm.
paxdiablo

53

Buradaki diğerlerinin de belirttiği gibi, sadece tam datetime nesnelerini kullanabilirsiniz:

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

Ancak, tam datetime nesnelerinin neden gerekli olduğunu açıklamaya değer olduğunu düşünüyorum. 23: 00'e 2 saat eklersem ne olacağını düşünün. Doğru davranış nedir? İstisna, çünkü 23: 59'dan daha büyük bir zamanınız olamaz mı? Geri mi dönmeli?

Farklı programcılar farklı şeyler bekler, bu yüzden hangi sonucu seçtiyse birçok insanı şaşırtacaktır. Daha da kötüsü, programcılar başlangıçta test ettiklerinde iyi çalışan bir kod yazacaklar ve daha sonra beklenmedik bir şey yaparak daha sonra kırılmalarını sağlayacaklardı. Bu çok kötü, bu yüzden zaman nesnelerine zamana dayalı nesneler eklemenize izin verilmiyor.


22

Küçük bir şey, varsayılan değeri saniyeler boyunca geçersiz kılmak için netlik ekleyebilir

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

4
Bunu beğendim. Belirtilen argüman ile güzel ve net.
Vigrond

12

@Pax Diablo, @bvmou ve @Arachnid'e, tam dattime kullanma önerisi için teşekkürler. Harici bir kaynaktan datetime.time nesnelerini kabul etmek zorunda kalırsam, bu alternatif bir add_secs_to_time()işlev gibi görünüyor :

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

Bu ayrıntılı kod, bu tek astarla sıkıştırılabilir:

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

ama yine de kod netliği için bir işlevde bunu sarmak istiyorum düşünüyorum.


Teşekkürler - harika fikir
Anupam

9

Projenize başka bir dosya / bağımlılık eklemeye değerse datetime.time, aritmetik yapabilme yeteneğiyle genişleyen küçük bir sınıf yazdım . Gece yarısı geçtiğinizde, sıfıra dolanıyor. Şimdi, "Saat kaçta olacak, 24 saat sonra" gün ışığından yararlanma saati, artık saniye, tarihsel saat dilimi değişiklikleri vb. Ama bazen gerçekten basit bir duruma ihtiyacınız vardır ve bu da bunu yapar.

Örneğiniz şöyle yazılır:

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

nptimemiras alır datetime.time, bu nedenle bu yöntemlerden herhangi biri de kullanılabilir olmalıdır.

PyPi'den nptime("bilgiçlik dışı zaman") veya GitHub'da kullanılabilir: https://github.com/tgs/nptime


6

datetimeHangi birimin kullanıldığının belirsiz olduğu için sayı ekleyemezsiniz : saniye, saat, hafta ...

timedeltaTarih ve saat içeren manipülasyonlar için bir sınıf var . datetimeeksi datetimeverir timedelta, datetimeartı timedeltaverir datetime, iki datetimenesne eklenebilse de iki nesne eklenemez timedelta.

timedeltaKaç saniye eklemek istediğiniz nesneyi oluşturun ve nesneye ekleyin datetime:

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

C ++ aynı kavram yoktur: std::chrono::duration.


4
lütfen DAİMA açıklamalar ekleyin, yeni gelenlerin burada ne yaptığınıza dair bir ipucu olmayabilir.
Gerhard Barnard

3

Tamlık uğruna, bunu yapmanın yolu arrow(Python için daha iyi tarihler ve saatler):

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

1

Bir eklemeyi deneyin datetime.datetimea datetime.timedelta. Yalnızca saat bölümünü istiyorsanız, elde time()edilen datetime.datetimenesneyi almak için yöntemi çağırabilirsiniz .


0

Eski soru, ama zaman dilimlerini işleyen bir işlev atacağımı düşündüm. Anahtar parçalar, datetime.timenesnenin tzinfoözniteliğini birleştirmeye geçirir ve sonra ortaya çıkan kukla tarih timetz()yerine kullanmaktan geçer time(). Bu cevap kısmen buradaki diğer cevaplardan esinlenmiştir.

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

Ve işte gerçekten basit bir test senaryosu sınıfı (yerleşik kullanarak 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()
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.