Yıllar içinde Python timedelta


Yanıtlar:


156

timedeltaKaç yıl geçtiğini söylemek için a'dan fazlasına ihtiyacınız var; ayrıca başlangıç ​​(veya bitiş) tarihini de bilmeniz gerekir. (Bu artık bir yıl.)

En iyi seçiminiz dateutil.relativedelta nesneyi kullanmaktır , ancak bu bir üçüncü taraf modülüdür. Bunun belirli bir tarihten sonraki yıllar datetimeolduğunu bilmek istiyorsanız n(varsayılan olarak şu an için), aşağıdakileri yapabilirsiniz ::

from dateutil.relativedelta import relativedelta

def yearsago(years, from_date=None):
    if from_date is None:
        from_date = datetime.now()
    return from_date - relativedelta(years=years)

Standart kütüphaneye bağlı kalmayı tercih ederseniz, cevap biraz daha karmaşıktır ::

from datetime import datetime
def yearsago(years, from_date=None):
    if from_date is None:
        from_date = datetime.now()
    try:
        return from_date.replace(year=from_date.year - years)
    except ValueError:
        # Must be 2/29!
        assert from_date.month == 2 and from_date.day == 29 # can be removed
        return from_date.replace(month=2, day=28,
                                 year=from_date.year-years)

2/29 ve 18 yıl önce 2/29 olmasaydı, bu işlev 2/28 döndürür. 3/1 döndürmek isterseniz, son returnifadeyi şu şekilde değiştirin :

    return from_date.replace(month=3, day=1,
                             year=from_date.year-years)

Sorunuz başlangıçta bir tarihten bu yana kaç yıl geçtiğini bilmek istediğinizi söyledi. Tam sayı bir yıl istediğinizi varsayarsak, yılda 365,25 güne göre tahmin edebilir ve sonra yearsagoyukarıda tanımlanan işlevlerden birini kullanarak kontrol edebilirsiniz ::

def num_years(begin, end=None):
    if end is None:
        end = datetime.now()
    num_years = int((end - begin).days / 365.25)
    if begin > yearsago(num_years, end):
        return num_years - 1
    else:
        return num_years

26
Gregoryen takvimi için 400 yıllık istisnayı dikkate alan 365.2425 (365.25 yerine) ile tam olarak doğru olabilirsiniz.
brianary

3
İngiltere ve Hong Kong gibi ülkeler için işleviniz yasal olarak kesiliyor, çünkü artık yıllar boyunca 1 Mart'a kadar yuvarlanıyorlar.
antihero


3
Ayrıca bkz. bu ve bu Her ikisi de zaman hakkında doğru olmayan şeylerin mükemmel listeleridir.
gvoysey

49

Birinin 18 yaşında olup olmadığını kontrol etmeye çalışıyorsanız timedelta, artık yıllar nedeniyle bazı kenar durumlarda doğru şekilde çalışmaz. Örneğin, 1 Ocak 2000'de doğan biri, 1 Ocak 2018'de tam olarak 6575 gün sonra 18'i (5 artık yıl dahil), ancak 1 Ocak 2001'de doğan biri, 1 Ocak'ta tam olarak 6574 gün sonra 18'i, 2019 (4 artık yıl dahil). Böylece, eğer birisi tam olarak 6574 günlükse, doğum tarihi hakkında biraz daha fazla bilgi bilmeden 17 veya 18 olup olmadığını belirleyemezsiniz.

Bunu yapmanın doğru yolu, iki yılı çıkararak ve sonra geçerli ayın / günün doğum ayından / gününden önce olması durumunda yaşı doğrudan tarihlerden hesaplamaktır.


9

Öncelikle, en ayrıntılı düzeyde, sorun tam olarak çözülemez. Yıllar uzunluk olarak değişir ve yıl boyu için net bir "doğru seçim" yoktur.

Bununla birlikte, hangi birimlerin "doğal" (muhtemelen saniye) olduğu farkını elde edin ve o ve yıllar arasındaki orana bölün. Örneğin

delta_in_days / (365.25)
delta_in_seconds / (365.25*24*60*60)

