Posts mit dem Label Datumsfunktionen werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Datumsfunktionen werden angezeigt. Alle Posts anzeigen

Montag, 7. Mai 2012

Datumsspielereien (Teil 9) / Date gadgets (Part 9)

Irgendwie sind Datumberechnungen ein Faß ohne Boden. Nach Teil 4 der Datumsspielereien war ich bereits der Meinung, nichts neues mehr zu diesem Thema zu finden. Aber irgendwie poppt in unregelmäßigen Abständen immer wieder eine neue Frage dazu auf.

Aktuell dreht es sich darum herauszufinden, wieviele Jahre, Monate und Tage zwischen zwei Datumswerten liegen.

Im folgenden Mustercode erledigt diese Aufgabe eine kleine Schleife die zunächst die Jahre, danach die Monate und letztendlich die Tage aufaddiert und uns so den genauen Zeitraum übermittelt.

Somehow, date calculations are a bottomless pit. With Part 4 of my date gadgets I was sure to find nothing new on this subject. But somehow every now and then, a new question pops up.

This post is about finding out the period between two dates.

The following sample code does this by using a loop that first adds years, then months and finally the days to give us the exact time between the given date values.


LOCAL ldDate1 AS Date, ldDate2 AS Date, liYear AS Integer, liMonth AS Integer, liDay AS Integer, llStatus as Boolean
ldDate1 = {28.8.1961}
ldDate2 = DATE()
STORE 0 TO liYear, liMonth, liDay

llStatus = GetPeriodBetweenDates( ldDate1 , ldDate2 , @liYear , @liMonth , @liDay )

CLEAR 
IF llStatus = .T.
    ? [Zeitraum zwischen ] + DTOC( ldDate1 ) + [ und ] + DTOC( ldDate2 )
    ?  TRANSFORM( liYear )  + [ Jahr]  + IIF( liYear  <> 1 , [e ] , [ ] )
    ?? TRANSFORM( liMonth ) + [ Monat] + IIF( liMonth <> 1 , [e ] , [ ] )
    ?? TRANSFORM( liDay )   + [ Tag]   + IIF( liDay   <> 1 , [e ] , [ ] )
ENDIF 

FUNCTION GetPeriodBetweenDates as Boolean

    * // Parameter 3-5 als Referenz übergeben!
    * // Parameters 3-5 by reference
    LPARAMETERS vDate1 as Date, vDate2 as Date, vYear as Integer, vMonth as Integer, vDay as Integer

    LOCAL ldDate1 as Date, ldDate2 as Date
    ldDate1 = IIF( vDate1 > vDate2 , vDate2 , vDate1 )
    ldDate2 = IIF( vDate1 > vDate2 , vDate1 , vDate2 )

    STORE 0 TO vYear , vMonth , vDay

    DO WHILE ldDate1 < ldDate2
        DO CASE 
        CASE GOMONTH( ldDate1 , 12 ) < ldDate2
            vYear = vYear + 1 
            ldDate1 = GOMONTH( ldDate1 , 12 )
        CASE GOMONTH( ldDate1 , 1 ) < ldDate2
            vMonth = vMonth + 1 
            ldDate1 = GOMONTH( ldDate1 , 1 )
        OTHERWISE 
            vDay = vDay + 1 
            ldDate1 = ldDate1 + 1 
        ENDCASE 
    ENDDO 

    RETURN .T.

ENDFUNC 

Mittwoch, 21. Dezember 2011

Datumsspielereien (Teil 8) / Date gadgets (Part 8)

Die TIME() Funktion von Visual Foxpro liefert uns eine Uhrzeit als Characterstring. Wenn wir zu dieser Zeit jedoch Stunden, Minuten oder Sekunden hinzuaddieren möchten, dann ist das bei einem String eine mühsame Arbeit.

Anstatt mit TIME() sollten wir für Berechnungen immer mit DATETIME() arbeiten. Hier steht uns neben dem Datum auch die Uhrzeit für Berechnungen zur Verfügung. Allerdings wird ein DATETIME() + 1 ein gänzlich anderes Ergebnis liefern als DATE() + 1. Wenn DATE() grundsätzlich auf Tagesbasis seine Berechnungen durchführt, so reagiert DATETIME() auf Sekundenbasis.
Um mit DATETIME() also Stunden oder Minuten zu berechnen müssen wir entweder x * 60 * 60 für Stunden oder x * 60 für Minuten eingeben.

Zur Extraktion der Uhrzeit vom Datum/Zeit-Wert steht uns dann im Anschluß die Funktion TTOC() zur Verfügung. Wichtig hierbei ist der zweite Parameterwert den wir zwingend auf 2 setzen müssen.

CLEAR
ltDatetime = DATETIME()
? ltDatetime
? CalcTime( 5 , 0 , 0 , ltDatetime )
? CalcTime( 0 , 5 , 0 , ltDatetime )
? CalcTime( 0 , 0 , 5 , ltDatetime )
? CalcTime( 5 , 5 , 5 , ltDatetime )

? CalcTime( -5 )


FUNCTION CalcTime as String
LPARAMETERS vHours as Integer, vMinutes as Integer, vSeconds as Integer, vDatetime as Datetime

    vHours      = EVL( vHours    , 0 )
    vMinutes    = EVL( vMinutes  , 0 )
    vSeconds    = EVL( vSeconds  , 0 )
    vDatetime   = EVL( vDatetime , DATETIME() )

    vDatetime = vDatetime + ( vHours   * 60 * 60 )
    vDatetime = vDatetime + ( vMinutes * 60 )
    vDatetime = vDatetime + ( vSeconds )

    RETURN TTOC( vDatetime , 2 )

ENDFUNC 

Freitag, 25. November 2011

Datumsspielereien (Teil 7) / Date gadgets (Part 7)

Im Folgenden eine kleine Abwandlung der Routine aus Teil 6 in der es um die Berechnung des letzten Sonntags eines Monats ging.
Wollen wir nicht den letzten Sonntag sondern einfach nur den letzten Tag des Monats berechnen, so ist es am einfachsten zunächst das Datum des 1. Tages des Folgemonats zu berechnen und davon einfach einen Tag abzuziehen. Ähnlich funktioniert auch die Methode aus Teil 6.
Hier nun der Mustercode:

CLEAR 

?GetLastDayOfMonth( DATE() )
?GetLastDayOfMonth( {12.02.2012} )

FUNCTION GetLastDayOfMonth as Date 
LPARAMETERS vDate as Date

    RETURN DATE( YEAR( GOMONTH( vDate , 1 ) ) , MONTH( GOMONTH( vDate , 1 ) ) , 1 ) - 1

ENDFUNC 

Freitag, 29. Januar 2010

Datumsspielereien (Teil 6) / Date gadgets (Part 6)

Datumsberechnungen und kein Ende :-)

Vor ein paar Tagen fiel mir mal wieder das leidige Thema MESZ ein. Ähnlich wie bei Ostern hatte ich mir nie wirklich Gedanken darum gemacht, wann denn nun das nächste Mal die Uhrzeit umgestellt wird. Windows wird es schon richten und ich würde mich wieder zwei Wochen lang mit der Zeitverschiebung rumschlagen... ;-)

Ein kurzer Blick in die Wikipedia und schon wußte ich: Es sind (mittlerweile europaweit) zwei Fixtermine, nämlich jeweils der letzte Sonntag im März und im Oktober. Und schon überlegte ich, wie man diese beiden Tage wohl im Fux berechnet...

Im folgenden also der kurze Mustercode auf Basis einer kleinen Funktion:

CLEAR
?GetLastSundayOfMonth({15/03/2010})
?GetLastSundayOfMonth()

FUNCTION GetLastSundayOfMonth as Date
LPARAMETERS vDate as Date

    * // Sicherstellen, dass wir ein Datum  
    * // zur Berechnung verfügbar haben      
    vDate = EVL(vDate,DATE())
    * // nun setzen wir das übergebene Datum
    * // auf den 1. Tag des Folgemonats     
    * // Korrektur gem. Gustavs Hinweis, da mein Originalcode
    * // einen Jahreswechsel zum Folgemonat nicht berücksichtigte
    vDate = DATE(YEAR(GOMONTH(vDate,1)),MONTH(GOMONTH(vDate,1)),1)
    * // Abschliessend geben wir das Datum  
    * // um den Wochentag reduziert zurück.  
    * // Dies ergibt automatisch den voran-  
    * // gegangenen Sonntag.              
    RETURN vDate - DOW(vDate,2)

ENDFUNC

Freitag, 11. Dezember 2009

Datumsspielereien (Teil 5) / Date gadgets (Part 5)

Heute gibt es eigentlich nur einen kleinen Nachtrag.

