Aby timedeltapowiedzieć, ile lat minęło, potrzebujesz czegoś więcej ; musisz również znać datę rozpoczęcia (lub zakończenia). (To rok przestępny.)
Najlepiej jest użyć dateutil.relativedeltaobiektu , ale jest to moduł innej firmy. Jeśli chcesz wiedzieć, datetimeże nminęło lata od jakiejś daty (domyślnie do teraz), możesz wykonać następujące czynności:
Twoje pytanie pierwotnie wskazywało, że chciałeś wiedzieć, ile lat minęło od jakiejś daty. Zakładając, że chcesz uzyskać całkowitą liczbę lat, możesz zgadnąć na podstawie 365,25 dni w roku, a następnie sprawdzić za pomocą jednej z yearsagofunkcji zdefiniowanych powyżej:
def num_years(begin, end=None):if end isNone:
end = datetime.now()
num_years = int((end - begin).days /365.25)if begin > yearsago(num_years, end):return num_years -1else:return num_years
zobacz także to i to Obie są doskonałymi listami rzeczy, które nie są prawdą o czasie.
gvoysey
49
Jeśli próbujesz sprawdzić, czy ktoś ma 18 lat, użyj timedelta nie będzie działać poprawnie w niektórych skrajnych przypadkach z powodu lat przestępnych. Na przykład osoba urodzona 1 stycznia 2000 r. Skończy 18 lat dokładnie 6575 dni później 1 stycznia 2018 r. (Włączając 5 lat przestępnych), ale osoba urodzona 1 stycznia 2001 r. Skończy 18 lat dokładnie 6574 dni później 1 stycznia, 2019 (w tym 4 lata przestępne). Tak więc, jeśli ktoś ma dokładnie 6574 dni, nie możesz określić, czy ma on 17 czy 18 lat, nie wiedząc trochę więcej o jego dacie urodzenia.
Prawidłowym sposobem na to jest obliczenie wieku bezpośrednio na podstawie dat, odejmując dwa lata, a następnie odejmując jeden, jeśli bieżący miesiąc / dzień poprzedza miesiąc / dzień urodzenia.
Po pierwsze, na najbardziej szczegółowym poziomie problemu nie da się dokładnie rozwiązać. Lata różnią się długością i nie ma jasnego „właściwego wyboru” długości roku.
To powiedziawszy, uzyskaj różnicę w jednostkach „naturalnych” (prawdopodobnie w sekundach) i podziel przez stosunek tych jednostek do lat. Na przykład
To NIE jest to, co ktokolwiek ma na myśli lub używa, gdy chodzi o to, ile lat służby lub czy dana osoba osiągnęła określony wiek.
John Machin
3
Twoja 365,25 powinna wynosić 365,2425, aby wziąć pod uwagę 400-letni wyjątek kalendarza gregoriańskiego.
Brianary
1
Cóż, problem można rozwiązać poprawnie - możesz z wyprzedzeniem powiedzieć, które lata mają dni przestępne i sekundy przestępne i tak dalej. Chodzi tylko o to, że nie ma niezwykle eleganckiego sposobu na zrobienie tego bez odejmowania lat, miesięcy, dni itd. ... w dwóch sformatowanych datach
Litherum,
7
Oto zaktualizowana funkcja DOB, która oblicza urodziny w taki sam sposób, jak ludzie:
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]exceptIndexError:raiseException('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:raiseException('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)exceptValueErroras e:if dob.month ==2and dob.day ==29:
birthday = get_leap_birthday(today.year)else:raise e
if today < birthday:
years -=1return years
print(age(datetime.date(1988,2,29)))
Dzieje się tak, gdy data urodzenia przypada 29 lutego, a bieżący rok nie jest rokiem przestępnym.
Trey Hunner
4
Uzyskaj liczbę dni, a następnie podziel przez 365,2425 (średni rok gregoriański) na lata. Podziel przez 30,436875 (średni miesiąc gregoriański) dla miesięcy.
Osoba urodzona 29 lutego będzie traktowana jako osoba, która ukończyła 1 rok życia następnego 28 lutego.
John Machin
Dobrze. Skorygowano, aby uwzględnić 0,08% populacji urodzonej 29 dnia miesiąca poprzez odwrócenie testu z „są urodziny po dniu dzisiejszym” na „urodziny są przed dniem dzisiejszym”. Czy to rozwiązuje problem?
John Mee
Na twoim przykładzie działa poprawnie!?! Jeśli ustawię „dzisiaj” na 28 lutego 2009, a datę urodzenia na 29 lutego 2008, to zwróci Zero - przynajmniej dla mnie; nie 1, jak sugerujesz (Python 2.5.2). Nie ma potrzeby niegrzecznego pana Machina. Z jakimi dokładnie dwiema datami masz problem?
John Mee,
Spróbuję jeszcze raz: większość ludzi, dla większości celów prawnych, będzie traktować osobę urodzoną 29 lutego jako osobę, która ukończyła 1 rok następnego 28 lutego. Twój kod daje 0, zarówno przed, jak i po "korekcie". W rzeczywistości dwie wersje twojego kodu dają DOKŁADNIE te same dane wyjściowe dla WSZYSTKICH 9 możliwości wejściowych (miesiąc <==> X dzień <==>). BTW, 100,0 / (4 * 365 + 1) daje 0,068, a nie 0,08.
John Machin,
2
Westchnienie. (0) Zajęcie się kwestiami 29 lutego jest niezbędne w każdej arytmetyce dat; po prostu to zignorowałeś. (1) Twój kod nie był lepszy za pierwszym razem; czego nie rozumiesz w „wytwarzaj DOKŁADNIE takie same wyniki”? (2) Trzy możliwe niepodzielne wyniki (<, ==,>) porównujące dzisiejszy miesiąc i dzień doby miesiąca; trzy możliwe wyniki atomowe porównujące dzisiaj.dzień i dob.dzień; 3 * 3 == 9 (3) stackoverflow.com/questions/2217488/…
John Machin,
1
Jak dokładna ma być? td.days / 365.25zbliży cię do siebie, jeśli martwisz się o lata przestępne.
Martwię się o lata przestępne. Należy sprawdzić, czy dana osoba ma ukończone 18 lat.
Migol
Wtedy nie ma łatwej jednej linijki, będziesz musiał przeanalizować dwie daty i dowiedzieć się, czy dana osoba przekroczyła swoje 18 urodziny, czy nie.
eduffy
1
Jeszcze inna biblioteka innej firmy, o której tutaj nie wspomniano, to mxDateTime (poprzednik zarówno Pythona, jak datetimei innej firmy timeutil), którą można wykorzystać do tego zadania.
I tak, dodanie zależności dla tego pojedynczego zadania z pewnością byłoby przesadą w porównaniu nawet z użyciem timeutil (sugerowane przez Ricka Copelanda).
Ostatecznie masz problem z matematyką. Jeśli co 4 lata mamy dodatkowy dzień, zanurkujmy czas w dniach, a nie 365, ale 365 * 4 + 1, to daje 4 lata. Następnie podziel go ponownie przez 4. timedelta / ((365 * 4) +1) / 4 = timedelta * 4 / (365 * 4 +1)
Roku przestępnego nie stosuje się, gdy lata są podzielne przez 100, z wyjątkiem sytuacji, gdy są podzielne przez 400. Tak więc dla roku 2000: - jest podzielny przez cztery, więc powinien być skokowy, ale ... - jest również podzielny przez sto, więc nie powinien być skokowy, ale ... - jest podzielny przez 400, więc był to właściwie rok przestępny. Dla 1900: - jest podzielna przez 4, więc powinna być skokiem. - jest podzielna przez 100, więc nie powinna być skokiem. - NIE jest podzielna przez 400, więc ta zasada nie ma zastosowania. Rok 1900 nie był rokiem przestępnym.
Jblasco,
1
To rozwiązanie, które wypracowałem, mam nadzieję, że może pomóc ;-)
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:returnTrueelse:returnFalseexceptException, ex_edad:
logging.error('Error menor de edad: %s'% ex_edad)returnTrue
Mimo że ten wątek jest już martwy, czy mogę zasugerować działające rozwiązanie tego samego problemu, z którym miałem do czynienia. Oto on (data to ciąg w formacie dd-mm-rrrr):
def validatedate(date):
parts = date.strip().split('-')if len(parts)==3andFalsenotin[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:returnTruereturnFalse
ta funkcja zwraca różnicę w latach między dwiema datami (traktowanymi jako ciągi w formacie ISO, ale można ją łatwo zmodyfikować, aby przyjmować dowolny format)
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 neededif ld < ed:
ld, ed = ed, ld
res = ld[0]- ed [0]if res >0:if ld[1]< ed[1]:
res -=1elif ld[1]== ed[1]:if ld[2]< ed[2]:
res -=1return res
Biorąc pod uwagę, że Python ma być potężnym i łatwym w użyciu językiem skryptowym, jego funkcje do pracy z datami i godzinami nie są tak przyjazne dla użytkownika, jak powinny. Celem pyfdate jest zaradzenie tej sytuacji poprzez udostępnienie funkcji do pracy z datami i godzinami, które są równie wydajne i łatwe w użyciu, jak reszta Pythona.
Podobało mi się rozwiązanie Johna Mee ze względu na jego prostotę i nie przejmuję się tym, jak 28 lutego lub 1 marca, kiedy nie jest to rok przestępny, określić wiek osób urodzonych 29 lutego. Ale tutaj jest poprawka w jego kodzie co, jak sądzę, odnosi się do skarg:
def age(dob):import datetime
today = datetime.date.today()
age = today.year - dob.year
if( today.month == dob.month ==2and
today.day ==28and dob.day ==29):passelif today.month < dob.month or \
(today.month == dob.month and today.day < dob.day):
age -=1return age
Odpowiedzi:
Aby
timedelta
powiedzieć, ile lat minęło, potrzebujesz czegoś więcej ; musisz również znać datę rozpoczęcia (lub zakończenia). (To rok przestępny.)Najlepiej jest użyć
dateutil.relativedelta
obiektu , ale jest to moduł innej firmy. Jeśli chcesz wiedzieć,datetime
żen
minęło lata od jakiejś daty (domyślnie do teraz), możesz wykonać następujące czynności:Jeśli wolisz pozostać przy standardowej bibliotece, odpowiedź jest nieco bardziej złożona:
Jeśli jest 2/29, a 18 lat temu nie było 2/29, ta funkcja zwróci 2/28. Jeśli wolisz zwrócić 3/1, po prostu zmień ostatnią
return
instrukcję na:Twoje pytanie pierwotnie wskazywało, że chciałeś wiedzieć, ile lat minęło od jakiejś daty. Zakładając, że chcesz uzyskać całkowitą liczbę lat, możesz zgadnąć na podstawie 365,25 dni w roku, a następnie sprawdzić za pomocą jednej z
yearsago
funkcji zdefiniowanych powyżej:źródło
datetime.now()
) jest większa niż różnica między średnimi latami juliańskimi (365.25
) i gregoriańskimi (365.2425
). . Właściwe podejście jest sugerowane w odpowiedzi @Adama RosenfieldaJeśli próbujesz sprawdzić, czy ktoś ma 18 lat, użyj
timedelta
nie będzie działać poprawnie w niektórych skrajnych przypadkach z powodu lat przestępnych. Na przykład osoba urodzona 1 stycznia 2000 r. Skończy 18 lat dokładnie 6575 dni później 1 stycznia 2018 r. (Włączając 5 lat przestępnych), ale osoba urodzona 1 stycznia 2001 r. Skończy 18 lat dokładnie 6574 dni później 1 stycznia, 2019 (w tym 4 lata przestępne). Tak więc, jeśli ktoś ma dokładnie 6574 dni, nie możesz określić, czy ma on 17 czy 18 lat, nie wiedząc trochę więcej o jego dacie urodzenia.Prawidłowym sposobem na to jest obliczenie wieku bezpośrednio na podstawie dat, odejmując dwa lata, a następnie odejmując jeden, jeśli bieżący miesiąc / dzień poprzedza miesiąc / dzień urodzenia.
źródło
Po pierwsze, na najbardziej szczegółowym poziomie problemu nie da się dokładnie rozwiązać. Lata różnią się długością i nie ma jasnego „właściwego wyboru” długości roku.
To powiedziawszy, uzyskaj różnicę w jednostkach „naturalnych” (prawdopodobnie w sekundach) i podziel przez stosunek tych jednostek do lat. Na przykład
...lub cokolwiek. Trzymaj się z dala od miesięcy, ponieważ są one jeszcze słabiej zdefiniowane niż lata.
źródło
Oto zaktualizowana funkcja DOB, która oblicza urodziny w taki sam sposób, jak ludzie:
źródło
Uzyskaj liczbę dni, a następnie podziel przez 365,2425 (średni rok gregoriański) na lata. Podziel przez 30,436875 (średni miesiąc gregoriański) dla miesięcy.
źródło
źródło
Jak dokładna ma być?
td.days / 365.25
zbliży cię do siebie, jeśli martwisz się o lata przestępne.źródło
Jeszcze inna biblioteka innej firmy, o której tutaj nie wspomniano, to mxDateTime (poprzednik zarówno Pythona, jak
datetime
i innej firmytimeutil
), którą można wykorzystać do tego zadania.Wspomniany
yearsago
byłoby:Oczekuje się, że pierwszy parametr będzie
DateTime
instancją.Aby przekonwertować zwykłe
datetime
naDateTime
możesz użyć tego z dokładnością do 1 sekundy):lub to z dokładnością do 1 mikrosekundy:
I tak, dodanie zależności dla tego pojedynczego zadania z pewnością byłoby przesadą w porównaniu nawet z użyciem timeutil (sugerowane przez Ricka Copelanda).
źródło
Ostatecznie masz problem z matematyką. Jeśli co 4 lata mamy dodatkowy dzień, zanurkujmy czas w dniach, a nie 365, ale 365 * 4 + 1, to daje 4 lata. Następnie podziel go ponownie przez 4. timedelta / ((365 * 4) +1) / 4 = timedelta * 4 / (365 * 4 +1)
źródło
To rozwiązanie, które wypracowałem, mam nadzieję, że może pomóc ;-)
źródło
Mimo że ten wątek jest już martwy, czy mogę zasugerować działające rozwiązanie tego samego problemu, z którym miałem do czynienia. Oto on (data to ciąg w formacie dd-mm-rrrr):
źródło
ta funkcja zwraca różnicę w latach między dwiema datami (traktowanymi jako ciągi w formacie ISO, ale można ją łatwo zmodyfikować, aby przyjmować dowolny format)
źródło
Ja proponuję Pyfdate
the poradnik
źródło
To jest kod, który operator Carrousel uruchomił w filmie Logan's Run;)
https://en.wikipedia.org/wiki/Logan%27s_Run_(film)
źródło
Natknąłem się na to pytanie i znalazłem odpowiedź Adamsa, która jest najbardziej pomocna https://stackoverflow.com/a/765862/2964689
Ale nie było przykładu jego metody w Pythonie, ale oto, czego ostatecznie użyłem.
wejście: obiekt datetime
wynik: całkowity wiek w pełnych latach
źródło
Podobało mi się rozwiązanie Johna Mee ze względu na jego prostotę i nie przejmuję się tym, jak 28 lutego lub 1 marca, kiedy nie jest to rok przestępny, określić wiek osób urodzonych 29 lutego. Ale tutaj jest poprawka w jego kodzie co, jak sądzę, odnosi się do skarg:
źródło