...ya da her neyse. Yıllardan daha az iyi tanımlandıkları için aylardan uzak durun.


2
Bu, kaç yıllık hizmet veya bir kişinin belirli bir yaşa ulaştığı sorusu olduğunda kimsenin ne anlama geldiği veya kullandığı DEĞİLDİR.
John Machin

3
Gregoryen takviminin 400 yıllık istisnasını dikkate almak için 365.25'iniz 365.2425 olmalıdır.
brianary

1
Aslında sorun olabilir doğru çözülecek - Önünüzde yıl sıçrama günleri ve artık saniye ve tüm bu kadar süre içinde söyleyebilir. Bu yıl, daha sonra ay, gün sayısı, vs ... iki biçimlendirilmiş tarihleri çıkarılarak olmadan bunu yapmanın hiçbir derece şık bir yol var ki sadece var
Litherum

7

İşte doğum günlerini insanların yaptığı gibi hesaplayan güncellenmiş bir DOB işlevi:

import datetime
import locale


# Source: https://en.wikipedia.org/wiki/February_29
PRE = [
    'US',
    'TW',
]
POST = [
    'GB',
    'HK',
]


def get_country():
    code, _ = locale.getlocale()
    try:
        return code.split('_')[1]
    except IndexError:
        raise Exception('Country cannot be ascertained from locale.')


def get_leap_birthday(year):
    country = get_country()
    if country in PRE:
        return datetime.date(year, 2, 28)
    elif country in POST:
        return datetime.date(year, 3, 1)
    else:
        raise Exception('It is unknown whether your country treats leap year '
                      + 'birthdays as being on the 28th of February or '
                      + 'the 1st of March. Please consult your country\'s '
                      + 'legal code for in order to ascertain an answer.')
def age(dob):
    today = datetime.date.today()
    years = today.year - dob.year

    try:
        birthday = datetime.date(today.year, dob.month, dob.day)
    except ValueError as e:
        if dob.month == 2 and dob.day == 29:
            birthday = get_leap_birthday(today.year)
        else:
            raise e

    if today < birthday:
        years -= 1
    return years

print(age(datetime.date(1988, 2, 29)))

Dob 29 Şubat olduğunda ve bu yıl bir artık yıl olmadığında bu kırılır.
Trey Hunner

4

Gün sayısını alın ve yıllarca 365.2425'e (ortalama Gregoryen yıl) bölün. Aylar için 30.436875'e (ortalama Gregoryen ay) bölün.


2
def age(dob):
    import datetime
    today = datetime.date.today()

    if today.month < dob.month or \
      (today.month == dob.month and today.day < dob.day):
        return today.year - dob.year - 1
    else:
        return today.year - dob.year

>>> import datetime
>>> datetime.date.today()
datetime.date(2009, 12, 1)
>>> age(datetime.date(2008, 11, 30))
1
>>> age(datetime.date(2008, 12, 1))
1
>>> age(datetime.date(2008, 12, 2))
0

29 Şubat'ta doğan bir kişi, takip eden 28 Şubat'ta 1 yaşını almış olarak kabul edilecektir.
John Machin

Tamam. Testi "bugünün doğum günü" den "bugünün doğum günü" olarak değiştirerek 29. doğumda doğan nüfusun% 0,08'ini karşılayacak şekilde düzeltildi. Bu çözüyor mu?
John Mee

Örneğiniz için doğru çalışıyor!?! "Bugün" ü 28 Şubat 2009 olarak ve doğum tarihini 29 Şubat 2008 olarak ayarlarsam, en azından benim için Sıfır değerini döndürür; önerdiğiniz gibi 1 değil (Python 2.5.2). Bay Machin'e kaba davranmaya gerek yok. Tam olarak hangi tarihte sorun yaşıyorsun?
John Mee

Tekrar deneyeceğim: 29 Şubat'ta doğan bir kişi, çoğu yasal kişi tarafından sonraki 28 Şubat'ta 1 yaşına gelmiş gibi muamele görecek. Kodunuz "düzeltmenizden" önce ve sonra 0 üretir. Aslında, kodunuzun iki sürümü TÜM 9 giriş olasılıkları için tam olarak aynı çıktıyı üretir (ay <==> X gün <==>). BTW, 100.0 / (4 * 365 + 1) 0.08 değil 0.068 üretir.
John Machin