Im 4. Teil der Datumsspielereien drehte es sich u. a. darum, wie wir die korrekte Kalenderwoche berechnen. Der umgekehrte Weg, aus einer Kalenderwoche wieder ein Datum zu generieren fehlte allerdings.

Wenn wir ein solches Datum berechnen sollen, dann müssen wir uns auf einen von sieben Tagen der Woche einigen. Der Einfachheit halber habe ich in der folgenden Beispielfunktion den Wochenbegin (=Montag) gewählt.

Die Funktion GetMondayFromCalWeek() erwartet maximal 2 Parameter. Wird kein zweiter Parameter (=Jahr) übergeben, so erfolgt die Datumsberechnung auf dem aktuellen Kalenderjahr sowie der als Parameter 1 übergebenen Kalenderwoche.

CLEAR
?GetMondayFromCalWeek(51)        && Für 2009: 14.12.2009
?GetMondayFromCalWeek(4,2010)    &&           25.01.2010

FUNCTION GetMondayFromCalWeek as Date
LPARAMETERS vWeek as Integer, vYear as Integer
   
    LOCAL ldDate as Date
   
    * // Wenn kein Jahr übergeben wurde, dann arbeiten wir mit dem aktuellen
    m.vYear    = IIF ( VARTYPE ( m.vYear ) <> [N],YEAR ( DATE () ) ,m.vYear )
    * // der 1.1. des gewählten Jahres stellt die Basis für die Berechnung   
    ldDate    = CTOD ( [01.01.] + ALLTRIM ( STR ( m.vYear ) ) )
    * // Wenn der 01.01. in der 1. Kalenderwoche liegt, dann ist alles gut,   
    * // andernfalls müssen wir 7 Tage hinzuaddieren.                       
    ldDate    = IIF ( WEEK ( ldDate,2,2 ) <> 1,ldDate + 7,ldDate )
    * // Den Montag der Woche des Datums berechnen und die Anzahl der Wochen
    * // hinzuaddieren. Dies ergibt den Montag der übergebenen Kalenderwoche
    RETURN ldDate - ( DOW ( ldDate,2 ) - 1 ) + ( ( m.vWeek - 1 ) * 7 )

ENDFUNC

Freitag, 24. Juli 2009

Datumsspielereien (Teil 4) / Date gadgets (Part 4)

Bereits in einigen früheren Postings (Datumsspielereien Teil 1-3) waren Datumswerte ein Thema. In diesem Posting dreht es sich jedoch nicht um Feiertage sondern um die Berechnung spezieller Tage. Insbesondere die aktuelle Woche des Monats, die Kalenderwoche sowie der Montag der Woche. Zur Berechnung des Monatswoche benötigen wir drei Funktionen: CEILING(), DOW() und DAY(). CEILING gibt die nächst höhere Ganzzahl zurück.
STORE 10.1 TO num1
STORE -10.9 TO num2
? CEILING(num1)  && zeigt 11
? CEILING(num2)  && zeigt -10
? CEILING(10.0)  && zeigt 10
? CEILING(-10.0) && zeigt -10
DOW liefert einen numerischen Tag-der-Woche Wert auf Basis eines Datums. Hierbei ist jedoch der 2. Parameter zu beachten, in dem der Erste Tag der Woche definiert wird. Da unsere Woche üblicherweise mit einem Montag beginnt, ist als Wert für den 2. Parameter zwingend eine 2 (-> Montag = Wochenbeginn) zu setzen.
? DOW(DATE(),2)    && zeigt beim 24.07.2009 den Wert 5
DAY wiederum extrahiert von einem Datumwert den Tagesblock.
? DAY(DATE())    && zeigt beim 24.07.2009 den Wert 24
FUNCTION WeekOfMonth as Integer
LPARAMETERS vDate as Date

    * // Woche des Monats bestimmen
    RETURN ( CEILING( ( DAY( m.vDate ) + DOW( ( m.vDate ) - DAY( m.vDate ) + 1, 2 )  - 1 ) / 7 ) )

