ISO 8601 Week Numbers

ISO 8601 Week Numbers

Postby cdmmaui » Mon Dec 29, 2008 4:34 am

Hello, does anyone have a function to calculate ISO week numbers, the xHarbour WEEK() is not returning the correct ISO week number.

Thank you,
*~*~*~*~*~*~*~*~*~*
Darrell Ortiz
CDM Software Solutions, Inc.
https://www.cdmsoft.com
User avatar
cdmmaui
 
Posts: 693
Joined: Fri Oct 28, 2005 9:53 am
Location: Houston ∙ Chicago ∙ Los Angeles ∙ Miami ∙ London ∙ Hong Kong

Date-Functions

Postby ukoenig » Mon Dec 29, 2008 12:36 pm

Hello Darrell,

I updated the Date / Time - Functions.
A Week-count from start-date to end-date is added.

A function week(), I couldn't find in xHARBOUR.
there is a sample < Dates4.prg > with date-functions :

function CheckDate( dDate ) // from xHARBOUR => Dates4.prg
OutStd( "Testing date:", dDate , s_cNewLine )
OutStd( "Days in month..:", daysinmonth( dDate ), s_cNewLine )
OutStd( "Day of year....:", doy( dDate ), s_cNewLine )
OutStd( "Begin of month.:", bom( dDate ), s_cNewLine )
OutStd( "End of month...:", eom( dDate ), s_cNewLine )
OutStd( "Week of month..:", wom( dDate ), s_cNewLine )
OutStd( "Week of year...:", woy( dDate ), s_cNewLine )
OutStd( "Begin of year..:", boy( dDate ), s_cNewLine )
OutStd( "End of year....:", eoy( dDate ), s_cNewLine )

Download ( PRG + RC-File ) :

http://www.pflegeplus.com/fw_downloads/DateTime2.zip

Image

ISO 8601 :
-------------

Year:
YYYY (eg 1997)
Year and month:
YYYY-MM (eg 1997-07)
Complete date:
YYYY-MM-DD (eg 1997-07-16)
Complete date plus hours and minutes:
YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)
Complete date plus hours, minutes and seconds:
YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
Complete date plus hours, minutes, seconds and a decimal fraction of a
second
YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)

where:

YYYY = four-digit year
MM = two-digit month (01=January, etc.)
DD = two-digit day of month (01 through 31)
hh = two digits of hour (00 through 23) (am/pm NOT allowed)
mm = two digits of minute (00 through 59)
ss = two digits of second (00 through 59)
s = one or more digits representing a decimal fraction of a second
TZD = time zone designator (Z or +hh:mm or -hh:mm)

Regards
Uwe :lol:
Since 1995 ( the first release of FW 1.9 )
i work with FW.
If you have any questions about special functions, maybe i can help.
User avatar
ukoenig
 
Posts: 4043
Joined: Wed Dec 19, 2007 6:40 pm
Location: Germany

Re: ISO 8601 Week Numbers

Postby Detlef Hoefner » Tue Dec 30, 2008 9:04 am

Uwe,

the program date_e is not working correctly.
I detected several mistakes.

Today, 12/30/2008 is already part of the ISO week no. 1 of 2009.
Your program claims it's week no. 53 of 2008, which is wrong.

Regards,
Detlef
User avatar
Detlef Hoefner
 
Posts: 312
Joined: Sat Oct 08, 2005 9:12 am
Location: Germany

Re: ISO 8601 Week Numbers

Postby driessen » Tue Dec 30, 2008 11:06 am

Perhaps, this is a solution to your question.

It is a function, coming from the NanTucket functions.

