AtNotes Übersicht Willkommen Gast. Bitte einloggen oder registrieren.
22.11.19 - 03:04:22
Übersicht Hilfe Regeln Glossar Suche Einloggen Registrieren
News:
Schnellsuche:
+  Das Notes Forum
|-+  Best Practices
| |-+  At Notes Best Practices (Moderatoren: Axel, MartinG, animate, koehlerbv)
| | |-+  [LotusScript, Formelsprache]: Kalenderwoche: Berechnung mit Formeln und LS
« vorheriges nächstes »
Seiten: [1] Nach unten Drucken
Autor Thema: [LotusScript, Formelsprache]: Kalenderwoche: Berechnung mit Formeln und LS  (Gelesen 25315 mal)
koehlerbv
Moderator
Gold Platin u.s.w. member:)
*****
Offline Offline

Geschlecht: Männlich
Beiträge: 20460



« am: 07.01.05 - 22:52:32 »

Autor(en):             Bernhard Koehler (koehlerbv), Formeln: Jürgen Schomann und Samuel Menigat

Joachim (jr)
Stand:                  05.09.2009
Version:                1.02
Notes-Versionen:    4.x, 5.x, 6.x, 7.x, 8.x
Atnotes-Thread:     Thread     (Einer von vielen)



Vorbemerkung

Das Thema "Kalenderwoche" erscheint uns in der Regel einfach zu lösen: Kalender aufschlagen und nachschauen ... Softwaretechnisch ist dies nicht ganz so einfach, allein schon, weil in unterschiedlichen Regionen der Erde auch unterschiedliche Regeln für die Berechnung der Wochennummer gelten. Im europäischen Sprachraum hat sich jedoch die Norm "ISO 8601" hinsichtlich der Berechnung der Kalenderwochennummer durchgesetzt.
Hierzu ein Auszug aus der deutschen Wikipedia (Stand 07.01.2005):

Zitat
Kalenderwoche

Das Jahr wird in Kalenderwochen eingeteilt, die durchnummeriert sind. Ein Jahr hat 52 oder 53 Kalenderwochen.

Bei den Wochennummerierungen gibt es verschiedene Variationen:

Die erste Woche des Jahres ist

    * jene, in die der 1. Januar fällt
    * die erste vollständige Woche des Jahres
    * die erste Woche, in die mindestens 4 Tage des neuen fallen. (ISO 8601)

Diese 3 Variationen beziehen sich alle auf die klassische Woche. Abweichungen gibt es z. B. in Großbritannien, wo es ein Steuerjahr gibt, das immer am 6. April beginnt.

Die internationale Norm ISO 8601 (1973) legt als Wochenanfang den Montag fest. Die erste Woche des Jahres muss mindestens vier Tage enthalten. Dies ist gleichbedeutend mit der Woche, die den 4. Januar enthält, oder der Woche, die den ersten Donnerstag des Jahres enthält. In Deutschland ist seit 1976 festgelegt, dass die Woche mit dem Montag beginnt: DIN 1355 (1974), DIN EN 28601 (1993).

Ein Vorteil dieser Zählweise ist, dass die letzte Kalenderwoche des Vorjahres nicht gleichzeitig die erste Kalenderwoche des Folgejahres ist.

Beispiel:
    * Kalenderwoche "KW 52", 2003: 2003-W52 (Montag, 2003-12-22 bis Sonntag, 2003-12-28)
    * Kalenderwoche "KW 1", 2004: 2004-W01 (Montag, 2003-12-29 bis Sonntag, 2004-01-04)

In weiten Teilen der Welt (z.B. Nordamerika) gilt die Konvention, den Sonntag als ersten Wochentag zu rechnen. Dies stimmt mit der Tradition der Judentums und Christentums überein, die den Samstag (Sabbat) als siebten Wochentag rechnen. Ebenso ist es in Japan (siehe Woche (Japan)). In den islamischen Ländern beginnt die Woche bereits mit dem Samstag.

Umsetzung der ISO 8601 in LotusScript

In LotusScript gibt es leider keine eingebaute Funktion, mit der sich nach ISO 8601 die Kalenderwoche errechnen lässt. Die Format-Funktion verspricht zwar eine Berechnung der KW - leider aber abseits des von uns benötigten Standards. Siehe hierzu auch
Thread "Kalenderwoche mit Format berechnen"

Der folgende Code basiert auf einem Algorithmus, der sich - ganz ähnlich codiert - im Netz (und in fertigen Applikationen) vielfach finden lässt. Christian Meis hat ihn 1999 bei Keysolutions veröffentlicht. Ich habe keine Ahnung, ob er der Ur-Autor ist. Einiges spricht aber dafür, denn der dort veröffentlichte Code funktioniert nur auf Systemen mit deutscher Datumsnotation.
Gerade wegen der Datumsnotation habe ich das Teil überarbeitet und für beliebige Datums-/Zeiteinstellungen lauffähig gemacht sowie ein paar programming standards eingebaut.

WICHTIG: Die Routine "ErrorHandler" (sowieso ein Muss für jede Anwendung) ist hier nur ein Dummy, der den jeweiligen Spezifika / Vorlieben etc. entsprechend selbst erstellt werden muss.

Code:
Sub ErrorHandler (szModule As String)

'Just a place holder ...

End Sub



Function CalculateISOWeekday (vDateGiven As Variant) As Integer

' Purpose: Calculates the weekday based on the ISO rules (0 = Monday, 6 = Sunday)

' Arguments:
' vDateGiven - the date we have to calculate the ISO weekday for

' Returns: The ISO weekday (0 = Monday, 6 = Sunday). If an error occurs, the return value will be -1

' Created by:   Bernhard Koehler on 13.12.2004            Modified by:

' Changes:


Dim iTempOffset As Integer

On Error Goto ErrorRoutine

'The default (error-) result:
CalculateISOWeekday = -1

iTempOffset = Weekday (vDateGiven)

If iTempOffset = 1 Then 'Sunday in non-ISO version
iTempOffset = iTempOffset + 7
End If

CalculateISOWeekday = iTempOffset - 2

Exit Function

ErrorRoutine:
CalculateISOWeekday = -1
Call ErrorHandler ("CalculateISOWeekday")
Exit Function
End Function



Function CalculateWeekNo (vDateGiven As Variant) As Integer

' Purpose: Calculates the week number based on ISO 8601:1988

' Arguments:
' vDateGiven - the date we have to calculate the week number for

' Returns: The calendar week number. If an error occurs, the return value will be -1

' Notes: This routine is an enhanced version of the algorithm posted by Christian Meis posted in 1999 on www.keysolutions.com

' Created by:   Bernhard Koehler on 13.12.2004            Modified by:

' Changes:


Dim iDateGivenOffset As Integer
Dim iYearGiven As Integer
Dim vJanuary4 As Variant
Dim iJanuary4Offset As Integer
Dim vFirstMonday As Variant
Dim iJanuary1Offset As Integer
Dim iDecember31Offset As Integer
Dim iWeekNo As Integer


On Error Goto ErrorRoutine

'The default result of the function:
CalculateWeekNo = -1

'Check if vDateGiven is a valid Date/Time value:
If Not (Isdate (vDateGiven)) Then
Exit Function
End If


iYearGiven = Year (vDateGiven)

'Get the offset of the given day to the ISO weekday value:
iDateGivenOffset = CalculateISOWeekday (vDateGiven)

'Get the offset for the first and the last day of the given year:
iJanuary1Offset = CalculateISOWeekday (Datenumber (iYearGiven, 1, 1))
iDecember31Offset = CalculateISOWeekday (Datenumber (iYearGiven, 12, 31))

'The ISO rule:
'Monday is the first day of the week. Week #1 is the week that contains the 4th of January (ISO 8601).
'The week at the end/beginning of the year belongs to the next/previous year, if there are 3 days or less of that week in the year in question.
'If the input date is after the 28th of December and the year ends with a monday, tuesday or wednesday, then the week belongs to the following year
'if the entered date is not a saturday or sunday


If Month (vDateGiven) = 1 And Day (vDateGiven) < 4 And iJanuary1Offset > 3 And iDateGivenOffset > 1 Then
iYearGiven = iYearGiven - 1
End If

  ' If the input date is after the 28th of December and the year ends with
  ' a monday, tuesday or wednesday, then the week belongs to the following year
  ' if the entered date is not a saturday or sunday
If Month (vDateGiven) = 12 And Day (vDateGiven) > 28 And iDecember31Offset < 3 And iDateGivenOffset < 5 Then
iYearGiven = iYearGiven + 1
End If

'The 4th of January defines week #1
vJanuary4 = Datenumber (iYearGiven, 1, 4)