ENDFUNC
Die Berechnung der Kalenderwoche gestaltet sich da schon um einiges einfacher. Die Wochenbestimmung hängt von zwei Grundeinstellungen ab, die der WEEK()-Funktion als Parameter 2 und 3 übergeben werden. - Parameter 2 definiert die Berechnung der ersten Woche des Jahres - Parameter 3 definiert den Wochenanfang und entspricht dem 2. Parameter von DOW()
FUNCTION WeekOfYear as Integer
LPARAMETERS vDate as Date

    * // Woche des Jahres bestimmen
    * // Parameter 2: Wert = 2
    * //              Die längere Hälfte der ersten Woche
    * //              (4 Tage) definiert die Jahreszugehörigkeit
    * // Parameter 3: Wert = 2
    * //              Montag gilt als der erste Tage der Woche
    RETURN ( WEEK( m.vDate, 2, 2 ) )
  
ENDFUNC
Zuletzt kommen wir zur Funktion zur Berechnung des Montags einer Woche. Auch in dieser Funktion wird mit DOW() gearbeitet, und wie bei den vorherigen Einsätzen wird der 2. Parameter wieder auf den Wert 2 gesetzt wird.
FUNCTION MondayOfWeek as Date
LPARAMETERS vDate as Date

    * // Montag der Woche des übergebenen Datums                          
    RETURN ( m.vDate - ( DOW( m.vDate, 2 ) - 1) )

ENDFUNC

Mittwoch, 22. Oktober 2008

Beliebig formatierte Datum-/Zeitstempel / Free formatted date- and timestamps

Immer wieder besteht der Bedarf, einen Dateinamen mit einem Datum- und/oder Zeitstempel zu versehen. Da der Aufbau jedoch jedes Mal anders aussieht, und alles (wie so oft) schnell gehen muss, sammeln sich im Laufe der Zeit die verschiedensten Funktionen an um den Dateinamen aufzubereiten. Um dieses Sammelsorium ein klein wenig zu entschlacken gibt es in diesem Blogeintrag einen Mustercode für eine zentrale Formatierung die letztlich nur einen Parameter benötigt, nämlich das Formatmuster.

Zulässige Formatierungskennungen sind YYYY bzw. YY für Jahr, MM für Monat, DD für Tag, hh für Stunde, mm für Minute, ss für Sekunde. Wird bspw. als Format die folgende Zeichenkette übergeben: Invoice-Spar-DD.MM.YYYY.edi wird daraus: Invoice-Spar-22.10.2008.edi

Die Zeichenkette: Invoice-Spar-YYYY.MM.DD_hh.mm.ss.edi wird zu: Invoice-Spar-2005.10.22_07.45.56.edi

Hier nun der Code:

FUNCTION FormatDTStamp
LPARAMETERS vFormat as String

    LOCAL   lcJahr as String, lcMonat as String, lcTag as String, ;
            lcStunde as String, lcMinute as String, lcSekunde as String, ;
            lcStamp as String
         
    lcJahr      = PADL(YEAR(DATE()),4,[0])
    lcMonat     = PADL(MONTH(DATE()),2,[0])
    lcTag       = PADL(DAY(DATE()),2,[0])
    lcStunde    = PADL(HOUR(DATETIME()),2,[0])
    lcMinute    = PADL(MINUTE(DATETIME()),2,[0])
    lcSekunde   = PADL(SEC(DATETIME()),2,[0])
    lcStamp     = m.vFormat

    DO CASE
    CASE OCCURS([YYYY],lcStamp) > 0
        lcStamp = STRTRAN(lcStamp,[YYYY],lcJahr)
    CASE OCCURS([YY],lcStamp) > 0
        lcStamp = STRTRAN(lcStamp,[YY],RIGHT(lcJahr,2))
    ENDCASE

    lcStamp = STRTRAN(lcStamp,[MM],lcMonat)
    lcStamp = STRTRAN(lcStamp,[DD],lcTag)
    lcStamp = STRTRAN(lcStamp,[hh],lcStunde)
    lcStamp = STRTRAN(lcStamp,[mm],lcMinute)
    lcStamp = STRTRAN(lcStamp,[ss],lcSekunde)

    RETURN lcStamp

ENDFUNC

Die Funktion kann um beliebige weitere Platzhalter ergänzt werden. Denkbar wäre eine textuelle Darstellung von Monat und Tag durch eine dreistellige Platzhalterdefinition (Jan,Feb,Mär,... -> MMM bzw. Mon,Die,Mit,... -> DDD).

Eine solche Umsetzung unterstützt VFP mit den beiden Funktionen CMONTH() und CDOW().

Mittwoch, 28. Mai 2008

Datumsspielereien (Teil 3) / Date gadgets (Part 3)

Im dritten Posting geht es um diejenigen Feiertage, die in direkter Beziehung zu Heiligabend oder vielmehr dem 1. Weihnachtsfeiertag stehen.

Im Einzelnen handelt es sich hier um den Volkstrauertag, Buss- und Bettag, Totensonntag sowie den 1. - 4. Advent.

Der folgende Code greift auf die im Teil 1 beschriebene Funktion SetYear() zurück.

Ähnlich wie beim Osterfest und den daran gekoppelten Feiertagen verhält es sich mit den an dieser Stelle aufgeführten Terminen. Basis ist der letzte Sonntag vor dem 1. Weihnachtsfeiertag.

* korrigierte Version gemäss wOOdy's Vorschlag            
* CTOD() gegen die bessere DATE()-Funktion auszutauschen
FUNCTION GetVolkstrauertag as Date
LPARAMETERS Jahr as Integer
    Jahr = SetYear(Jahr)
    ld25 = DATE(Jahr,12,25)
    RETURN ld25 - DOW(ld25,2) - 35
ENDFUNC

FUNCTION GetBussUndBettag as Date
LPARAMETERS Jahr as Integer
    Jahr = SetYear(Jahr)
    RETURN GetTotensonntag(Jahr) - 4
ENDFUNC

FUNCTION GetTotensonntag as Date
LPARAMETERS Jahr as Integer
    Jahr = SetYear(Jahr)
    ld25 = DATE(Jahr,12,25)
    RETURN ld25 - DOW(ld25,2) - 28
ENDFUNC

FUNCTION GetErsterAdvent as Date
LPARAMETERS Jahr as Integer
    Jahr = SetYear(Jahr)
    ld25 = DATE(Jahr,12,25)
    RETURN ld25 - DOW(ld25,2) - 21
ENDFUNC

FUNCTION GetZweiterAdvent as Date
LPARAMETERS Jahr as Integer
    Jahr = SetYear(Jahr)
    ld25 = DATE(Jahr,12,25)
    RETURN ld25 - DOW(ld25,2) - 14
ENDFUNC

FUNCTION GetDritterAdvent as Date
LPARAMETERS Jahr as Integer
    Jahr = SetYear(Jahr)
    ld25 = DATE(Jahr,12,25)
    RETURN ld25 - DOW(ld25,2) - 7
ENDFUNC

FUNCTION GetVierterAdvent as Date
LPARAMETERS Jahr as Integer
    Jahr = SetYear(Jahr)
    ld25 = DATE(Jahr,12,25)
    RETURN ld25 - DOW(ld25,2)
ENDFUNC

Montag, 26. Mai 2008

Datumsspielereien (Teil 2) / Date gadgets (Part 2)

Im zweiten Posting der Datumspielereien geht es um die Berechnung von Weiberfastnacht, Rosenmontag, Fastnacht, Aschermittwoch, Karfreitag, Ostermontag, Christi Himmelfahrt, Pfingstsonntag, Pfingstmontag und Fronleichnam. Mit anderen Worten um sämtliche (mir bekannten) Ostern-abhängigen Feiertage.

Der folgende Code greift auf die im Teil 1 beschriebenen Funktionen GetOstersonntag() und SetYear() zurück.

Die zuvor genannten Feiertage liegen sozusagen in 'fester Entfernung' zum Osterfest.
Weiberfastnacht liegt genau 50 Tage vor dem Ostersonntag
Christi Himmelfahrt hingegen 39 Tage hinter dem Ostersonntag
Pfingsten wiederum liegt 49 Tage hinter dem Ostersonntag
Fronleichnam bringt es auf 60 Tage hinter dem Ostersonntag

FUNCTION GetWeiberFastnacht as Date
LPARAMETERS Jahr as Integer
    Jahr = SetYear(Jahr)
    RETURN GetOstersonntag(Jahr) - 50
ENDFUNC

FUNCTION GetRosenmontag as Date
LPARAMETERS Jahr as Integer
    Jahr = SetYear(Jahr)
    RETURN GetOstersonntag(Jahr) - 48
ENDFUNC

FUNCTION GetFastnacht as Date
LPARAMETERS Jahr as Integer
    Jahr = SetYear(Jahr)
    RETURN GetOstersonntag(Jahr) - 47
ENDFUNC

FUNCTION GetAschermittwoch as Date
LPARAMETERS Jahr as Integer
    Jahr = SetYear(Jahr)
    RETURN GetOstersonntag(Jahr) - 46
ENDFUNC

FUNCTION GetKarfreitag as Date
LPARAMETERS Jahr as Integer
    Jahr = SetYear(Jahr)
    RETURN GetOstersonntag(Jahr) - 2
ENDFUNC

FUNCTION GetOstermontag as Date
LPARAMETERS Jahr as Integer
    Jahr = SetYear(Jahr)
    RETURN GetOstersonntag(Jahr) + 1
ENDFUNC

FUNCTION GetChristiHimmelfahrt as Date
LPARAMETERS Jahr as Integer
    Jahr = SetYear(Jahr)
    RETURN GetOstersonntag(Jahr) + 39
ENDFUNC

FUNCTION GetPfingstsonntag as Date
LPARAMETERS Jahr as Integer
    Jahr = SetYear(Jahr)
    RETURN GetOstersonntag(Jahr) + 49
ENDFUNC

FUNCTION GetPfingstmontag as Date
LPARAMETERS Jahr as Integer
    Jahr = SetYear(Jahr)
    RETURN GetOstersonntag(Jahr) + 50
ENDFUNC

FUNCTION GetFronleichnam as Date
LPARAMETERS Jahr as Integer
    Jahr = SetYear(Jahr)
    RETURN GetOstersonntag(Jahr) + 60
ENDFUNC

Montag, 19. Mai 2008

Datumsspielereien (Teil 1) / Date gadgets (Part 1)

Als ich mit dem Entwickeln von Software begann, hätte ich mir nicht träumen lassen, welche Algorithmen hinter der Berechnung eines speziellen Datums liegen können.

Natürlich war ich mir der beweglichen kirchlichen Feiertage bewußt, aber um das Warum machte ich mir keine Gedanken. Erst wenn wir uns näher mit diesen diversen Feiertagen befassen stellen wir fest, dass das Osterfest für die Berechnung des Fastnachtstermins ebenso ursächliche Wirkung zeigt wie für Christi Himmelfahrt und Pfingsten.

Mit diesem Posting beginne ich eine kleine Serie rund um Datumsberechnungen im Fux. Die Berechnung der Feiertage beruht hierbei auf den Daten der westlichen Kirchen.

Den Anfang macht natürlich das schon zuvor angesprochene Osterfest, im speziellen der Ostersonntag.

Die von Carl Friedrich Gauß erstmals im Jahre 1800 veröffentlichte Gaußsche Osterformel steht bereits in Pascal und Basic und sicherlich auch anderen Sprachen im WWW zum Herunterladen bereit. Der folgende Code stellt eine Möglichkeit der Umsetzung in Visual Foxpro dar.

FUNCTION GetOstersonntag as Date
LPARAMETERS Jahr as Integer
* Erster Sonntag nach dem Frühlingsvollmond                         
* Die u.a. Formel entspricht der von Gauss entwickelten Variante 
LOCAL a as Integer, b as Integer, c as Integer, d as Integer, e as Integer, f as Integer 
    Jahr = SetYear(Jahr) 
    a = MOD(Jahr,19) 
    b = INT(Jahr/ 100) 
    c = INT((8 * b + 13) / 25 - 2) 
    d = b - INT(Jahr/ 400) - 2 
    e = MOD(19 * MOD(Jahr,19) + MOD(15 - c + d,30),30) 
    DO CASE 
    CASE e = 28 AND a > 10
        e = 27 
    CASE e = 29
        e = 28 
    ENDCASE 
    f = MOD(d + 6 * e + 2 * MOD(Jahr,4) + 4 * MOD(Jahr,7) + 6,7) 
    * CTOD entsporgt = korrigierte wOOdy-Version (Thanx :-) )     
    * die '-1' lasse ich im Gedenken an das Original (d + e + 22) 
    * noch so stehen.                                             
    RETURN DATE(Jahr,3,1) + (e + f + 22) - 1
ENDFUNC

Die o.a. Funktion greift auf eine weitere Funktion mit dem Namen 'SetYear' zurück. Sie stellt sicher, dass bei ungültiger Parametrisierung mit einem gültigen Wert gearbeitet wird.

Hier nun diese zusätzliche Funktion, auf die im Übrigen auch die Codebeispiele in den folgenden Postings zurückgreifen werden.

FUNCTION SetYear as Integer
LPARAMETERS Jahr as Integer

    * korrigierte wOOdy-Version (again Thanx :-) )
    RETURN EVL(Jahr, YEAR(DATE()))
   
ENDFUNC