|
Himitsu, Sir Rufo und Wolfgang Mix zeigen in diesem Tutorial, wie man das Alter einer Sache oder einer Person fehlerfrei bestimmen kann.
In Datenbanken kommt es häufig vor, dass man zu einer Person das Alter bestimmen muss. Die Funktionen von (nicht nur) Delphi YearsBetween und YearSpan liefern schaltjahresabhängig richtige oder falsche Werte, für die Zeitspanne z.B '01.01.2009' und '01.01.2010' falsche Werte, wie Sir Rufo kürzlich gezeigt hat. Das wird auch klar, wenn man sich die OH von Delphi anschaut:
Zitat:
.. gibt YearsBetween als auch YearSpan eine Näherung zurück, die auf einem Wert von 365,25 Tagen pro Jahr basiert ...
Wenn es um die Bestimmung von ganzzahligen Jahren zwischen 2 Daten geht, hilft nachstehend beschriebener Pseudo-Algorithmus von Wolfgang Mix weiter, der plattformunabhängig fehlerfreie Rückgabewerte liefert. Alternativ kann man auch mit der neu codierten Funktion von YearsBetween von himitsu und Sir Rufo ermitteln. (siehe unten) Wer mit Jahresteilen mit Jahr >= 1 weiterrechnen muss, ist mit himitsus und Sir Rufos Code bestens bedient. Sie zeigen eindrucksvoll, dass ein bisschen mehr Code erforderlich ist, wenn man mit YearsBetween korrekt rechnen will. Der Algorithmus, den Wolfgang Mix hier vorstellt, lässt sich am einfachsten ohne PC am Schreibtisch begreifen: Man nehme ein Blatt Papier und einen Stift und mache folgendes: 1. Schreibe das heutige Datum im Format YYYYMMDD (ohne Trennzeichen) auf. 2. Schreibe darunter Deinen Geburtstag im selben Format. 3. Bilde die Differenz dieser beiden LongInt-Zahlen. 4. Die Ziffern 1-4 (meist nur 3 und 4) ergeben das Alter in ganzen Jahren. Führende Nullen weglassen! Dieser Algorithmus funktioniert plattformunabhängig in jeder Programmier-Sprache und wurde von Wolfgang Mix erstmals 2/1992 in DOS International (heute PC-Magazin) vorgestellt, ist aber im WEB nicht mehr greifbar gewesen. Beispiel 1: Das Systemdatum sei 24.1.2010 und mein Geburtstag 25.1.1950 1. 20100124 2. 19500125 ________ 3./4. 00599999 Ziffern 3 und 4 ergeben das Alter: 59 Beispiel 2: Einen Tag später ergibt sich folgendes: 1. 20100125 2. 19500125 ________ 3./4. 00600000 Ziffern 3 und 4 ergeben das Alter: 60 Vorteil des Verfahrens: In den meisten Programmiersprachen ist dieser Pseudocode als Einzeiler codierbar... Außerdem braucht mach sich keine Gedanken um Schaltjahresregeln zu machen. Das Ganze funktioniert sogar, wenn etwas älter als 1000 Jahre wird. Zu beachten ist allerdings, dass ein Datum zuerst in seine Einzelkomponenten zerlegt werden muss oder in diesen vorliegen muss, damit das Verfahren angewendet werden kann. Zur Umsetzung in Delphi-Code werden hier ein paar Beispiele angefügt, die hier in der DP entstanden sind.
Delphi-Quellcode:
//DeddyH – Delphi - PRAXiS
function Age(BirthDate: TDate): integer; var y1,y2,m1,m2,d1,d2: Word; begin SysUtils.DecodeDate(date,y1,m1,d1); SysUtils.DecodeDate(BirthDate,y2,m2,d2); Result := ((y1 * 10000 + m1 * 100 + d1) - (y2 * 10000 + m2 * 100 + d2)) div 10000; end; Für Datenbankanwendungen hat Omata folgende Lösung zur Umsetzung des Pseudocodes beigetragen:
SQL-Code:
SELECT ( ( YEAR(GETDATE()) * 10000
+ MONTH(GETDATE()) * 100 + DAY(GETDATE())) - ( YEAR(geburtsdatum) * 10000 + MONTH(geburtsdatum) * 100 + DAY(geburtsdatum))) / 10000 AS "alter" FROM tabelle MySQL:
SQL-Code:
SELECT ( ( YEAR(CURRENT_DATE()) * 10000
+ MONTH(CURRENT_DATE()) * 100 + DAY(CURRENT_DATE())) - ( YEAR(geburtsdatum) * 10000 + MONTH(geburtsdatum) * 100 + DAY(geburtsdatum))) DIV 10000 AS "alter" FROM tabelle Firebird:
SQL-Code:
SELECT ( ( EXTRACT(YEAR FROM CURRENT_DATE) * 10000
+ EXTRACT(MONTH FROM CURRENT_DATE) * 100 + EXTRACT(DAY FROM CURRENT_DATE)) - ( EXTRACT(YEAR FROM geburtsdatum) * 10000 + EXTRACT(MONTH FROM geburtsdatum) * 100 + EXTRACT(DAY FROM geburtsdatum))) / 10000 AS "alter" FROM tabelle Shmia zeigt hier, wie man Aufgabe für einen binär rechnenden Computer optimiert.
Delphi-Quellcode:
Erklärung:
function Age(BirthDate: TDate): integer;
var y1,y2,m1,m2,d1,d2: Word; begin SysUtils.DecodeDate(date,y1,m1,d1); SysUtils.DecodeDate(BirthDate,y2,m2,d2); { Result := ((y1 * 10000 + m1 * 100 + d1) - (y2 * 10000 + m2 * 100 + d2)) div 10000; } Result := (((y1 shl 4 or m1) shl 5 or d1) - ((y2 shl 4 or m2) shl 5 or d2)) shr 9; end; ein Monat hat maximal 31 Tage - also darf man auch mit 32 anstatt mit 100 multiplizieren. Das entspricht einem Linksshift um 5 Bits. Ein Jahr hat 12 Monate. Also darf man auch mit 16 multiplizieren. Das entspricht einem Linksshift um 4 Bits. Der Rechtsshift um 9 macht alles wieder rückgängig und lässt dabei den Rest wie bei einer Division verschwinden Himitsu und Sir Rufo haben die Funktion YearsBetween neu programmiert, damit man nicht nur mit ganzen Jahren, sondern auch mit Jahresteilen richtig rechnen kann:
Delphi-Quellcode:
//himitsu - Delphi-PRAXiS
// -------------------------------------------------------------------------- // Tauscht die übergebenen Datumsangaben, damit ANow <= AThen // -------------------------------------------------------------------------- procedure CheckedSwap( Var ANow, AThen : TDateTime ); Inline; Var Temp : TDateTime; Begin If ANow <= AThen Then Exit; Temp := ANow; ANow := AThen; AThen := Temp; End; ///himitsu und Sir Rufo - Delphi - PRAXiS // -------------------------------------------------------------------------- // Ermittelt die Jahre zwischen zwei Datumswerten // -------------------------------------------------------------------------- function YearsBetween(ANow: TDateTime; AThen: TDateTime): Integer; var Yn, Yt, Mn, Mt, Dn, Dt: Word; Begin CheckedSwap(ANow, AThen); DecodeDate(ANow, Yn, Mn, Dn); DecodeDate(AThen, Yt, Mt, Dt); Result := Yt - Yn; If (Mt < Mn) or ((Mt = Mn) and ((Dt < Dn))) Then Dec(Result); End; Beispiel 1: AThen = 25.08.2002 > ANow = 21.08.2008 Result = 2008 - 2002 Result = 6 Jahre (+4 Tage) Anders herum: AThen = 21.08.2002 > ANow = 25.08.2008 Result = 2008 - 2002 Result = 6 Jahre (-4 Tage) 8=8 und 21<25 ... also Monat ist gleich und Tag ist kleiner bedeutet also, daß zwischen 25.08. und 21.08. kein ganzes Jahr liegt, weswegen dieses unvollständige Jahr vom Ergebnis abgezogen wird if ... or ((8 = 8) and (21 < 25)) then Result := Result - 1; Result = 5 ganze Jahre Dieses fällt ganz besonders bei extremeren Werten auf. Beispiel 2: ANow = 1.12.2002 > AThen = 02.01.2004 Result = 2004 - 2002 = 2 if (1 < 12) or ... then Result := Result - 1; Result = nur 1 ganzes Jahr Unterschied (genauer gesagt 1 Jahr und 2 Tage) Beispiel 3: Delphis YearsBetween macht Fehler z.B für ANow = 01.01.2009 AThen = 01.01.2010 Result = 0 Jahre, richtig wäre 1 Jahr |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |