Ayın son günü nasıl alınır?


632

Belirli bir ayın son gününü kolayca belirlemek (yani bir işlev çağrısı) için Python'un standart kütüphanesini kullanmanın bir yolu var mı?

Standart kütüphane bunu desteklemiyorsa, dateutil paketi bunu destekliyor mu?

Yanıtlar:


1082

Modülün belgelerinecalendar bakarken bunu daha önce fark etmedim , ancak adı verilen bir yöntem monthrangebu bilgileri sağlar:

monthrange (yıl, ay)
    Belirtilen yıl ve ay için ayın ilk gününün hafta gününü ve aydaki gün sayısını döndürür.

>>> import calendar
>>> calendar.monthrange(2002,1)
(1, 31)
>>> calendar.monthrange(2008,2)
(4, 29)
>>> calendar.monthrange(2100,2)
(0, 28)

yani:

calendar.monthrange(year, month)[1]

en basit yol gibi görünüyor.

Açık olmak gerekirse, monthrangeartık yılları da destekliyor:

>>> from calendar import monthrange
>>> monthrange(2012, 2)
(2, 29)

Önceki cevabım hala çalışıyor, ancak açıkça yetersiz.


Bu asıl soruya doğru bir cevap değil! Ya ayın son günü Cmt / Paz ise.
Mehdi

8
@mahdi: doğru, ikinci sayı ne tür bir gün olursa olsun, "aydaki gün sayısı" == "son gün" dür.
RickyA

1800 şubat yılı için yanlış gün döner. Ben alamadım
sword1st

8
@ sword1st, Gregoryen takvimi kurallarını28 kullanarak doğru cevabı görüyorum
Blair Conrad

monthrangeKafa karıştırıcı bir isim olduğunu düşünen tek kişi olamam . Bunu döneceğini düşünürdüm (first_day, last_day)değil(week_day_of_first_day, number_of_days)
Flimm

146

calendarModülü içe aktarmak istemiyorsanız , iki adımlı basit bir işlev de olabilir:

import datetime

def last_day_of_month(any_day):
    next_month = any_day.replace(day=28) + datetime.timedelta(days=4)  # this will never fail
    return next_month - datetime.timedelta(days=next_month.day)

Çıktılar:

>>> for month in range(1, 13):
...     print last_day_of_month(datetime.date(2012, month, 1))
...
2012-01-31
2012-02-29
2012-03-31
2012-04-30
2012-05-31
2012-06-30
2012-07-31
2012-08-31
2012-09-30
2012-10-31
2012-11-30
2012-12-31

81

EDIT: Daha temiz bir çözüm için @Blair Conrad'ın cevabına bakınız.


>>> import datetime
>>> datetime.date(2000, 2, 1) - datetime.timedelta(days=1)
datetime.date(2000, 1, 31)

43
Aslında bu temizleyici derim, ancak ne zaman Aralık ayında başarısız olursa today.month + 1 == 13ve bir olsun ValueError.
Mart'ta

4
O (today.month % 12) + 1zamandan beri kullanarak bunu çözebilirsiniz 12 % 120
bluesmoon

Bir ayın 31'inde bazı garip gün ışığından yararlanma anahtarı (bugün var, ancak gelecek farklı olabilir) o ayın 31'ini sadece 23 saat uzunluğunda hale getirebilir, böylece bir günü çıkarmak size izin verir 30.00'da 23: 00'da bitiyor. Bu çok garip bir durum, elbette, ama yaklaşımın sağlam olmadığını gösteriyor.
Alfe

50

Bu aslında dateutil.relativedelta(pip için python-datetutil paketi) ile oldukça kolaydır . day=31her zaman ayın son gününü döndürür.

Misal:

from datetime import datetime
from dateutil.relativedelta import relativedelta

date_in_feb = datetime.datetime(2013, 2, 21)
print datetime.datetime(2013, 2, 21) + relativedelta(day=31)  # End-of-month
>>> datetime.datetime(2013, 2, 28, 0, 0)

7
Şahsen relativedelta'yı seviyorum (ay = + 1, saniye = -1) neler olduğunu daha açık görünüyor
BenH

Yanılıyorsun. datetime(2014, 2, 1) + relativedelta(days=31)verir datetime(2014, 3, 4, 0, 0)...
Emmanuel

9
gün kullandınız = gün yerine =
Vince Spicer

@BenH Bu önce monthseklendi, sonra secondsçıkarılır umut (Ben belirtildi emin değilim) dayanmaktadır . **kwargsBen buna güvenmediğim ve bir dizi ayrı işlem yaptığım için geçtikleri için : now + relative(months=+1) + relative(day=1) + relative(days=-1)bu açık.
Alfe

last_day = (<datetime_object> + relativedelta(day=31)).day
user12345

44

EDIT: diğer cevabımı gör . Birisi nasıl kendi "rulo" hesap makinesi görmek isteyen ilgilenen durumunda ben burada bırakın, daha iyi bir uygulama vardır.

John Millikin, gelecek ayın ilk gününü hesaplamanın karmaşıklığıyla birlikte iyi bir cevap veriyor.

Aşağıdakiler özellikle zarif değildir, ancak herhangi bir tarihin yaşandığı ayın son gününü bulmak için deneyebilirsiniz:

def last_day_of_month(date):
    if date.month == 12:
        return date.replace(day=31)
    return date.replace(month=date.month+1, day=1) - datetime.timedelta(days=1)

>>> last_day_of_month(datetime.date(2002, 1, 17))
datetime.date(2002, 1, 31)
>>> last_day_of_month(datetime.date(2002, 12, 9))
datetime.date(2002, 12, 31)
>>> last_day_of_month(datetime.date(2008, 2, 14))
datetime.date(2008, 2, 29)

Kulağa aptalca geliyor ama ayın ilk gününü nasıl bu şekilde elde ederim.
Kishan

10
Her zaman 1 değil mi?
Blair Conrad

Evet ama kafam böyle bir şey arıyordum karıştı: start_date = date (datetime.now (). Yıl, datetime.now (). Ay, 1)
Kishan

4
Ah. today = datetime.date.today(); start_date = today.replace(day=1). 31 Aralık'ta gece yarısından hemen önce ve sonra gece yarısından sonra aradıysanız, datetime.now öğesini iki kez çağırmak istemezsiniz. 2016-12-01 veya 2017-01-01 yerine 2016-01-01 alırsınız.
Blair Conrad

Bu, anlaşılması çok kolaydır ve birçok durumda yararlı olabilecek bir datetime örneği döndürür. Diğer bir avantajı girişi ise işe yaraması datebir örneğidir datetime.date, datetime.datetimeayrıca ve pandas.Timestamp.
Guilherme Salomé

26

dateutil.relativedeltaBunu kullanarak ayın son tarihini şöyle elde edersiniz:

from dateutil.relativedelta import relativedelta
last_date_of_month = datetime(mydate.year, mydate.month, 1) + relativedelta(months=1, days=-1)

Fikir, ayın ilk gününü almak ve relativedelta1 ay ileri ve 1 gün geri gitmek için kullanmaktır , böylece istediğiniz ayın son gününü elde edersiniz.


13

Başka bir çözüm böyle bir şey yapmak olacaktır:

from datetime import datetime

def last_day_of_month(year, month):
    """ Work out the last day of the month """
    last_days = [31, 30, 29, 28, 27]
    for i in last_days:
        try:
            end = datetime(year, month, i)
        except ValueError:
            continue
        else:
            return end.date()
    return None

Ve işlevi şu şekilde kullanın:

>>> 
>>> last_day_of_month(2008, 2)
datetime.date(2008, 2, 29)
>>> last_day_of_month(2009, 2)
datetime.date(2009, 2, 28)
>>> last_day_of_month(2008, 11)
datetime.date(2008, 11, 30)
>>> last_day_of_month(2008, 12)
datetime.date(2008, 12, 31)

5
Çok karmaşık, python zeninin üçüncü kuralını ihlal ediyor.
markuz

11
from datetime import timedelta
(any_day.replace(day=1) + timedelta(days=32)).replace(day=1) - timedelta(days=1)

Bu hatalar nelerdir;) 31 Ocak ile deneyin
LeartS

@ Kalpler: benim için çalışıyor. Denediğinde ne oluyor?
Collin Anderson

1
İşe yarıyor. any_day 31 Ocak, biz 1 yerine gün, yani 1 Ocak, 32 gün ekleyin, biz 2 Şubat olsun, yerine tekrar gün = 1 ile değiştirin ve biz 1 Şubat olsun. Bir gün çıkarın ve 31 Ocak olsun. Görmüyorum sorunun ne olduğunu. Hangi gün alıyorsun
Collin Anderson

9
>>> import datetime
>>> import calendar
>>> date  = datetime.datetime.now()

>>> print date
2015-03-06 01:25:14.939574

>>> print date.replace(day = 1)
2015-03-01 01:25:14.939574

>>> print date.replace(day = calendar.monthrange(date.year, date.month)[1])
2015-03-31 01:25:14.939574

9

harici bir kütüphane kullanmak istiyorsanız, http://crsmithdev.com/arrow/ adresini ziyaret edin

Daha sonra şu ayın son gününü alabilirsiniz:

import arrow
arrow.utcnow().ceil('month').date()

Bu, daha sonra manipülasyonunuzu yapabileceğiniz bir tarih nesnesi döndürür.


9

Ayın son tarihini almak için şöyle bir şey yaparız:

from datetime import date, timedelta
import calendar
last_day = date.today().replace(day=calendar.monthrange(date.today().year, date.today().month)[1])

Şimdi burada ne yaptığımızı açıklamak için iki parçaya ayıracağız:

İlk kullandığımız hangi cari ayın gün sayısını elde ettiğini monthrange Blair Conrad zaten onun çözümünü söz etti:

calendar.monthrange(date.today().year, date.today().month)[1]

İkinci biz yardımı ile yapmak son tarih kendisi oluyor değiştirin mesela

>>> date.today()
datetime.date(2017, 1, 3)
>>> date.today().replace(day=31)
datetime.date(2017, 1, 31)

ve bunları yukarıda belirtildiği gibi birleştirdiğimizde dinamik bir çözüm elde ederiz.


Bu kod sorunu çözmeye yardımcı olsa da , soruyu neden ve / veya nasıl cevapladığını açıklamaz . Bu ek bağlamın sağlanması, uzun vadeli eğitim değerini önemli ölçüde artıracaktır. Hangi sınırlamalar ve varsayımlar dahil olmak üzere açıklama eklemek için lütfen yanıtınızı düzenleyin .
Toby Speight

Bu en basit gibi görünüyor .. Eğer iki satır vermek için istekli iseniz, güzel bir alabilirsiniz date.replace(day=day)böylece herkes neler olduğunu biliyor.
Adam Starrh

9

Python 3.7'de belgelenmemiş calendar.monthlen(year, month)işlev vardır :

>>> calendar.monthlen(2002, 1)
31
>>> calendar.monthlen(2008, 2)
29
>>> calendar.monthlen(2100, 2)
28

Belgelenen calendar.monthrange(year, month)[1]çağrıya eşdeğerdir .


1
Bu Python 3.8.1 üzerinde çalışmıyor gibi görünüyor: AttributeError: '' calendar 'modül' monthlen 'özelliği yok
jeppoo1

1
@ jeppoo1: evet, bpo-28292'de özel olarak işaretlenmiştir - belgelenmemiş bir işlev beklenir.
jfs

5
import datetime

now = datetime.datetime.now()
start_month = datetime.datetime(now.year, now.month, 1)
date_on_next_month = start_month + datetime.timedelta(35)
start_next_month = datetime.datetime(date_on_next_month.year, date_on_next_month.month, 1)
last_day_month = start_next_month - datetime.timedelta(1)

5

Pandaları kullanın!

def isMonthEnd(date):
    return date + pd.offsets.MonthEnd(0) == date

isMonthEnd(datetime(1999, 12, 31))
True
isMonthEnd(pd.Timestamp('1999-12-31'))
True
isMonthEnd(pd.Timestamp(1965, 1, 10))
False

1
pd.series.dt.is_month_end bağlantıyı
Pablo

1
Pandalar datetime nesnesinin bunun için belirli bir yöntemi vardır:now=datetime.datetime.now(); pd_now = pd.to_datetime(now); print(pd_now.days_in_month)
Roei Bahumi

3

Benim için en basit yol:

selected_date = date(some_year, some_month, some_day)

if selected_date.month == 12: # December
     last_day_selected_month = date(selected_date.year, selected_date.month, 31)
else:
     last_day_selected_month = date(selected_date.year, selected_date.month + 1, 1) - timedelta(days=1)

3

En kolay yol (takvimi içe aktarmak zorunda kalmadan), bir sonraki ayın ilk gününü almak ve daha sonra bir gün çıkarmaktır.

import datetime as dt
from dateutil.relativedelta import relativedelta

thisDate = dt.datetime(2017, 11, 17)

last_day_of_the_month = dt.datetime(thisDate.year, (thisDate + relativedelta(months=1)).month, 1) - dt.timedelta(days=1)
print last_day_of_the_month

Çıktı:

datetime.datetime(2017, 11, 30, 0, 0)

Not: Bu kod import calendaryaklaşıma göre daha hızlı çalışır ; aşağıya bakınız:

import datetime as dt
import calendar
from dateutil.relativedelta import relativedelta

someDates = [dt.datetime.today() - dt.timedelta(days=x) for x in range(0, 10000)]

start1 = dt.datetime.now()
for thisDate in someDates:
    lastDay = dt.datetime(thisDate.year, (thisDate + relativedelta(months=1)).month, 1) - dt.timedelta(days=1)

print ('Time Spent= ', dt.datetime.now() - start1)


start2 = dt.datetime.now()
for thisDate in someDates:
    lastDay = dt.datetime(thisDate.year, 
                          thisDate.month, 
                          calendar.monthrange(thisDate.year, thisDate.month)[1])

print ('Time Spent= ', dt.datetime.now() - start2)

ÇIKTI:

Time Spent=  0:00:00.097814
Time Spent=  0:00:00.109791

Bu kod, ayın son gününün tarihini istediğinizi varsayar (yani yalnızca DD bölümü değil, tüm YYYYAAGG tarihi)


neden istemiyorsun import calendar?
Adam Venturella

1
Çünkü daha hızlı. Yukarıdaki cevabımı bunu içerecek şekilde değiştirdim.
Vishal

@Vishal kavramı doğru anladınız, ancak aşağıdaki satır değildi: `` dt.datetime (thisDate.year, (thisDate + relativedelta (ay = 1)). Ay, 1) - dt.timedelta (gün = 1) ` `` özellikle ay yılın sonundaysa. `` last_date_of_month = \ first_date_of_month + relativedelta (ay = 1) - relativedelta (gün = 1) `` yerine ``
XV

3

İşte başka bir cevap. Ekstra paket gerekmez.

datetime.date(year + int(month/12), month%12+1, 1)-datetime.timedelta(days=1)

Gelecek ayın ilk gününü alın ve ondan bir gün çıkarın.


2

Bitiş tarihini kendiniz hesaplayabilirsiniz. basit mantık bir günü gelecek ayın başlangıç_tarihi'nden çıkarmaktır. :)

Özel bir yöntem yazın,

import datetime

def end_date_of_a_month(date):


    start_date_of_this_month = date.replace(day=1)

    month = start_date_of_this_month.month
    year = start_date_of_this_month.year
    if month == 12:
        month = 1
        year += 1
    else:
        month += 1
    next_month_start_date = start_date_of_this_month.replace(month=month, year=year)

    this_month_end_date = next_month_start_date - datetime.timedelta(days=1)
    return this_month_end_date

Arayan,

end_date_of_a_month(datetime.datetime.now().date())

Bu ayın bitiş tarihini döndürecek. Bu işleve herhangi bir tarih iletin. size o ayın bitiş tarihini döndürür.



1

Bu, yalnızca standart datetime kütüphanesini kullanarak benim için en basit çözümdür:

import datetime

def get_month_end(dt):
    first_of_month = datetime.datetime(dt.year, dt.month, 1)
    next_month_date = first_of_month + datetime.timedelta(days=32)
    new_dt = datetime.datetime(next_month_date.year, next_month_date.month, 1)
    return new_dt - datetime.timedelta(days=1)

0

Bu ana soruyu ele almaz, ancak bir ay içinde son hafta içi günü almak için güzel bir hile calendar.monthcalendar, Pazartesi ile ilk sütun olarak Pazar ile sonuncu olarak düzenlenen bir tarih matrisi döndüren kullanmaktır .

# Some random date.
some_date = datetime.date(2012, 5, 23)

# Get last weekday
last_weekday = np.asarray(calendar.monthcalendar(some_date.year, some_date.month))[:,0:-2].ravel().max()

print last_weekday
31

Her [0:-2]şey hafta sonu sütunlarını tıraş etmek ve atmak. Ayın dışında kalan tarihler 0 ile gösterilir, böylece maks.

Kullanımı numpy.ravelkesinlikle gerekli değildir, ama sadece sözleşmeye güvenmekten nefret ediyorum .numpy.ndarray.max boyunca hesaplamak için hangi ekseni bildirilmediği takdirde diziyi dümdüz olacak.


0
import calendar
from time import gmtime, strftime
calendar.monthrange(int(strftime("%Y", gmtime())), int(strftime("%m", gmtime())))[1]

Çıktı:

31



Bu, geçerli ayın son gününü yazdıracaktır. Bu örnekte 15 Mayıs 2016'ydı. Dolayısıyla, çıktınız farklı olabilir, ancak çıktı mevcut ayın olduğu kadar gün olacaktır. Günlük bir cron işi çalıştırarak ayın son gününü kontrol etmek istiyorsanız harika.

Yani:

import calendar
from time import gmtime, strftime
lastDay = calendar.monthrange(int(strftime("%Y", gmtime())), int(strftime("%m", gmtime())))[1]
today = strftime("%d", gmtime())
lastDay == today

Çıktı:

False

Ayın son günü olmadığı sürece.


0

Bu yolu tercih ederim

import datetime
import calendar

date=datetime.datetime.now()
month_end_date=datetime.datetime(date.year,date.month,1) + datetime.timedelta(days=calendar.monthrange(date.year,date.month)[1] - 1)

0

Kendi küçük işlevinizi yapmak istiyorsanız, bu iyi bir başlangıç ​​noktasıdır:

def eomday(year, month):
    """returns the number of days in a given month"""
    days_per_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    d = days_per_month[month - 1]
    if month == 2 and (year % 4 == 0 and year % 100 != 0 or year % 400 == 0):
        d = 29
    return d

Bunun için artık yılların kurallarını bilmelisiniz:

  • her dördüncü yılda bir
  • her 100 yılda bir hariç
  • ama yine her 400 yılda bir

1
Elbette, ancak sistem kütüphaneleri zaten bu verilere sahiptir ve kurallar kararname ile değiştirilirse, kütüphanelerin güncellenmesi başkasının problemidir.
Jasen

Eh, mümkün ama pek olası ve hatta eğer - sadece 2000 hakkında yıl sonra lokma olacağını ... en.wikipedia.org/wiki/Gregorian_calendar#Accuracy
mathause

Bu kurallar 500 yıl geçmişte işe yaramıyor Binlerce yıl boyunca geleceklerine dair hiçbir güvenim yok
Jasen

0

Bir tarih aralığını geçerseniz, bunu kullanabilirsiniz:

def last_day_of_month(any_days):
    res = []
    for any_day in any_days:
        nday = any_day.days_in_month -any_day.day
        res.append(any_day + timedelta(days=nday))
    return res

0

Aşağıdaki kodda 'get_last_day_of_month (dt)' size 'YYYY-AA-GG' gibi dize biçiminde tarih verir.

import datetime

def DateTime( d ):
    return datetime.datetime.strptime( d, '%Y-%m-%d').date()

def RelativeDate( start, num_days ):
    d = DateTime( start )
    return str( d + datetime.timedelta( days = num_days ) )

def get_first_day_of_month( dt ):
    return dt[:-2] + '01'

def get_last_day_of_month( dt ):
    fd = get_first_day_of_month( dt )
    fd_next_month = get_first_day_of_month( RelativeDate( fd, 31 ) )
    return RelativeDate( fd_next_month, -1 )

0

En basit yol kullanmak datetimeve bazı tarih matematiği kullanmaktır , örneğin bir sonraki ayın ilk gününden bir gün çıkarmak:

import datetime

def last_day_of_month(d: datetime.date) -> datetime.date:
    return (
        datetime.date(d.year + d.month//12, d.month % 12 + 1, 1) -
        datetime.timedelta(days=1)
    )

Alternatif olarak, calendar.monthrange()bir aydaki gün sayısını (artık yılları dikkate alarak) almak ve tarihi buna göre güncellemek için kullanabilirsiniz:

import calendar, datetime

def last_day_of_month(d: datetime.date) -> datetime.date:
    return d.replace(day=calendar.monthrange(d.year, d.month)[1])

Hızlı bir karşılaştırma, ilk sürümün belirgin şekilde daha hızlı olduğunu gösterir:

In [14]: today = datetime.date.today()

In [15]: %timeit last_day_of_month_dt(today)
918 ns ± 3.54 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [16]: %timeit last_day_of_month_calendar(today)
1.4 µs ± 17.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

0

İşte uzun (anlaşılması kolay) bir versiyon ama artık yıllarla ilgileniyor.

alkış, JK

def last_day_month(year, month):
    leap_year_flag = 0
    end_dates = {
        1: 31,
        2: 28,
        3: 31,
        4: 30,
        5: 31,
        6: 30,
        7: 31,
        8: 31,
        9: 30,
        10: 31,
        11: 30,
        12: 31
    }

    # Checking for regular leap year    
    if year % 4 == 0:
        leap_year_flag = 1
    else:
        leap_year_flag = 0

    # Checking for century leap year    
    if year % 100 == 0:
        if year % 400 == 0:
            leap_year_flag = 1
        else:
            leap_year_flag = 0
    else:
        pass

    # return end date of the year-month
    if leap_year_flag == 1 and month == 2:
        return 29
    elif leap_year_flag == 1 and month != 2:
        return end_dates[month]
    else:
        return end_dates[month]

silebilir else: passve if year % 400 == 0: leap_year_flag = 1küçük değişikliklerden kurtulabilirsiniz
canbax

-1

İşte çözüm tabanlı bir python lambdas:

next_month = lambda y, m, d: (y, m + 1, 1) if m + 1 < 13 else ( y+1 , 1, 1)
month_end  = lambda dte: date( *next_month( *dte.timetuple()[:3] ) ) - timedelta(days=1)

next_monthLambda ertesi yıla tanımlama grubu sonraki ayın ilk gününden temsil ve rulo bulur. month_endLambda bir tarih (dönüşümleri dte, bir tuplea) uygular next_monthve yeni bir tarih yaratır. O zaman "ay sonu" sadece bir sonraki ayın ilk günü eksi olur timedelta(days=1).

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.