that was a hard job
Even in internet have been wrong calculations.
Step by step the source is explained :
There is allways a MsgAlert() after each calculation for the result.
- Code: Select all Expand view RUN
SET DATE FORMAT TO "DD/MM/YYYY"
dDate := CTOD( "29/12/2008" ) // Date()
ISO8601Week(dDate)
// -----------------------------------------------
/**
* ISO-8601 Week Number
* Processes the week number of a date,
*/
function ISO8601Week(dDate)
// 1) Convert date to Y M D
Y := Year(dDate)
M := Month(dDate)
D := Day(dDate)
WeekNumber := 0
DayOfYear := D
MsgAlert( Y, "1a) Date-Year" )
MsgAlert( M, "1b) Date-Month" )
MsgAlert( D, "1c) Date-Day" )
// 2) Find out if Y is a leap year (Logic-var)
// ----------------------------------------------------
isLeapYear := .F.
IF (Y % 4 == 0 .and. Y % 100 != 0) .or. Y % 400 == 0
isLeapYear := .T.
ENDIF
MsgAlert( isLeapYear, "2) Date is LeapYear" )
// 3) Find out if Year before is a leap year
// --------------------------------------------------
lastYear := Y - 1
lastYearIsLeap := .F.
IF (lastYear % 4 == 0 .and. lastYear % 100 != 0) .or. lastYear % 400 == 0
lastYearIsLeap := .T.
ENDIF
MsgAlert( lastYearIsLeap, "3) Year before LeapYear" )
// 4) Find the Day of Year Number for Y M D
// ------------------------------------------------------
DayOfYear := 1
aDays := {0,31,59,90,120,151,181,212,243,273,304,334}
DayOfYear := D + aDays[M]
IF isLeapYear = .T. .and. M > 1
DayOfYear++
ENDIF
MsgAlert( DayOfYear, "4) Day-Number of Date" )
// 5) Find the weekday for Jan 1 (monday = 1, sunday = 7)
// -------------------------------------------------------------------------
YY := (Y-1) % 100
C := (Y-1) - YY // get century
G := YY + YY/4
Jan1Weekday := 1 + (((((C / 100) % 4) * 5) + G) % 7)
MsgAlert( INT(Jan1Weekday), "5) WeekDay of 1. Januar" )
// 6) Find the weekday for Y M D
// ---------------------------------------
H := DayOfYear + (Jan1Weekday - 1)
Weekday := 1 + ((H -1) % 7)
MsgAlert( INT(Weekday), "6) WeekDay of Date" )
// 7) Find if Y M D falls in YearNumber Y-1, WeekNumber 52 or 53
// ----------------------------------------------------------------------------------
YearNumber = Y
WeekNumber := 0
IF DayOfYear <= (8-Jan1Weekday) .and. Jan1Weekday > 4
// Date is within the last week of the previous year.
YearNumber = Y - 1
IF Jan1Weekday == 5 .or. Jan1Weekday == 6 .and. isLeapYear
WeekNumber = 53
else
WeekNumber = 52
ENDIF
ENDIF
MsgAlert( YearNumber, "7a) Falls in Year" )
MsgAlert( WeekNumber, "7b) Week-Number" )
// 8) Find if Y M D falls in YearNumber Y+1, WeekNumber 1
// --------------------------------------------------------------------------
IF YearNumber == Y
Number = 365
IF isLeapYear
Number = 366
if (Number - DayOfYear) < (4 - Weekday)
// Date is within the first week of the next year
YearNumber = Y + 1
WeekNumber = 1
endif
ENDIF
ENDIF
MsgAlert( YearNumber, "8a) Falls in Next-Year" )
MsgAlert( WeekNumber, "8b) Week-Number in Next Year" )
// 9) Find if Y M D falls in YearNumber Y, WeekNumber 1 through 53
// -------------------------------------------------------------------------------------
IF YearNumber == Y
// Date is within it's current year.')
J := DayOfYear + (7 - Weekday) + (Jan1Weekday -1)
WeekNumber = J / 7
IF Jan1Weekday > 4
WeekNumber--
ENDIF
ENDIF
MsgAlert( INT(WeekNumber), "9) Week-Number is in Year" )
// RESULT
// ---------
// ---------
ISOWEEK := 0
IF (WeekNumber < 10)
ISOWEEK := STR(YearNumber) + "-W0" + ALLTRIM(STR(INT(WeekNumber))) + ;
"-" + ALLTRIM(STR(INT(DayOfYear)))
ENDIF
IF (WeekNumber > 9)
ISOWEEK := STR(YearNumber) + "-W" + ALLTRIM(STR(INT(WeekNumber))) + ;
"-" + ALLTRIM(STR(INT(DayOfYear)))
ENDIF
msgalert( "ISO- Week-Number : " + ISOWEEK, "Tested Date : " + DTOC(dDate) )
RETURN( WeekNumber )
The calculation problem and useful informations and tests.
---------------------------------------------------------------------
The ISO standard avoids explicitly stating the possible range of week numbers,
but this can easily be deduced from the definition. Possible ISO week numbers are in
the range 01 to 53. A year always has a week 52.
(There is one historic exception: the year in which the Gregorian calendar was introduced
had less than 365 days and less than 52 weeks.)
Proof: Per definition, the first week of a year is W01 and consequently days before
week W01 belong to the previous year and so there is no week with lower numbers.
Considering the highest possible week number, the worst case is a leap year like 1976 that starts
with a Thursday, because this keeps the highest possible number of days of W01 in the
previous year, i.e. 3 days. In this case, the Sunday of W52 of the worst case year is day
number 4+51*7=361 and 361-366=5 days of W53 belong still to this year, which guarantees
that in the worst case year day 4 (Thursday) of W53 is not yet in the next year, so a week
number 53 is possible. For example, the 53 weeks of the worst case year 1976 started
with 1975-12-29 = 1976-W01-1 and ended with 1977-01-02 = 1976-W53-7.
On the other hand, considering the lowest number of the last week of a year, the worst
case is a non-leap year like 1999 that starts with a Friday, which ensures that the first three
days of the year belong to the last week of the previous year. In this case, the Sunday of
week 52 would be day number 3+52*7=367, i.e. only the last 367-365=2 days of the W52
reach into the next year and consequently, even a worst case year like 1999 has a
week W52 including the days 1999-12-27 to 2000-01-02. q.e.d.
Uwe