Devo verificare se sono trascorsi alcuni anni da una certa data. Attualmente ho timedelta
da datetime
moduli e non so come convertire a anni.
Devo verificare se sono trascorsi alcuni anni da una certa data. Attualmente ho timedelta
da datetime
moduli e non so come convertire a anni.
Risposte:
Ti serve più di un timedelta
per dire quanti anni sono passati; devi anche conoscere la data di inizio (o fine). (È un anno bisestile.)
La soluzione migliore è utilizzare l' dateutil.relativedelta
oggetto , ma si tratta di un modulo di terze parti. Se vuoi sapere datetime
che sono n
trascorsi anni da qualche data (il default è adesso), puoi fare quanto segue:
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)
Se preferisci attenersi alla libreria standard, la risposta è un po 'più complessa:
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)
Se è il 29/02, e 18 anni fa non c'era il 29/02, questa funzione restituirà il 28/02. Se preferisci restituire 3/1, modifica l'ultima return
istruzione in read ::
return from_date.replace(month=3, day=1,
year=from_date.year-years)
Inizialmente la tua domanda diceva che volevi sapere da quanti anni è passato un po 'di tempo. Supponendo che desideri un numero intero di anni, puoi indovinare in base a 365,25 giorni all'anno e quindi verificare utilizzando una delle yearsago
funzioni sopra definite:
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
datetime.now()
) è maggiore della differenza tra gli anni medi di Julian ( 365.25
) e Gregorian ( 365.2425
). . L'approccio corretto è suggerito nella risposta di @Adam Rosenfield
Se stai cercando di verificare se qualcuno ha 18 anni, l'utilizzo timedelta
non funzionerà correttamente su alcuni casi limite a causa degli anni bisestili. Ad esempio, qualcuno nato il 1 ° gennaio 2000 compirà 18 anni esattamente 6575 giorni dopo il 1 ° gennaio 2018 (inclusi 5 anni bisestili), ma qualcuno nato il 1 ° gennaio 2001 compirà 18 anni esattamente 6574 giorni dopo il 1 ° gennaio, 2019 (4 anni bisestili inclusi). Pertanto, se qualcuno ha esattamente 6574 giorni, non puoi determinare se ha 17 o 18 anni senza conoscere un po 'più di informazioni sulla sua data di nascita.
Il modo corretto per farlo è calcolare l'età direttamente dalle date, sottraendo i due anni e quindi sottraendo uno se il mese / giorno corrente precede il mese / giorno di nascita.
Innanzitutto, al livello più dettagliato, il problema non può essere risolto esattamente. Gli anni variano in lunghezza e non esiste una chiara "scelta giusta" per la durata dell'anno.
Detto questo, ottieni la differenza in qualunque unità sia "naturale" (probabilmente secondi) e dividi per il rapporto tra quello e gli anni. Per esempio
delta_in_days / (365.25)
delta_in_seconds / (365.25*24*60*60)
... o qualunque altra cosa. Stare lontano da mesi, poiché sono ancora meno ben definiti degli anni.
Ecco una funzione DOB aggiornata, che calcola i compleanni allo stesso modo degli umani:
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)))
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
Quanto esatto ti serve per essere? td.days / 365.25
ti avvicinerà molto, se sei preoccupato per gli anni bisestili.
Ancora un'altra libreria di terze parti non menzionata qui è mxDateTime (predecessore sia di Python datetime
che di terze parti timeutil
) potrebbe essere usato per questo compito.
Quanto sopra yearsago
sarebbe:
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)
Il primo parametro dovrebbe essere DateTime
un'istanza.
Per convertire da ordinario datetime
aDateTime
te potresti usare questo per una precisione di 1 secondo):
def DT_from_dt_s(t):
return DT.DateTimeFromTicks(time.mktime(t.timetuple()))
o questo per 1 microsecondo di precisione:
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)
E sì, aggiungere la dipendenza per questa singola attività in questione sarebbe sicuramente eccessivo rispetto all'uso di timeutil (suggerito da Rick Copeland).
Alla fine quello che hai è un problema di matematica. Se ogni 4 anni abbiamo un giorno in più permettiamo di immergere la timedelta in giorni, non per 365 ma 365 * 4 + 1, che ti darebbe la quantità di 4 anni. Quindi dividerlo di nuovo per 4. timedelta / ((365 * 4) +1) / 4 = timedelta * 4 / (365 * 4 +1)
Questa è la soluzione che ho elaborato, spero possa aiutare ;-)
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
Anche se questo thread è già morto, potrei suggerire una soluzione funzionante per questo stesso problema che stavo affrontando. Eccola (la data è una stringa nel formato gg-mm-aaaa):
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
questa funzione restituisce la differenza in anni tra due date (prese come stringhe in formato ISO, ma può essere facilmente modificata per assumere qualsiasi formato)
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
Suggerirò Pyfdate
Che cos'è pyfdate?
Dato l'obiettivo di Python di essere un linguaggio di scripting potente e facile da usare, le sue funzionalità per lavorare con date e orari non sono così facili da usare come dovrebbero essere. Lo scopo di pyfdate è di rimediare a tale situazione fornendo funzionalità per lavorare con date e orari che sono potenti e facili da usare come il resto di Python.
il tutorial
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()
Questo è il codice che l'operatore Carrousel stava eseguendo nel film di Logan's Run;)
Mi sono imbattuto in questa domanda e ho trovato Adams rispondere al più utile https://stackoverflow.com/a/765862/2964689
Ma non c'era alcun esempio di pitone del suo metodo, ma ecco quello che ho finito per usare.
input: oggetto datetime
output: età intera in anni interi
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
Mi è piaciuta la soluzione di John Mee per la sua semplicità, e non sono così preoccupato di come, il 28 febbraio o il 1 marzo, quando non è un anno bisestile, determinare l'età delle persone nate il 29 febbraio. Ma ecco una modifica del suo codice che penso affronti i reclami:
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