2
İç çekmek. (0) Herhangi bir tarih aritmetiğinde 29 Şubat sayılarının ele alınması esastır; sadece görmezden geldin. (1) Kodunuz ilk seferde daha iyi değildi; "TAMAMEN aynı çıktıyı üret" bölümünde ne anlamıyorsunuz? (2) Bugün karşılaştırılan üç olası atom sonucu (<, ==,>). Ay ve dob.ay; bugün karşılaştırılan üç olası atom sonucu. gün ve dob.day; 3 * 3 == 9 (3) stackoverflow.com/questions/2217488/…
John Machin

1

Ne kadar kesin olması gerekiyor? td.days / 365.25Eğer artık yıllar hakkında endişeleniyorsanız, size oldukça yakın olacak.


Artık yıllar konusunda gerçekten endişeliyim. Kişinin 18 yaşından büyük olup olmadığını kontrol etmelidir.
Migol

O zaman kolay bir astar yoktur, iki tarihi ayrıştırmanız ve kişinin 18. doğum gününü geçip geçmediğini anlamanız gerekir.
eduffy

1

Yine burada belirtilmeyen başka bir 3. taraf lib mxDateTime (hem python hem de datetime3. tarafın selefi timeutil) bu görev için kullanılabilir.

Yukarıda belirtilenler yearsago:

from mx.DateTime import now, RelativeDateTime

def years_ago(years, from_date=None):
    if from_date == None:
        from_date = now()
    return from_date-RelativeDateTime(years=years)

İlk parametrenin bir DateTimeörnek olması beklenir .

Sıradan dönüştürmek datetimeiçin DateTimebunu 1 saniye hassasiyetle kullanabilirsiniz):

def DT_from_dt_s(t):
    return DT.DateTimeFromTicks(time.mktime(t.timetuple()))

veya 1 mikrosaniye hassasiyet için:

def DT_from_dt_u(t):
    return DT.DateTime(t.year, t.month, t.day, t.hour,
  t.minute, t.second + t.microsecond * 1e-6)

Ve evet, söz konusu bu göreve bağımlılık eklemek, timeutil (Rick Copeland tarafından önerilen) kullanımı ile karşılaştırıldığında kesinlikle aşırıya kaçmak olacaktır.


1

Sonunda elinizde matematik sorunu var. Eğer her 4 yılda bir ekstra günümüz varsa, zaman dilimini 365 gün değil, 365 * 4 + 1 ile günler halinde dalış yapalım, bu size 4 yıl verir. Sonra tekrar 4'e bölün. Timedelta / ((365 * 4) +1) / 4 = timedelta * 4 / (365 * 4 +1)


Artık yıl olayı, yıllar 100'e bölünebiliyorsa geçerli değildir, 400'e bölünebilirler hariç. Yani, 2000 yılı için: - dörtle bölünebilir, bu yüzden sıçrama olmalı ama ... - ayrıca bölünebilir yüzlerce, bu yüzden sıçrama olmamalı ama ... - 400 ile bölünebilir, bu yüzden aslında bir sıçrama yılıydı. 1900 için: - 4 ile bölünebilir, bu yüzden sıçrama olmalıdır. - 100 ile bölünebilir, bu yüzden sıçrama olmamalıdır. - 400 ile bölünemez, bu nedenle bu kural geçerli değildir. 1900 artık bir yıl değildi.
Jblasco

1

Çalıştığım çözüm bu, umarım yardımcı olabilir ;-)

def menor_edad_legal(birthday):
    """ returns true if aged<18 in days """ 
    try:

        today = time.localtime()                        

        fa_divuit_anys=date(year=today.tm_year-18, month=today.tm_mon, day=today.tm_mday)

        if birthday>fa_divuit_anys:
            return True
        else:
            return False            

    except Exception, ex_edad:
        logging.error('Error menor de edad: %s' % ex_edad)
        return True

0

Bu iş parçacığı zaten ölü olsa da, karşılaştığım aynı sorun için çalışan bir çözüm önerebilir miyim. İşte (tarih dd-aa-yyyy biçiminde bir dizedir):

def validatedate(date):
    parts = date.strip().split('-')

    if len(parts) == 3 and False not in [x.isdigit() for x in parts]: 
        birth = datetime.date(int(parts[2]), int(parts[1]), int(parts[0]))
        today = datetime.date.today()

        b = (birth.year * 10000) + (birth.month * 100) + (birth.day)
        t = (today.year * 10000) + (today.month * 100) + (today.day)

        if (t - 18 * 10000) >= b:
            return True

    return False

0

bu işlev iki tarih arasındaki yıl farkını döndürür (ISO biçiminde dize olarak alınır, ancak herhangi bir biçimde almak için kolayca değiştirilebilir)

import time
def years(earlydateiso,  laterdateiso):
    """difference in years between two dates in ISO format"""

    ed =  time.strptime(earlydateiso, "%Y-%m-%d")
    ld =  time.strptime(laterdateiso, "%Y-%m-%d")
    #switch dates if needed
    if  ld < ed:
        ld,  ed = ed,  ld            

    res = ld[0] - ed [0]
    if res > 0:
        if ld[1]< ed[1]:
            res -= 1
        elif  ld[1] == ed[1]:
            if ld[2]< ed[2]:
                res -= 1
    return res

0

Ben önermek olacak Pyfdate

Pyfdate nedir?

Python'un güçlü ve kullanımı kolay bir komut dosyası dili olma hedefi göz önüne alındığında, tarih ve saatlerle çalışma özellikleri olması gerektiği gibi kullanıcı dostu değildir. Pyfdate'in amacı, Python'un geri kalanı kadar güçlü ve kullanımı kolay tarih ve saatlerle çalışmak için özellikler sağlayarak bu durumu düzeltmektir.

öğretici


0
import datetime

def check_if_old_enough(years_needed, old_date):

    limit_date = datetime.date(old_date.year + years_needed,  old_date.month, old_date.day)

    today = datetime.datetime.now().date()

    old_enough = False

    if limit_date <= today:
        old_enough = True

    return old_enough



def test_ages():

    years_needed = 30

    born_date_Logan = datetime.datetime(1988, 3, 5)

    if check_if_old_enough(years_needed, born_date_Logan):
        print("Logan is old enough")
    else:
        print("Logan is not old enough")


    born_date_Jessica = datetime.datetime(1997, 3, 6)

    if check_if_old_enough(years_needed, born_date_Jessica):
        print("Jessica is old enough")
    else:
        print("Jessica is not old enough")


test_ages()

Bu, Atlı Karınca operatörünün Logan's Run filminde çalıştırdığı koddur;)

https://en.wikipedia.org/wiki/Logan%27s_Run_(film)


0

Bu soruya rastladım ve Adams'ın en faydalı yanıtı buldum https://stackoverflow.com/a/765862/2964689

Ama yönteminin python örneği yoktu ama işte sonunda kullandığım şey.

input: datetime nesnesi

çıktı: tam yıl tamsayı

def age(birthday):
    birthday = birthday.date()
    today = date.today()

    years = today.year - birthday.year

    if (today.month < birthday.month or
       (today.month == birthday.month and today.day < birthday.day)):

        years = years - 1

    return years

0

John Mee'nin basitliği için çözümünü beğendim ve 28 Şubat veya 1 Mart'ta artık bir yıl olmadığında, 29 Şubat'ta doğan insanların yaşını nasıl belirleyeceğinden endişe duymuyorum. Bence şikayetleri ele alıyor:

def age(dob):
    import datetime
    today = datetime.date.today()
    age = today.year - dob.year
    if ( today.month == dob.month == 2 and
         today.day == 28 and dob.day == 29 ):
         pass
    elif today.month < dob.month or \
      (today.month == dob.month and today.day < dob.day):
        age -= 1
    return age
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.