Code: Select all  Expand view  RUN
FUNCTION FT_WOY(dInDate)

  LOCAL nFirstDays, nDayOffset, nWkNumber, cCentury

  IF VALTYPE( dInDate) <> "D"

     nWkNumber := NIL

  ELSE

     // resolve century issue
     IF LEN(DTOC(dInDate)) > 8                  // CENTURY is on
        cCentury := SUBSTR( DTOC( dInDate) ,7 ,4)
     ELSE
        cCentury := SUBSTR( DTOC( dInDate) ,7 ,2)
     ENDIF


     // find number of days in first week of year
     nFirstDays := 8 - (DOW(CTOD("01/01/" + cCentury)))
     nWkNumber  := 1


     // find how many days after first week till dInDate

     nDayOffset := (dInDate - CTOD ("01/01/" + cCentury)) - nFirstDays + 1

     // count weeks in offset period

     DO WHILE nDayOffset > 0
        ++nWkNumber
        nDayOffset -= 7
     ENDDO

  ENDIF

RETURN(nWkNumber)


Hope to have helped you.

Good luck.
User avatar
driessen
 
Posts: 1422
Joined: Mon Oct 10, 2005 11:26 am
Location: Genk, Belgium

Re: ISO 8601 Week Numbers

Postby cdmmaui » Tue Dec 30, 2008 3:48 pm

Thank You for your reply, however this function returns an invalid week of 53 for date 12/29/2008 which is week 1 for 2009
*~*~*~*~*~*~*~*~*~*
Darrell Ortiz
CDM Software Solutions, Inc.
https://www.cdmsoft.com
User avatar
cdmmaui
 
Posts: 693
Joined: Fri Oct 28, 2005 9:53 am
Location: Houston ∙ Chicago ∙ Los Angeles ∙ Miami ∙ London ∙ Hong Kong

Re: ISO 8601 Week Numbers

Postby ukoenig » Tue Dec 30, 2008 4:32 pm

Hello Darrell,

I noticed, that nearly all date-calculations don't take care of a LEAP-YEAR. I will check this, maybe that is the reason for wrong calculations.

February 29, 2008
The year 2008 is a leap year. If you look at a 2008 calendar, you will see that February has five Fridays–the month begins and ends on a Friday. Between the years 1904 and 2096, leap years that share the same day of week for each date repeat only every 28 years. The most recent year in which February comprised five Fridays was in 1980, and the next occurrence will be in 2036. February 29, the leap day, has been associated with age-old traditions, superstitions and folklore.
What is a leap year?
A leap year is a year in which one extra day has been inserted, or intercalated, at the end of February. A leap year consists of 366 days, whereas other years, called common years, have 365 days.

Regards
Uwe :roll:
Since 1995 ( the first release of FW 1.9 )
i work with FW.
If you have any questions about special functions, maybe i can help.
User avatar
ukoenig
 
Posts: 4043
Joined: Wed Dec 19, 2007 6:40 pm
Location: Germany

Re: ISO 8601 Week Numbers

Postby cdmmaui » Tue Dec 30, 2008 4:45 pm

Hi Uwe,

Here is VBA code I found, does this help? Can you translate this to FWH?

//------------------------------------------------------------------------------------------
Public Function ISOWeekNum(AnyDate As Date, _
Optional WhichFormat As Variant) As Integer
'
' WhichFormat: missing or <> 2 then returns week number,
' = 2 then YYWW
'
Dim ThisYear As Integer
Dim PreviousYearStart As Date
Dim ThisYearStart As Date
Dim NextYearStart As Date
Dim YearNum As Integer

ThisYear = Year(AnyDate)
ThisYearStart = YearStart(ThisYear)
PreviousYearStart = YearStart(ThisYear - 1)
NextYearStart = YearStart(ThisYear + 1)
Select Case AnyDate
Case Is >= NextYearStart
ISOWeekNum = (AnyDate - NextYearStart) \ 7 + 1
YearNum = Year(AnyDate) + 1
Case Is < ThisYearStart
ISOWeekNum = (AnyDate - PreviousYearStart) \ 7 + 1
YearNum = Year(AnyDate) - 1
Case Else
ISOWeekNum = (AnyDate - ThisYearStart) \ 7 + 1
YearNum = Year(AnyDate)
End Select

If IsMissing(WhichFormat) Then
Exit Function
End If
If WhichFormat = 2 Then
ISOWeekNum = CInt(Format(Right(YearNum, 2), "00") & _
Format(ISOWeekNum, "00"))
End If

End Function

//------------------------------------------------------------------------------------------
Function YearStart(WhichYear As Integer) As Date

Dim WeekDay As Integer
Dim NewYear As Date

NewYear = DateSerial(WhichYear, 1, 1)
WeekDay = (NewYear - 2) Mod 7
If WeekDay < 4 Then
YearStart = NewYear - WeekDay
Else
YearStart = NewYear - WeekDay + 7
End If

End Function
*~*~*~*~*~*~*~*~*~*
Darrell Ortiz
CDM Software Solutions, Inc.
https://www.cdmsoft.com
User avatar
cdmmaui
 
Posts: 693
Joined: Fri Oct 28, 2005 9:53 am
Location: Houston ∙ Chicago ∙ Los Angeles ∙ Miami ∙ London ∙ Hong Kong

Re: ISO 8601 Week Numbers

Postby StefanHaupt » Tue Dec 30, 2008 4:49 pm

Hi Darrel,

in xHarbour you can use the function Week (dDate, lSimpleweek). To get the correct week number call the function with .f. as second parameter.
Code: Select all  Expand view  RUN
nIsoWeek := Week (Date(), .f.)


Or you can use this function

Code: Select all  Expand view  RUN
function IsoWeek (dDate)

  LOCAL nWeek := 0, dDate2

  dDate2 := dDate + 3 - ( DoW( dDate ) + 5 ) % 7
  nWeek := Int (( DoY( dDate2 ) - 1 ) / 7 + 1)

return (nWeek)


Hope it helps
kind regards
Stefan
StefanHaupt
 
Posts: 824
Joined: Thu Oct 13, 2005 7:39 am
Location: Germany

Re: ISO 8601 Week Numbers

Postby cdmmaui » Tue Dec 30, 2008 5:08 pm

Stefan,

Thank you, the function IsoWeek function worked, the week( DATE(), .F.) did not work. Thank you for your help!!!
*~*~*~*~*~*~*~*~*~*
Darrell Ortiz
CDM Software Solutions, Inc.
https://www.cdmsoft.com
User avatar
cdmmaui
 
Posts: 693
Joined: Fri Oct 28, 2005 9:53 am
Location: Houston ∙ Chicago ∙ Los Angeles ∙ Miami ∙ London ∙ Hong Kong

Re: ISO 8601 Week Numbers

Postby cdmmaui » Tue Dec 30, 2008 9:14 pm

Sorry, I tested more dates and I found that the week number was not calculating correctly. Here are some examples

12/28/2008 - calculates to week 52, should be week 1
01/11/2009 - calculates to week 2, should be week 3
01/18/2009 - calculates to week 3, should be week 4

It is my understanding that the ISO week starts on a Sunday. Please correct me if I am wrong.
*~*~*~*~*~*~*~*~*~*
Darrell Ortiz
CDM Software Solutions, Inc.
https://www.cdmsoft.com
User avatar
cdmmaui
 
Posts: 693
Joined: Fri Oct 28, 2005 9:53 am
Location: Houston ∙ Chicago ∙ Los Angeles ∙ Miami ∙ London ∙ Hong Kong

Re: ISO 8601 Week Numbers

Postby ukoenig » Tue Dec 30, 2008 9:50 pm

Hello Darrell,

It is not easy, to calculate this with just a simple function.
There are many things to do for a correct calculation.
You have to take care of the year-end before the calculated year and the start of the next year.

That is the problem, You figured out :

Get week number 1 to 53 of the year this date falls in, according to
the rules of ISO standard IS−8601 section 5.5. A week that lies partly
in one year and partly in another is assigned a number in the year in
which most of its days lie. This means that week 1 of any year is the
week that contains 4 January, or equivalently week 1 of any year is
the week that contains the first Thursday in January. Most years have
52 weeks, but years that start on a Thursday and leap years that start
on a Wednesday have 53 weeks. Jan 1 may well be in week 53 of the
previous year! Only defined for dates on or after 1600 Jan 01.

I'm on the way, to find a solution for FWH.

Regards
Uwe :roll:
Last edited by ukoenig on Tue Dec 30, 2008 9:59 pm, edited 1 time in total.
Since 1995 ( the first release of FW 1.9 )
i work with FW.
If you have any questions about special functions, maybe i can help.
User avatar
ukoenig
 
Posts: 4043
Joined: Wed Dec 19, 2007 6:40 pm
Location: Germany

Re: ISO 8601 Week Numbers

Postby cdmmaui » Tue Dec 30, 2008 9:54 pm

Hi Uwe, I really appreciate your assistance!!!
*~*~*~*~*~*~*~*~*~*
Darrell Ortiz
CDM Software Solutions, Inc.
https://www.cdmsoft.com
User avatar
cdmmaui
 
Posts: 693
Joined: Fri Oct 28, 2005 9:53 am
Location: Houston ∙ Chicago ∙ Los Angeles ∙ Miami ∙ London ∙ Hong Kong

Re: ISO 8601 Week Numbers

Postby ukoenig » Tue Dec 30, 2008 10:49 pm

Hello Darrell,

Your Tests :
Sorry, I tested more dates and I found that the week number was not calculating correctly. Here are some examples
12/28/2008 - calculates to week 52, should be week 1 !!!!!!!!
01/11/2009 - calculates to week 2, should be week 3
01/18/2009 - calculates to week 3, should be week 4

29.12.2008 = 1. Week in January 2009
Image

It seems, that there is really something wrong.
Image

The description ( informations ), how to calculate it ( only the end-function we need ) :

To explain the routine for calculating the ISO week number,
we first focus on the simple week number (SWN) defined below.
-------------------------------------------------------------------------------------------------------
At the end we give the necessary corrections to calculate the ISO week number. !!!!!!!!
-------------------------------------------------------------------------------------------------------
Introducing the simple week number.
The simple week number we define such that week 1 starts on January 1st of a given year,
week n+1 starts 7 days after week n
For an arbitrary day (1..31) of a given month (1..12) and year, the SWN can be calculated by:

SWN( y, m, d ) = 1 + ( DP( y, m ) + d-1 ) / 7

where DP ("Days Passed") is given by:

DP( y, 1 ) = 0
DP( y, m+1 ) = DP( y, m ) + ML( y, m )

and ML ("Month Length") is defined as:

ML( y, 1 ) = 31
ML( y, 2 ) = 28 + LEAP( y )
ML( y, 3 ) = 31
ML( y, 4 ) = 30
ML( y, 5 ) = 31
ML( y, 6 ) = 30
ML( y, 7 ) = 31
ML( y, 8 ) = 31
ML( y, 9 ) = 30
ML( y, 10 ) = 31
ML( y, 11 ) = 30
ML( y, 12 ) = 31

and LEAP( y ) is defined as:

LEAP( y ) = ( y % 4 == 0 ) && ( ( y % 100 != 0 ) || ( y % 400 == 0 ) )
Approximating DP.
To improve on the full-fledged calculation described above,
we first turn our attention to the DP function.
As a first approximation we ignore the exact month lengths and instead
assume a standard month length of 30 days.
With this approximation of DP, a first approximation of SWN can be calculated by:

SWN1( y, m, d ) = 1 + 4 * (m-1) + ( 2 * (m-1) + d-1 ) / 7
With this formula, the simple week number is calculated correctly for
some 240 of the 365/366 days in a year. By adding a rounding term of + 2
we can increase the number of correctly calculated week numbers to almost 290:

SWN2( y, m, d ) = 1 + 4 * (m-1) + ( 2 * (m-1) + d-1 + 2 ) / 7
However, we can correctly calculate the week number for all 365/366 days in a year
by making use of the simple day of the week (SDOW) function,
defined as the current day for a given date, assuming that the year starts on a Monday.

For an arbitrary day (1..31) of a given month (1..12) and a year that starts on a monday,
the SDOW can be calculated by:

SDOW( y, m, d ) = ( DP( y, m ) + d-1 ) % 7 ( 0 = Monday, ..., 6 = Sunday )
Using this function, we define the third approximation of SWN as:

SWN3( y, m, d ) = 1 + 4 * (m-1) + ( 2 * (m-1) + d-1 - SDOW( y, m, d ) + 5 ) / 7
By exhaustive experiments, we verified that SWN3 equals SWN for all possible values of y, m, and d.

Getting rid of the division.
The calculation of SWN3 still contains an division by 7, which is not a standard operation on the 6805.
We approximate this division with a formula taken from [BLINN95],
which states that for division of an integer i by a number n = 2^k-1, we can use the following approximation:

i / n = ( i + (n+1)/2 ) * ( (n+2) / (n+1)^2 )
In our case this leads to the fourth approximation for SWN:

SWN4( y, m, d ) = 1 + 4 * (m-1) + ( 2 * (m-1) + d-1 - SDOW( y, m, d ) + 6 ) * 9 / 64
Note that the rounding term has been adjusted, in order to guarantee equivalence between SWN4 and SWN.

Although the division by 64 can be implemented as a series of right shifts,
the 8x8->16 bits MUL operation available on the 6805 offers yet another possibility of optimization:
Instead of multiplying by 9, we can multiply both numerator and denominator of the 9/64 fraction by 4
and get the division result directly from the high byte of the multiplication result:

SWN5( y, m, d ) = 1 + 4 * (m-1) + ( 2 * (m-1) + d-1 - SDOW( y, m, d ) + 6 ) * 36 / 256
From the simple week number to the ISO week number.
In [ISO8601], the week number is defined by:

weeks start on a monday
week 1 of a given year is the one that includes the first Thursday of that year.
(or, equivalently, week 1 is the week that includes 4 January.)
This means that the days before week 1 in a given year are attributed to the last week of the previous year.
Also the days that come after the last week of a given year are attributed to the first week of the next year.

If we adapt approximation SWN5 for the simple week number to reflect the differences between the definitions
of both week numbers, we arrive at the final solution, adopted for the week number wristapp:

// ----------------------------------- RESULT - C-Function ( must translated to FWH ) -------------------------------------
Code: Select all  Expand view  RUN

ISO_WN( y, m, d )
{
    dow     = DOW( y, m, d );
    dow0101 = DOW( y, 1, 1 );

    if      ( m == 1  &&  3 < dow0101 < 7 - (d-1) )
    {
        // days before week 1 of the current year have the same week number as
        // the last day of the last week of the previous year

        dow     = dow0101 - 1;
        dow0101 = DOW( y-1, 1, 1 );
        m       = 12;
        d       = 31;
    }
    else if ( m == 12  &&  30 - (d-1) < DOW( y+1, 1, 1 ) < 4 )
    {
        // days after the last week of the current year have the same week number as
        // the first day of the next year, (i.e. 1)
        return 1;
    }
    return ( DOW( y, 1, 1 ) < 4 ) + 4 * (m-1) + ( 2 * (m-1) + (d-1) + dow0101 - dow + 6 ) * 36 / 256;
}



The translation would look like ( still testing ) :

Code: Select all  Expand view  RUN

FUNCTION ISO_WEEKNR( y, m, d )
// Year/month/day
// Sample : ISO_WEEKNR(08,12,29)

y1 := PADL( STR(y), 2, "0")
y2 := PADL( STR(y - 1), 2, "0")
Y3 := PADL( STR(y + 1), 2, "0")
m1 := PADL( STR(m), 2, "0")
d1 := PADL( STR(d), 2, "0")

date1 := CTOD ( '"'+ y1 + "." + m1 + "." + d1 + '"' )  //   Test : 08.12.29
date2 := CTOD ( '"'+ y1 + ".01.01" )     //    08.01.01 
date3 := CTOD ( '"'+ y2 + ".01.01" )     //    07.01.01  Year before
date4 := CTOD ( '"'+ y3 + ".01.01" )     //    09.01.01  Year after

dow1 := DOW( date1 )
dow0101 := DOW( date2 )

if ( m == 1  &&  3 < dow0101 < 7 - (d-1) )     //  To be translated !!!
   // days before week 1 of the current year have the same week number as
   // the last day of the last week of the previous year
   dow1:= dow0101 - 1
   dow0101   := DOW( date3 )
   m := 12
   d := 31
ELSE
   IF ( m == 12  &&  30 - (d-1) < DOW( date4 ) < 4 )      // To be translated !!!!
      // days after the last week of the current year have the same week number as
      // the first day of the next year, (i.e. 1)
      return 1
   ENDIF
ENDIF

RETURN ( DOW( date2 ) < 4 ) + 4 * (m-1) + ( 2 * (m-1) + (d-1) + dow0101 - dow1 + 6 ) * 36 / 256



Regards
Uwe :roll:
Last edited by ukoenig on Wed Dec 31, 2008 1:16 am, edited 2 times in total.
Since 1995 ( the first release of FW 1.9 )
i work with FW.
If you have any questions about special functions, maybe i can help.
User avatar
ukoenig
 
Posts: 4043
Joined: Wed Dec 19, 2007 6:40 pm
Location: Germany

Re: ISO 8601 Week Numbers

Postby StefanHaupt » Wed Dec 31, 2008 12:28 am

cdmmaui wrote:Sorry, I tested more dates and I found that the week number was not calculating correctly. Here are some examples

12/28/2008 - calculates to week 52, should be week 1
01/11/2009 - calculates to week 2, should be week 3
01/18/2009 - calculates to week 3, should be week 4

It is my understanding that the ISO week starts on a Sunday. Please correct me if I am wrong.


Darrel,

I´m sorry to contradict you, but my small function is working correct. ISO Week numbers always start on Monday, the first day of a week is the Monday ! That´s very important.

See here :http://en.wikipedia.org/wiki/Week

First day of the week

In most of Europe, and some other countries, Monday is considered to be the first day of the week. Monday is literally named as such in Baltic languages, for example Lithuanian (pirmadienis - means First Day); in Estonian (esmaspäev - means First Day); Hungarian (hétfő - means literally Head of The Seven/Week); Basque (astelehen - means Week-First) and Mandarin (pinyin Xīngqí Yī, literally means Weekday One). In Slavic languages, Tuesday, Thursday and Friday were named literally for their number after Monday[5], a meaning still conserved in Russian (for example Tuesday: вторник - vtórnik - means second).

The ISO prescribes Monday as the first day of the week with ISO 8601 for software date formats.

In Jewish, Arab, Western Christian and Greek Orthodox tradition, the first day of the week is Sunday. The Hebrew, Ecclesiastical Latin and Medieval and Modern Greek languages number most of the days of the week. In Hebrew, Sunday through Friday are numbered one through six; in Arabic, Sunday through Thursday are numbered one through five; in Ecclesiastical Latin and modern Portuguese, Monday through Friday are numbered the second through the sixth days of the week (feria in Latin or feira in Portuguese); in Medieval and Modern Greek, Monday through Thursday are numbered the second through fifth. For many Western Christians and Jews, Sunday remains the first day of the week. Most, though not all, business and social calendars in North America mark Sunday as the first day of the week.


You see, in USA the calculation is another one than in Europe, the USA soes not use the ISO Standard.

I hope I could shed some light on this problem.
Last edited by StefanHaupt on Wed Dec 31, 2008 12:36 am, edited 1 time in total.
kind regards
Stefan
StefanHaupt
 
Posts: 824
Joined: Thu Oct 13, 2005 7:39 am
Location: Germany

Re: ISO 8601 Week Numbers

Postby cdmmaui » Wed Dec 31, 2008 12:32 am

Thank you for the clarification
*~*~*~*~*~*~*~*~*~*
Darrell Ortiz
CDM Software Solutions, Inc.
https://www.cdmsoft.com
User avatar
cdmmaui
 
Posts: 693
Joined: Fri Oct 28, 2005 9:53 am
Location: Houston ∙ Chicago ∙ Los Angeles ∙ Miami ∙ London ∙ Hong Kong

Next

Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 102 guests