'Offset to the monday of week #1
vFirstMonday = vJanuary4 - CalculateISOWeekday (vJanuary4)

'The time range between the monday of week #1 and the monday of the week in question is divided by 7, plus 1 for the first week:
iWeekNo = (vDateGiven - iDateGivenOffset - vFirstMonday) \ 7 + 1

  'Return the result:
CalculateWeekNo = iWeekNo

Exit Function

ErrorRoutine :
Call ErrorHandler ("CalculateWeekNo")
CalculateWeekNo = -1
Exit Function
End Function


In Spaltenformeln von Ansichten oder in anderem @functions-bezogenen Kontext nützt natürlich LotusScript herzlich wenig, daher hier auch Umsetzung für die Formelsprache. Ausgangspunkt ist der Wert von "Datum":

Code:
REM "Berechnung der Kalenderwoche des Tages >>Datum<<";
Date := [<Datum>];
WeekThursday := @Adjust(Date; 0; 0; @If (@Weekday(Date) = 1; -3; -@Weekday (Date) + 5); 0; 0; 0);
WeekYear := @Year (WeekThursday);
January4Date := @Date (WeekYear; 1; 4);
FirstThursday := @Adjust (January4Date; 0; 0; @If (@Weekday (January4Date) = 1; -3; -@Weekday (January4Date) + 5); 0; 0; 0);
Week := ((WeekThursday - FirstThursday) / 86400) / 7 + 1;

@Prompt([Ok];"";@Text (Week) + ". KW, " + @Text (WeekYear))

Obige Formel wurde von Jürgen Schomann zur Verfügung gestellt - meine eigene Routine war einige Zeilen länger.
Vielen Dank dafür.

Ebensolcher Dank geht an Samuel Menigat - er lieferte die Idee zu diesem

Umkehrschluss: Einen Wochentag in einer bestimmten Kalenderwoche des Jahres bestimmen

Der von Samuel beigetragene Algorithmus lässt sich besonders einfach in seiner ursprünglichen Fassung nachvollziehen. Wir gehen hierbei davon aus, dass durch die Variablen "Year" und "WeekNo" diese Werte vorgegeben sind:
Code:
_Monday := @If(
@Weekday(@Date(year; 1; 1))=1; @Adjust(@Date(year; 1; 1); 0; 0; 1+ ((WeekNo-1)*7); 0; 0; 0);
@Weekday(@Date(year; 1; 1))=2; @Adjust(@Date(year; 1; 1); 0; 0; ((WeekNo-1)*7); 0; 0; 0);
@Weekday(@Date(year; 1; 1))=3; @Adjust(@Date(year; 1; 1); 0; 0; ((WeekNo-1)*7) -1; 0; 0; 0);
@Weekday(@Date(year; 1; 1))=4; @Adjust(@Date(year; 1; 1); 0; 0; ((WeekNo-1)*7)-2; 0; 0; 0);
@Weekday(@Date(year; 1; 1))=5; @Adjust(@Date(year; 1; 1); 0; 0; ((WeekNo-1)*7)-3; 0; 0; 0);
@Weekday(@Date(year; 1; 1))=6; @Adjust(@Date(year; 1; 1); 0; 0; ((WeekNo-1)*7)+3; 0; 0; 0);
@Weekday(@Date(year; 1; 1))=7; @Adjust(@Date(year; 1; 1); 0; 0; ((WeekNo-1)*7)+2; 0; 0; 0);
"");

@Prompt ([OK]; "Ergebnis"; @Text (_Monday))

Die kürzere und performantere Variante habe ich wie folgt erstellt:
Code:
_FirstDayOfYear := @Date (Year; 1; 1);

WeekNoMonday := @Adjust (_FirstDayOfYear; 0; 0; @Subset (@Subset (1 : -0 : -1 : -2 : -3 : 3 : 2; @Weekday (_FirstDayOfYear)); -1)  + ((WeekNo - 1) * 7); 0; 0; 0);

@Prompt ([Ok]; "Ergebnis"; @Text (WeekNoMonday))
« Letzte Änderung: 27.02.10 - 16:33:33 von koehlerbv » Gespeichert
Seiten: [1] Nach oben Drucken 
« vorheriges nächstes »
Gehe zu:  


Einloggen mit Benutzername, Passwort und Sitzungslänge

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2006, Simple Machines Prüfe XHTML 1.0 Prüfe CSS
Impressum Atnotes.de - Powered by Syslords Solutions - Datenschutz | Partner: