Ich muss überprüfen, ob seit einem bestimmten Datum einige Jahre vergangen sind. Zur Zeit muß ich timedelta
aus datetime
Modul und ich weiß nicht , wie es zu Jahr konvertieren.
Ich muss überprüfen, ob seit einem bestimmten Datum einige Jahre vergangen sind. Zur Zeit muß ich timedelta
aus datetime
Modul und ich weiß nicht , wie es zu Jahr konvertieren.
Antworten:
Sie brauchen mehr als eine timedelta
, um zu sagen, wie viele Jahre vergangen sind; Sie müssen auch das Anfangs- (oder End-) Datum kennen. (Es ist eine Schaltjahrsache.)
Am besten verwenden Sie das dateutil.relativedelta
Objekt , aber das ist ein Modul eines Drittanbieters. Wenn Sie wissen möchten, datetime
dass n
Jahre von einem bestimmten Datum an vergangen sind (standardmäßig jetzt), können Sie Folgendes tun:
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)
Wenn Sie lieber bei der Standardbibliothek bleiben möchten, ist die Antwort etwas komplexer:
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)
Wenn es 2/29 ist und es vor 18 Jahren keine 2/29 gab, gibt diese Funktion 2/28 zurück. Wenn Sie lieber 3/1 zurückgeben möchten, ändern Sie einfach die letzte return
Anweisung in read ::
return from_date.replace(month=3, day=1,
year=from_date.year-years)
Ihre Frage besagte ursprünglich, dass Sie wissen wollten, wie viele Jahre seit einem bestimmten Datum vergangen sind. Angenommen, Sie möchten eine ganzzahlige Anzahl von Jahren, können Sie anhand von 365,25 Tagen pro Jahr raten und dann mit einer der yearsago
oben definierten Funktionen prüfen :
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()
) eingeführte Unterschied größer als der Unterschied zwischen durchschnittlichen julianischen ( 365.25
) und gregorianischen ( 365.2425
) Jahren. . Der richtige Ansatz wird in @Adam Rosenfields Antwort vorgeschlagen
Wenn Sie versuchen zu überprüfen, ob jemand 18 Jahre alt ist, timedelta
funktioniert die Verwendung in einigen Randfällen aufgrund von Schaltjahren nicht richtig. Zum Beispiel wird jemand, der am 1. Januar 2000 geboren wurde, am 1. Januar 2018 genau 6575 Tage später 18 Jahre alt (einschließlich 5 Schaltjahre), aber jemand, der am 1. Januar 2001 geboren wurde, wird am 1. Januar genau 6574 Tage später 18 Jahre alt. 2019 (4 Schaltjahre inklusive). Wenn also jemand genau 6574 Tage alt ist, können Sie nicht feststellen, ob er 17 oder 18 Jahre alt ist, ohne ein wenig mehr Informationen über sein Geburtsdatum zu kennen.
Der richtige Weg, dies zu tun, besteht darin, das Alter direkt von den Daten zu berechnen, indem die zwei Jahre subtrahiert werden und dann eines subtrahiert wird, wenn der aktuelle Monat / Tag vor dem Geburtsmonat / -tag liegt.
Zunächst einmal kann das Problem auf der detailliertesten Ebene nicht genau gelöst werden. Die Jahre variieren in der Länge, und es gibt keine klare "richtige Wahl" für die Jahreslänge.
Das heißt, erhalten Sie den Unterschied in den Einheiten, die "natürlich" sind (wahrscheinlich Sekunden), und dividieren Sie durch das Verhältnis zwischen dieser und den Jahren. Z.B
delta_in_days / (365.25)
delta_in_seconds / (365.25*24*60*60)
...oder Wasauchimmer. Halten Sie sich von Monaten fern, da sie noch weniger gut definiert sind als Jahre.
Hier ist eine aktualisierte DOB-Funktion, die Geburtstage genauso berechnet wie Menschen:
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
Wie genau muss es sein? td.days / 365.25
Sie werden ziemlich nah dran sein, wenn Sie sich Sorgen um Schaltjahre machen.
Eine weitere hier nicht erwähnte Drittanbieter-Bibliothek ist mxDateTime (Vorgänger von Python datetime
und Drittanbieter timeutil
), die für diese Aufgabe verwendet werden könnte.
Das vorgenannte yearsago
wäre:
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)
Der erste Parameter wird voraussichtlich eine DateTime
Instanz sein.
Um normal datetime
zu konvertieren , können DateTime
Sie dies für eine Genauigkeit von 1 Sekunde verwenden):
def DT_from_dt_s(t):
return DT.DateTimeFromTicks(time.mktime(t.timetuple()))
oder dies für 1 Mikrosekunden Genauigkeit:
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)
Und ja, das Hinzufügen der Abhängigkeit für diese einzelne Aufgabe wäre definitiv ein Overkill im Vergleich zur Verwendung von timeutil (vorgeschlagen von Rick Copeland).
Am Ende haben Sie ein mathematisches Problem. Wenn wir alle 4 Jahre einen zusätzlichen Tag haben, können wir das Zeitdelta in Tagen tauchen, nicht um 365, sondern um 365 * 4 + 1, das ergibt einen Betrag von 4 Jahren. Teilen Sie es dann erneut durch 4. timedelta / ((365 * 4) +1) / 4 = timedelta * 4 / (365 * 4 +1)
Dies ist die Lösung, die ich ausgearbeitet habe, ich hoffe, sie kann helfen ;-)
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
Auch wenn dieser Thread bereits tot ist, könnte ich eine funktionierende Lösung für genau das Problem vorschlagen, mit dem ich konfrontiert war. Hier ist es (Datum ist eine Zeichenfolge im Format TT-MM-JJJJ):
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
Diese Funktion gibt die Differenz in Jahren zwischen zwei Daten zurück (als Zeichenfolgen im ISO-Format verwendet, kann jedoch leicht geändert werden, um jedes Format anzunehmen).
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
Ich werde Pyfdate vorschlagen
Was ist Pyfdate?
Angesichts des Ziels von Python, eine leistungsstarke und benutzerfreundliche Skriptsprache zu sein, sind die Funktionen zum Arbeiten mit Datum und Uhrzeit nicht so benutzerfreundlich, wie sie sein sollten. Der Zweck von pyfdate besteht darin, diese Situation zu beheben, indem Funktionen für die Arbeit mit Datums- und Uhrzeitangaben bereitgestellt werden, die genauso leistungsfähig und benutzerfreundlich sind wie der Rest von Python.
das 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()
Dies ist der Code, den der Carrousel-Operator in Logans Run-Film ausgeführt hat;)
Ich bin auf diese Frage gestoßen und habe festgestellt, dass Adams die hilfreichste Antwort auf https://stackoverflow.com/a/765862/2964689 ist
Aber es gab kein Python-Beispiel für seine Methode, aber hier ist, was ich letztendlich verwendet habe.
Eingabe: Datum / Uhrzeit-Objekt
Ausgabe: ganzzahliges Alter in ganzen Jahren
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
Ich mochte John Mees Lösung wegen ihrer Einfachheit, und ich bin nicht so besorgt darüber, wie man am 28. Februar oder 1. März, wenn es kein Schaltjahr ist, das Alter der am 29. Februar geborenen Menschen bestimmen kann. Aber hier ist eine Optimierung seines Codes was meiner Meinung nach die Beschwerden anspricht:
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