Python'da çeşitli tarihler oluşturma


374

Örneğin, 100 gün içinde, bugünden başlayıp gelişigüzel sayıda güne gitmek için bir tarih listesi oluşturmak istiyorum. Bunu yapmanın daha iyi bir yolu var mı?

import datetime

a = datetime.datetime.today()
numdays = 100
dateList = []
for x in range (0, numdays):
    dateList.append(a - datetime.timedelta(days = x))
print dateList

Yanıtlar:


459

Marjinal olarak daha iyi ...

base = datetime.datetime.today()
date_list = [base - datetime.timedelta(days=x) for x in range(numdays)]

6
Bu, saat dilimi farkında tarihler kullanırsanız ve DST kayması varsa çalışmaz !!! Yani, bir başlangıç ​​ve bitiş tarihi kullandığınızda ve bu şekilde
doldurduğunuzda

@ s-lott range(0, numdays)bu durumda kullanamaz mıydınız ?
Lukas Juhrich

3
On, 5 dakikalık aralıklar, +/- bir değer (benim durumumda 30 saniye) oluşturmak için bu yöntemi biraz farklı bir şekilde kullandım. Sadece paylaşacağımı düşündüm: datetimes = [start + timedelta(seconds=x*60+randint(-30, 30)) for x in range (0, range_end*5, 5)]burada değişkenrange_end = 10
MikeyE

247

Pandas genel olarak zaman serileri için mükemmeldir ve tarih aralıkları için doğrudan desteğe sahiptir.

Örneğin pd.date_range():

import pandas as pd
from datetime import datetime

datelist = pd.date_range(datetime.today(), periods=100).tolist()

Ayrıca hayatı kolaylaştırmak için birçok seçeneğe sahiptir. Örneğin, yalnızca hafta içi günler istiyorsanız, sadecebdate_range .

Tarih aralığı belgelerine bakın

Buna ek olarak, pytz zaman dilimlerini tamamen destekler ve ilkbahar / sonbahar DST vardiyalarını sorunsuz bir şekilde kaplayabilir.

OP ile DÜZENLE:

Panda zaman damgalarının aksine, gerçek python tarihlerine ihtiyacınız varsa:

import pandas as pd
from datetime import datetime

pd.date_range(end = datetime.today(), periods = 100).to_pydatetime().tolist()

#OR

pd.date_range(start="2018-09-09",end="2020-02-02")

Bu, orijinal soruyla eşleşmek için "son" parametresini kullanır, ancak azalan tarihler istiyorsanız:

pd.date_range(datetime.today(), periods=100).to_pydatetime().tolist()

22
Pandalar zaten kullanılıyorsa en iyi cevabı kesin. Ekleyeceğim tek şey, tarihleriniz orijinal gönderiye göre geriye giderse end = parametresini kullanmanızdır. pd.date_range (end = pd.datetime.today (), nokta = 100) .tolist ()
Thomas Browne

5
Bu yöntemlerle ilgili bir sorun, Python Datetime türüne ihtiyacınız olduğunda ... Pandalar veya numpy tarih aralığı yöntemlerini kullanmak Zaman Damgası ve Datetime64 türlerini oluşturacaktır ... list(map(pd.Timestamp.to_pydatetime, datelist))datetime türünü geri almanız gerekir ...
Malik Koné

pandas.datetimeSınıf kaldırılan ve ilerideki bir sürümünde pandalar kaldırılacaktır. datetimeBunun yerine modülden içe aktarın .
Trenton McKinney

82

Belirtilen başlangıç ​​ve bitiş tarihleri ​​arasındaki tarih aralığını alın (Zaman ve alan karmaşıklığı için optimize edilmiştir):

import datetime

start = datetime.datetime.strptime("21-06-2014", "%d-%m-%Y")
end = datetime.datetime.strptime("07-07-2014", "%d-%m-%Y")
date_generated = [start + datetime.timedelta(days=x) for x in range(0, (end-start).days)]

for date in date_generated:
    print date.strftime("%d-%m-%Y")

6
İlk öneri, bir date_generator almak için [] yerine () kullanmaktır. Bu anlamda etkilidir, tüm tarih dizisini depolamaya ve yalnızca gerektiğinde bir tarih oluşturmaya gerek yoktur.
Sandeep

2
Bitiş_tarihi'nin oluşturulmadığını unutmayın.
Thorbjørn Ravn Andersen

8
bitiş tarihini almak için (bitiş-başlangıç ​​+ 1) tuşlarını kullanın.
Sandeep

6
OP'nin sorusuna cevap vermiyor, ama peşinde olduğum şey :)
Thierry J.

2
(end-start+1)çalışmıyorsa, bir timedelta ve int ekleyemezsiniz. (end-start).days + 1Yine de kullanabilirsiniz .
Stephen Paulger

44

Bugünden başlayarak tarih nesnelerini döndüren bir üreteç işlevi yazabilirsiniz:

import datetime

def date_generator():
  from_date = datetime.datetime.today()
  while True:
    yield from_date
    from_date = from_date - datetime.timedelta(days=1)

Bu jeneratör bugünden başlayarak ve her seferinde bir gün geriye gidecek tarihleri ​​döndürür. İlk 3 tarihi nasıl alacağınız aşağıda açıklanmıştır:

>>> import itertools
>>> dates = itertools.islice(date_generator(), 3)
>>> list(dates)
[datetime.datetime(2009, 6, 14, 19, 12, 21, 703890), datetime.datetime(2009, 6, 13, 19, 12, 21, 703890), datetime.datetime(2009, 6, 12, 19, 12, 21, 703890)]

Bu yaklaşımın bir döngü veya liste kavrayışı üzerindeki avantajı, istediğiniz kadar geri gidebilmenizdir.

Düzenle

İşlev yerine jeneratör ifadesi kullanan daha kompakt bir sürüm:

date_generator = (datetime.datetime.today() - datetime.timedelta(days=i) for i in itertools.count())

Kullanımı:

>>> dates = itertools.islice(date_generator, 3)
>>> list(dates)
[datetime.datetime(2009, 6, 15, 1, 32, 37, 286765), datetime.datetime(2009, 6, 14, 1, 32, 37, 286836), datetime.datetime(2009, 6, 13, 1, 32, 37, 286859)]

1
Jeneratörler, gün sayısı keyfi ise, bunu yapmanın ideal yoludur.
xssChauhan

32

evet, tekerleği yeniden icat .... sadece forumda arama ve böyle bir şey alırsınız:

from dateutil import rrule
from datetime import datetime

list(rrule.rrule(rrule.DAILY,count=100,dtstart=datetime.now()))

22
Labix.org/python-dateutil gerektirir . Güzel görünüyor ama sadece bir satır kurtarmak için dış bağımlılığa pek değer yok.
Beni Cherniavsky-Paskin

1
Kimse diğer cevaplar çok pitonik şeyler inanamıyorum. Kural korkunç bir isim olsa da, bu en azından gözler için kolaydır.
boatcoder

7
@ BeniCherniavsky-Paskin: Dönem (takvim) aritmetiği uygularken ince hataları tanıtmak çok kolaydır. iCalendar RFCdateutil.rrule uygular - çok az farklı olan hemen hemen aynı işlevselliğe sahip birden çok uygulama yerine, iyi tanımlanmış bir davranışa sahip işlevleri kullanmak daha kolaydır. hata düzeltmeyi tek bir yerde sınırlamanızı sağlar. dateutil.rrule
jfs

3
@ Mark0978: rruleisim rastgele değil; o dan gelen rfc
jfs

1
Evet, talihsiz isim seçimi için dateutil'i suçlamıyordum :-)
boatcoder

32

Gün sırasını daha basit hale getirmek için de kullanabilirsiniz:

def date_range(start_date, end_date):
    for ordinal in range(start_date.toordinal(), end_date.toordinal()):
        yield datetime.date.fromordinal(ordinal)

Veya yorumlarda önerildiği gibi aşağıdaki gibi bir liste oluşturabilirsiniz:

date_range = [
    datetime.date.fromordinal(ordinal) 
    for ordinal in range(
        start_date.toordinal(),
        end_date.toordinal(),
    )
]

18

Bu sorunun başlığından böyle bir şey bulmayı bekliyordum range() iki tarih belirtmeme ve aradaki tüm tarihleri ​​içeren bir liste oluşturmamı sağlayacak bir . Bu şekilde, önceden bilmiyorsa, bu iki tarih arasındaki gün sayısını hesaplamak gerekmez.

Bu yüzden biraz konu dışı olma riskiyle, bu tek astar işi yapar:

import datetime
start_date = datetime.date(2011, 01, 01)
end_date   = datetime.date(2014, 01, 01)

dates_2011_2013 = [ start_date + datetime.timedelta(n) for n in range(int ((end_date - start_date).days))]

Bu cevaba verilen tüm krediler !


1
Bu, soruya verilen diğer cevapların çoğundan daha fazla bir astar değildir.
Thomas Browne

4
Bunun diğerlerinin cevaplarından çok daha fazla tek katmanlı olduğunu iddia etmedim, ne de daha iyi bir çözüm değildi. İstediğinizden biraz farklı bir şey yapan bir kod parçası gösterdim, ancak sorunun başlığı göz önüne alındığında burada bulmaktan memnuniyet duyarım.
snake_charmer

11

İşte S.Lott'un iki tarih startve arasındaki tarihlerin listesini veren cevabını oluşturan biraz farklı bir cevap end. Aşağıdaki örnekte, 2017'nin başından bugüne.

start = datetime.datetime(2017,1,1)
end = datetime.datetime.today()
daterange = [start + datetime.timedelta(days=x) for x in range(0, (end-start).days)]

7

Biraz geç cevap biliyorum, ama aynı problemi yaşadım ve Python'un iç menzil işlevinin bu açıdan biraz eksik olduğuna karar verdim, bu yüzden onu bir util modülünde geçersiz kıldım.

from __builtin__ import range as _range
from datetime import datetime, timedelta

def range(*args):
    if len(args) != 3:
        return _range(*args)
    start, stop, step = args
    if start < stop:
        cmp = lambda a, b: a < b
        inc = lambda a: a + step
    else:
        cmp = lambda a, b: a > b
        inc = lambda a: a - step
    output = [start]
    while cmp(start, stop):
        start = inc(start)
        output.append(start)

    return output

print range(datetime(2011, 5, 1), datetime(2011, 10, 1), timedelta(days=30))

1
Bence istiyorsun output = []ve while cmp(...)döngüdeki çizgileri değiştirmek . Karşılaştır range(0,10,1)ve _range(0,10,1).
sigfpe

3
Eğer fonksiyonu isimlendirirseniz bu cevabın daha iyi olacağını düşünüyorum date_range.
Brandon Bradley

7

Kendim için yazdığım cevaplara dayanarak:

import datetime;
print [(datetime.date.today() - datetime.timedelta(days=x)).strftime('%Y-%m-%d') for x in range(-5, 0)]

Çıktı:

['2017-12-11', '2017-12-10', '2017-12-09', '2017-12-08', '2017-12-07']

Aradaki fark, ' date' nesnesini değil, ' datetime.datetime' nesnesini elde etmem .


7

İki tarih varsa ve aralığa ihtiyacınız varsa

from dateutil import rrule, parser
date1 = '1995-01-01'
date2 = '1995-02-28'
datesx = list(rrule.rrule(rrule.DAILY, dtstart=parser.parse(date1), until=parser.parse(date2)))

5

İşte kendi kodumdan oluşturduğum öz, bu yardımcı olabilir. (Sorunun çok eski olduğunu biliyorum, ancak diğerleri bunu kullanabilir)

https://gist.github.com/2287345

(aynı şey aşağıda)

import datetime
from time import mktime

def convert_date_to_datetime(date_object):
    date_tuple = date_object.timetuple()
    date_timestamp = mktime(date_tuple)
    return datetime.datetime.fromtimestamp(date_timestamp)

def date_range(how_many=7):
    for x in range(0, how_many):
        some_date = datetime.datetime.today() - datetime.timedelta(days=x)
        some_datetime = convert_date_to_datetime(some_date.date())
        yield some_datetime

def pick_two_dates(how_many=7):
    a = b = convert_date_to_datetime(datetime.datetime.now().date())
    for each_date in date_range(how_many):
        b = a
        a = each_date
        if a == b:
            continue
        yield b, a

4

İşte bash scriptleri için hafta içi bir liste almak için bir liner, bu python 3.

python -c "import sys,datetime; print('\n'.join([(datetime.datetime.today() - datetime.timedelta(days=x)).strftime(\"%Y/%m/%d\") for x in range(0,int(sys.argv[1])) if (datetime.datetime.today() - datetime.timedelta(days=x)).isoweekday()<6]))" 10

Başlangıç ​​(veya daha doğrusu bitiş) tarihi sağlamak için bir varyant

python -c "import sys,datetime; print('\n'.join([(datetime.datetime.strptime(sys.argv[1],\"%Y/%m/%d\") - datetime.timedelta(days=x)).strftime(\"%Y/%m/%d \") for x in range(0,int(sys.argv[2])) if (datetime.datetime.today() - datetime.timedelta(days=x)).isoweekday()<6]))" 2015/12/30 10

İşte keyfi başlangıç ​​ve bitiş tarihleri ​​için bir değişken. Bu son derece verimli değil, ama bir bash betiğinde for for döngüsü koymak için iyi değil:

python -c "import sys,datetime; print('\n'.join([(datetime.datetime.strptime(sys.argv[1],\"%Y/%m/%d\") + datetime.timedelta(days=x)).strftime(\"%Y/%m/%d\") for x in range(0,int((datetime.datetime.strptime(sys.argv[2], \"%Y/%m/%d\") - datetime.datetime.strptime(sys.argv[1], \"%Y/%m/%d\")).days)) if (datetime.datetime.strptime(sys.argv[1], \"%Y/%m/%d\") + datetime.timedelta(days=x)).isoweekday()<6]))" 2015/12/15 2015/12/30

Yanıt postanızı yorumunuzdaki kodla güncellemek isteyebilirsiniz. Python yorumlarda karıştırılıyor ve biçimlendirmeye ihtiyacı var.
Jake Bathman

3

Matplotlib ile ilgili

from matplotlib.dates import drange
import datetime

base = datetime.date.today()
end  = base + datetime.timedelta(days=100)
delta = datetime.timedelta(days=1)
l = drange(base, end, delta)

3

Bunun cevaplandığını biliyorum, ama tarihsel amaçlar için cevabımı bırakacağım ve bence bu doğru.

import numpy as np
import datetime as dt
listOfDates=[date for date in np.arange(firstDate,lastDate,dt.timedelta(days=x))]

Tabii kod golf gibi bir şey kazanmayacak, ama bence zarif.


arangeAdımlarla oldukça güzel, ama listOfDatesoluşur numpy datetime64 yerine piton yerli tarihsaat arasında.
F.Raab

2
Ancak numpy datetime64 yerine yerel python datetime döndürmek np.arange(…).astype(dt.datetime)için kullanabilirsiniz arange.
F.Raab

2

Sandeep'in cevabından başlayarak ileri veya geri sayan başka bir örnek.

from datetime import date, datetime, timedelta
from typing import Sequence
def range_of_dates(start_of_range: date, end_of_range: date) -> Sequence[date]:

    if start_of_range <= end_of_range:
        return [
            start_of_range + timedelta(days=x)
            for x in range(0, (end_of_range - start_of_range).days + 1)
        ]
    return [
        start_of_range - timedelta(days=x)
        for x in range(0, (start_of_range - end_of_range).days + 1)
    ]

start_of_range = datetime.today().date()
end_of_range = start_of_range + timedelta(days=3)
date_range = range_of_dates(start_of_range, end_of_range)
print(date_range)

verir

[datetime.date(2019, 12, 20), datetime.date(2019, 12, 21), datetime.date(2019, 12, 22), datetime.date(2019, 12, 23)]

ve

start_of_range = datetime.today().date()
end_of_range = start_of_range - timedelta(days=3)
date_range = range_of_dates(start_of_range, end_of_range)
print(date_range)

verir

[datetime.date(2019, 12, 20), datetime.date(2019, 12, 19), datetime.date(2019, 12, 18), datetime.date(2019, 12, 17)]

Başlangıç ​​tarihinin geri dönüşe dahil olduğunu unutmayın, bu nedenle toplam dört tarih istiyorsanız şunu kullanın: timedelta(days=3)


1
from datetime import datetime, timedelta
from dateutil import parser
def getDateRange(begin, end):
    """  """
    beginDate = parser.parse(begin)
    endDate =  parser.parse(end)
    delta = endDate-beginDate
    numdays = delta.days + 1
    dayList = [datetime.strftime(beginDate + timedelta(days=x), '%Y%m%d') for x in range(0, numdays)]
    return dayList

1

İle aylık tarih aralığı jeneratör datetimeve dateutil. Basit ve anlaşılması kolay:

import datetime as dt
from dateutil.relativedelta import relativedelta

def month_range(start_date, n_months):
        for m in range(n_months):
            yield start_date + relativedelta(months=+m)

0
import datetime    
def date_generator():
    cur = base = datetime.date.today()
    end  = base + datetime.timedelta(days=100)
    delta = datetime.timedelta(days=1)
    while(end>base):
        base = base+delta
        print base

date_generator()

1
Yani O .. değil ileriye, geriye gitmek istedi endolmalıdır base - datetime.timedelta. Üstelik ... Bu çözüm neden orijinal çözümden daha iyi?
frarugi87

0

Yukarıdaki cevaplardan tarih üreticisi için bu örneği oluşturdum

import datetime
date = datetime.datetime.now()
time = date.time()
def date_generator(date, delta):
  counter =0
  date = date - datetime.timedelta(days=delta)
  while counter <= delta:
    yield date
    date = date + datetime.timedelta(days=1)
    counter +=1

for date in date_generator(date, 30):
   if date.date() != datetime.datetime.now().date():
     start_date = datetime.datetime.combine(date, datetime.time())
     end_date = datetime.datetime.combine(date, datetime.time.max)
   else:
     start_date = datetime.datetime.combine(date, datetime.time())
     end_date = datetime.datetime.combine(date, time)
   print('start_date---->',start_date,'end_date---->',end_date)
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.