Necesito verificar si han pasado varios años desde alguna fecha. He actualmente tiene timedelta
de datetime
módulo y no sé cómo convertir al año.
Necesito verificar si han pasado varios años desde alguna fecha. He actualmente tiene timedelta
de datetime
módulo y no sé cómo convertir al año.
Respuestas:
Necesita más que un timedelta
para saber cuántos años han pasado; También necesita saber la fecha de inicio (o finalización). (Es un año bisiesto).
Su mejor opción es usar el dateutil.relativedelta
objeto , pero ese es un módulo de terceros. Si desea saber datetime
que pasaron n
años desde alguna fecha (por defecto en este momento), puede hacer lo siguiente:
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)
Si prefiere seguir con la biblioteca estándar, la respuesta es un poco más compleja:
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)
Si es 2/29, y hace 18 años no había 2/29, esta función devolverá 2/28. Si prefiere devolver 3/1, simplemente cambie la última return
instrucción para leer ::
return from_date.replace(month=3, day=1,
year=from_date.year-years)
Su pregunta originalmente decía que quería saber cuántos años han pasado desde alguna fecha. Suponiendo que desea un número entero de años, puede adivinar en base a 365.25 días por año y luego verificar usando cualquiera de las yearsago
funciones definidas anteriormente ::
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()
) es mayor que la diferencia entre los años promedio de Julian ( 365.25
) y Gregorian ( 365.2425
). . El enfoque correcto se sugiere en la respuesta de @Adam Rosenfield
Si está tratando de verificar si alguien tiene 18 años de edad, el uso timedelta
no funcionará correctamente en algunos casos extremos debido a los años bisiestos. Por ejemplo, alguien nacido el 1 de enero de 2000 cumplirá 18 años exactamente 6575 días después el 1 de enero de 2018 (5 años bisiestos incluidos), pero alguien nacido el 1 de enero de 2001 cumplirá 18 años exactamente 6574 días después el 1 de enero, 2019 (4 años bisiestos incluidos). Por lo tanto, si alguien tiene exactamente 6574 días, no puede determinar si tiene 17 o 18 años sin conocer un poco más de información sobre su fecha de nacimiento.
La forma correcta de hacer esto es calcular la edad directamente de las fechas, restando los dos años, y luego restando uno si el mes / día actual precede al mes / día de nacimiento.
En primer lugar, en el nivel más detallado, el problema no puede resolverse exactamente. Los años varían en duración, y no hay una clara "elección correcta" para la duración del año.
Dicho esto, obtenga la diferencia en cualquier unidad que sea "natural" (probablemente segundos) y divida por la relación entre eso y años. P.ej
delta_in_days / (365.25)
delta_in_seconds / (365.25*24*60*60)
...o lo que sea. Manténgase alejado de los meses, ya que están incluso menos definidos que años.
Aquí hay una función DOB actualizada, que calcula los cumpleaños de la misma manera que los humanos:
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
¿Qué tan exacto necesitas que sea? td.days / 365.25
te acercará bastante, si te preocupan los años bisiestos.
Sin embargo, otra biblioteca de terceros que no se menciona aquí es mxDateTime (predecesora de python datetime
y de terceros timeutil
) podría usarse para esta tarea.
Lo anterior yearsago
sería:
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)
Se espera que el primer parámetro sea una DateTime
instancia.
Para convertir ordinario datetime
a DateTime
podría usar esto para precisión de 1 segundo):
def DT_from_dt_s(t):
return DT.DateTimeFromTicks(time.mktime(t.timetuple()))
o esto para 1 microsegundo de precisión:
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)
Y sí, agregar la dependencia para esta tarea en cuestión definitivamente sería una exageración en comparación incluso con el uso de timeutil (sugerido por Rick Copeland).
Al final, lo que tienes es un problema de matemáticas. Si cada 4 años tenemos un día extra, dejemos el tiempo delta en días, no en 365 sino 365 * 4 + 1, eso le daría la cantidad de 4 años. Luego divídalo nuevamente por 4. timedelta / ((365 * 4) +1) / 4 = timedelta * 4 / (365 * 4 +1)
Esta es la solución que resolví, espero que pueda ayudar ;-)
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
Aunque este hilo ya está muerto, ¿puedo sugerir una solución de trabajo para este mismo problema que estaba enfrentando? Aquí está (la fecha es una cadena en el formato dd-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
Esta función devuelve la diferencia en años entre dos fechas (tomadas como cadenas en formato ISO, pero puede modificarse fácilmente para tomar en cualquier 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
Voy a sugerir Pyfdate
¿Qué es pyfdate?
Dado el objetivo de Python de ser un lenguaje de secuencias de comandos potente y fácil de usar, sus funciones para trabajar con fechas y horas no son tan fáciles de usar como deberían ser. El propósito de pyfdate es remediar esa situación al proporcionar funciones para trabajar con fechas y horas que son tan poderosas y fáciles de usar como el resto de Python.
el 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()
Este es el código que el operador Carrousel estaba ejecutando en la película Logan's Run;)
Me encontré con esta pregunta y encontré que Adams responde la más útil https://stackoverflow.com/a/765862/2964689
Pero no hubo un ejemplo de su método en Python, pero esto es lo que terminé usando.
entrada: objeto de fecha y hora
salida: edad entera en años enteros
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
Me gustó la solución de John Mee por su simplicidad, y no me preocupa cómo, el 28 de febrero o el 1 de marzo, cuando no es un año bisiesto, determinar la edad de las personas nacidas el 29 de febrero. Pero aquí hay un ajuste de su código que creo aborda las quejas:
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