การสร้างช่วงของวันที่ใน Python


373

ฉันต้องการสร้างรายการวันที่เริ่มต้นวันนี้และย้อนกลับไปตามจำนวนวันโดยพลการในตัวอย่างของฉัน 100 วัน มีวิธีที่ดีกว่าที่จะทำมากกว่านี้?

import datetime

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

คำตอบ:


458

ดีขึ้นเล็กน้อย ...

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

6
สิ่งนี้ไม่ทำงานหากคุณใช้ชุดข้อมูลที่ทราบเขตเวลาและมีการเปลี่ยน DST !!! ฉันหมายความว่าเมื่อคุณใช้เริ่มต้นและสิ้นสุดวันที่และเติมขึ้นมาในระหว่างทางนี้ ...
gabn88

@ s-lott คุณไม่สามารถใช้range(0, numdays)ในกรณีนี้ได้ใช่ไหม
Lukas Juhrich

3
ฉันใช้วิธีนี้ในวิธีที่แตกต่างกันเล็กน้อยเพื่อสร้างช่วงเวลาสิบ, 5 นาที, +/- ค่าบางค่า (30 วินาทีในกรณีของฉัน) ฉันเพิ่งคิดว่าฉันจะแบ่งปัน: datetimes = [start + timedelta(seconds=x*60+randint(-30, 30)) for x in range (0, range_end*5, 5)]ที่ตัวแปรrange_end = 10
MikeyE

246

Pandas เหมาะอย่างยิ่งสำหรับอนุกรมเวลาโดยทั่วไปและได้รับการสนับสนุนโดยตรงสำหรับช่วงวันที่

ตัวอย่างเช่นpd.date_range():

import pandas as pd
from datetime import datetime

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

นอกจากนี้ยังมีตัวเลือกมากมายที่จะทำให้ชีวิตง่ายขึ้น bdate_rangeตัวอย่างเช่นถ้าคุณต้องการวันธรรมดาเท่านั้นคุณก็จะแลกเปลี่ยนใน

ดูเอกสารช่วงวันที่

นอกจากนี้ยังรองรับเขตเวลาแบบ Pytz อย่างเต็มที่และสามารถยืดเวลาการเลื่อน DST ของสปริง / ฤดูใบไม้ร่วงได้อย่างราบรื่น

แก้ไขโดย OP:

หากคุณต้องการชุดข้อมูลหลามจริง ๆ ซึ่งตรงข้ามกับเวลาประทับของ Pandas:

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

สิ่งนี้ใช้พารามิเตอร์ "สิ้นสุด" เพื่อจับคู่คำถามต้นฉบับ แต่ถ้าคุณต้องการวันที่จากมากไปน้อย:

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

22
กำหนดคำตอบที่ดีที่สุดหากมีการใช้แพนด้าอยู่แล้ว สิ่งเดียวที่ฉันจะเพิ่มคือคุณจะใช้พารามิเตอร์ end = หากวันที่ของคุณย้อนหลังตามโพสต์ดั้งเดิม pd.date_range (สิ้นสุด = pd.datetime.today (), ระยะเวลา = 100) .tolist ()
โทมัสบราวน์

5
หนึ่งปัญหาด้วยวิธีนี้คือเมื่อคุณจำเป็นต้องใช้ประเภทงูหลาม Datetime ... การใช้นุ่นหรือวิธีการช่วงวัน numpy จะสร้างการประทับเวลาและ Datetime64 ประเภท ... คุณต้องการlist(map(pd.Timestamp.to_pydatetime, datelist))ที่จะได้รับ datetime ชนิดกลับ ...
มาลิกKoné

pandas.datetimeชั้นจะเลิกและจะถูกลบออกจากหมีแพนด้าในรุ่นอนาคต นำเข้าจากdatetimeโมดูลแทน
Trenton McKinney

82

รับช่วงวันที่ระหว่างวันที่เริ่มต้นและวันที่สิ้นสุดที่ระบุ (ปรับให้เหมาะสมกับความซับซ้อนของเวลาและพื้นที่):

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
ข้อเสนอแนะเบื้องต้นคือการใช้ () แทน [] เพื่อรับ date_generator มีประสิทธิภาพในแง่ที่ไม่จำเป็นต้องเก็บอาร์เรย์ทั้งหมดของวันที่และสร้างหนึ่งเมื่อจำเป็นเท่านั้น
Sandeep

2
หมายเหตุ end_date ไม่ได้ถูกสร้างขึ้น
Thorbjørn Ravn Andersen

8
ใช้ (end-start + 1) เพื่อรับวันที่สิ้นสุด
Sandeep

6
ไม่ตอบคำถามของ OP แต่นั่นคือสิ่งที่ฉันเป็นหลังจาก :)
Thierry J.

2
(end-start+1)ไม่ทำงานคุณไม่สามารถเพิ่ม timedelta และ int ได้ คุณสามารถใช้(end-start).days + 1แม้ว่า
Stephen Paulger

44

คุณสามารถเขียนฟังก์ชันตัวสร้างที่ส่งคืนวัตถุวันที่เริ่มตั้งแต่วันนี้:

import datetime

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

เครื่องกำเนิดไฟฟ้านี้จะคืนวันที่เริ่มต้นจากวันนี้และย้อนกลับทีละวัน นี่คือวิธีการใช้ 3 วันแรก:

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

ข้อดีของวิธีนี้ในการวนซ้ำหรือความเข้าใจในรายการคือคุณสามารถย้อนกลับไปได้บ่อยเท่าที่ต้องการ

แก้ไข

รุ่นกะทัดรัดยิ่งขึ้นโดยใช้นิพจน์ตัวสร้างแทนฟังก์ชัน:

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

การใช้งาน:

>>> 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
เครื่องกำเนิดไฟฟ้าเป็นวิธีที่เหมาะสมที่สุดในการทำเช่นนี้หากจำนวนวันเป็นไปโดยพลการ
xssChauhan

32

ใช่สร้างนวัตกรรมใหม่ .... เพียงแค่ค้นหาฟอรัมและคุณจะได้รับสิ่งนี้:

from dateutil import rrule
from datetime import datetime

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

22
ต้องlabix.org/python-dateutil ดูดี แต่ไม่ค่อยคุ้มค่ากับการพึ่งพาจากภายนอกเพียงแค่บันทึกหนึ่งบรรทัด
Beni Cherniavsky-Paskin

1
ไม่สามารถเชื่อในสิ่งที่ทุกคนคำตอบอื่น ๆ เป็น pythonic มาก ในขณะที่กฎเป็นชื่อที่น่ากลัวคนนี้อย่างน้อยก็ง่ายในสายตา
boatcoder

7
@ BeniCherniavsky-Paskin: มันเป็นเรื่องง่ายมากที่จะแนะนำข้อบกพร่องที่ลึกซึ้งในขณะที่ใช้คณิตศาสตร์ (ปฏิทิน) เลขคณิต dateutil.rruleใช้iCalendar RFC - ง่ายต่อการใช้ฟังก์ชั่นที่มีพฤติกรรมที่กำหนดไว้อย่างดีแทนที่จะใช้หลาย ๆ การใช้งานของฟังก์ชั่นเดียวกันซึ่งแตกต่างกันเล็กน้อย dateutil.rruleอนุญาตให้ จำกัด การแก้ไขข้อผิดพลาดในที่เดียว
jfs

3
@ Mark0978: rruleชื่อไม่ได้เป็นแบบสุ่ม มันมาจากrfc ที่สอดคล้องกัน
jfs

1
ใช่ฉันไม่ได้ตำหนิ dateutil สำหรับตัวเลือกที่โชคร้ายของชื่อ :-)
boatcoder

32

คุณยังสามารถใช้ลำดับวันเพื่อทำให้ง่ายขึ้น:

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

หรือตามที่แนะนำในความคิดเห็นที่คุณสามารถสร้างรายการเช่นนี้:

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

18

จากชื่อของคำถามนี้ฉันคาดหวังว่าจะได้พบกับสิ่งที่ชอบ range()กันที่จะให้ฉันระบุสองวันและสร้างรายการที่มีวันที่ทั้งหมดในระหว่าง ด้วยวิธีนี้เราไม่จำเป็นต้องคำนวณจำนวนวันระหว่างวันที่สองวันนั้นหากไม่ทราบล่วงหน้า

ดังนั้นด้วยความเสี่ยงของการไม่ได้อยู่ที่หัวข้อเล็กน้อยหนึ่งบรรทัดนี้ทำงาน:

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

เครดิตทั้งหมดสำหรับคำตอบนี้ !


1
นั่นไม่ใช่หนึ่งซับมากกว่าคำตอบอื่น ๆ อีกมากมายสำหรับคำถาม
โธมัสบราวน์

4
ฉันไม่เคยแสร้งว่านี่เป็นคำตอบเดียวมากกว่าคำตอบอื่น ๆ และนั่นไม่ใช่วิธีแก้ปัญหาที่ดีกว่า ฉันพบรหัสชิ้นหนึ่งที่ทำสิ่งที่แตกต่างจากที่คุณขอเล็กน้อย แต่ฉันยินดีที่พบที่นี่โดยให้ชื่อคำถาม
snake_charmer

11

นี่คือคำตอบที่แตกต่างกันเล็กน้อยสร้างออกจากคำตอบของ S.Lott ที่ช่วยให้รายการของวันระหว่างวันที่สองวันและstart endในตัวอย่างด้านล่างตั้งแต่ต้นปี 2560 ถึงวันนี้

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

คำตอบที่ช้าฉันรู้ แต่ฉันเพิ่งมีปัญหาเดียวกันและตัดสินใจว่าฟังก์ชั่นพิสัยภายในของ Python นั้นขาดเล็กน้อยในส่วนนี้ดังนั้นฉันจึงเขียนทับมันในโมดูล util ของฉัน

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
ฉันคิดว่าคุณต้องการoutput = []และสลับบรรทัดในwhile cmp(...)ลูป เปรียบเทียบและrange(0,10,1) _range(0,10,1)
sigfpe

3
date_rangeผมคิดว่าคำตอบนี้จะดีกว่าถ้าคุณตั้งชื่อฟังก์ชั่น
แบรนดอนแบรดลีย์

7

จากคำตอบที่ฉันเขียนเอง:

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

เอาท์พุท:

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

ความแตกต่างคือฉันได้dateวัตถุ "" ไม่ใช่วัตถุ " datetime.datetime"


7

หากมีสองวันและคุณต้องลองช่วง

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

นี่คือส่วนสำคัญที่ฉันสร้างขึ้นจากรหัสของฉันเองนี่อาจช่วยได้ (ฉันรู้ว่าคำถามนั้นเก่าเกินไป แต่คนอื่น ๆ สามารถใช้ได้)

https://gist.github.com/2287345

(สิ่งเดียวกันด้านล่าง)

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

ต่อไปนี้เป็นบทสรุปสำหรับสคริปต์ทุบตีเพื่อรับรายการวันธรรมดานี่คือ python 3 แก้ไขได้อย่างง่ายดายสำหรับทุกสิ่ง int ที่สิ้นสุดคือจำนวนวันในอดีตที่คุณต้องการ

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

นี่คือชุดตัวเลือกเพื่อให้วันที่เริ่มต้น (หรือค่อนข้างสิ้นสุด)

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

นี่คือตัวแปรสำหรับวันที่เริ่มต้นและสิ้นสุดโดยพลการ ไม่ใช่ว่ามันไม่ได้มีประสิทธิภาพมากนัก แต่ก็ดีสำหรับการใส่วนในสคริปต์ทุบตี:

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

อาจต้องการอัปเดตคำตอบของคุณด้วยรหัสในความคิดเห็นของคุณ Python ได้รับการรวบรวมความคิดเห็นและต้องการการจัดรูปแบบ
Jake Bathman

3

Matplotlib ที่เกี่ยวข้อง

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

ฉันรู้ว่าสิ่งนี้ได้รับคำตอบแล้ว แต่ฉันจะเอาคำตอบของฉันลงเพื่อจุดประสงค์ทางประวัติศาสตร์และเนื่องจากฉันคิดว่ามันตรงไปตรงมา

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

แน่นอนว่ามันจะไม่ชนะอะไรอย่างโค้ดกอล์ฟ แต่ฉันคิดว่ามันสวยงาม


arangeด้วยขั้นตอนเป็นสิ่งที่ดีมาก แต่listOfDatesประกอบด้วย datetime64 numpyแทน datetimes พื้นเมืองหลาม
F.Raab

2
อย่างไรก็ตามคุณสามารถใช้np.arange(…).astype(dt.datetime)เพื่อarangeส่งคืนไพ ธ อนไทม์เนทีฟแบบดั้งเดิมแทนการใช้ดัมบ์แบบ 64 บิต
F.Raab

2

อีกตัวอย่างหนึ่งที่นับไปข้างหน้าหรือข้างหลังเริ่มต้นจากคำตอบของ Sandeep

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)

จะช่วยให้

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

และ

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)

จะช่วยให้

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

โปรดทราบว่าวันที่เริ่มต้นรวมอยู่ในการส่งคืนดังนั้นหากคุณต้องการให้ใช้วันที่ทั้งหมดสี่วัน 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

เครื่องกำเนิดไฟฟ้าช่วงวันรายเดือนและdatetime dateutilง่ายและเข้าใจง่าย:

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
เขาต้องการที่จะกลับไปไม่ไปข้างหน้า .. ดังนั้นควรจะเป็นend base - datetime.timedeltaยิ่งกว่านั้น ... ทำไมโซลูชั่นนี้ดีกว่าของเดิม?
frarugi87

0

จากคำตอบข้างต้นฉันสร้างตัวอย่างนี้สำหรับตัวสร้างวันที่

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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.