Page 1 of 1

ISO weeknumber

Posted: Sun Aug 11, 2013 4:16 pm
by blueznl
I'm looking for a good example how to calculate the ISO weeknumber. I've been looking in the forum, as well as checking out the internet, and thus far I've seen many examples, but none I could understand or convert.

Would anyone have a snippet handy of sample code?

Re: ISO weeknumber

Posted: Sun Aug 11, 2013 5:05 pm
by wilbert
The week that contains january 4 is week 1.
ISO weeks start on monday.

So maybe you could use DayOfWeek(Date) to check what kind of day january 4 of a year was (monday, tuesday etc.), and use that to determine the start of week 1.
One you know the start of week 1, you could determine the week of another date in that year be taking the difference in time stamp to see how many weeks have passed.

Re: ISO weeknumber

Posted: Sun Aug 11, 2013 6:25 pm
by TI-994A
blueznl wrote:I'm looking for a good example how to calculate the ISO weeknumber.
Hello blueznl. Here's a simple implementation of the ISO 8601 week calculator:

Code: Select all

Procedure ISOWeek(date)
  year = Year(date)
  firstDay = DayOfWeek(Date(year, 1, 1, 0, 0, 0))
  If firstDay = 0
    firstDay = 7
  EndIf
  If firstDay <= 4
    ISOday = DayOfYear(date) + (firstDay - 1)
  Else
    ISOday = DayOfYear(date) - (8 - firstDay)
  EndIf
  ISOwk = Round(ISOday / 7, #PB_Round_Up)
  If Not ISOwk
    ISOwk = ISOWeek(Date(year - 1, 12, 31, 0, 0, 0))
  EndIf
  ;------
  If ISOwk = 53 And Month(date) = 12 And
     DayOfWeek(Date(year + 1, 1, 1, 0, 0, 0)) <= 4
    ISOwk = 1
  EndIf  
  ;------
  ProcedureReturn ISOWk
EndProcedure

Debug ISOWeek(Date())
Debug ISOWeek(Date(1997, 12, 29, 0, 0, 0)) ;week #1
Debug ISOWeek(Date(2012, 12, 31, 0, 0, 0)) ;week #1
Debug ISOWeek(Date(2012, 1, 1, 0, 0, 0))   ;week #52
Debug ISOWeek(Date(2016, 1, 1, 0, 0, 0))   ;week #53
It's a first attempt, so please do test it exhaustively before using. :wink:


EDIT: Code fixed to include a missing 53rd-week check, thanks to testing by Little John. :)

Re: ISO weeknumber

Posted: Sun Aug 11, 2013 6:33 pm
by wilbert
Here's my attempt after some thinking

Code: Select all

Procedure.i WeekNumberISO(year, month, day)
  
  Protected week1_prev, week1_this, week1_next
  Protected specified_date = Date(year, month, day, 0, 0, 0)
  
  week1_prev = Date(year - 1, 1, 4, 0, 0, 0)
  week1_this = Date(year    , 1, 4, 0, 0, 0)
  week1_next = Date(year + 1, 1, 4, 0, 0, 0)
  week1_prev - ((DayOfWeek(week1_prev) + 6) % 7) * 86400
  week1_this - ((DayOfWeek(week1_this) + 6) % 7) * 86400
  week1_next - ((DayOfWeek(week1_next) + 6) % 7) * 86400
  
  If specified_date < week1_this
    ; still in last week of previous year
    ProcedureReturn (specified_date - week1_prev) / 604800 + 1
  ElseIf specified_date >= week1_next
    ; already in week 1 of next year
    ProcedureReturn 1
  Else  
    ProcedureReturn (specified_date - week1_this) / 604800 + 1
  EndIf
  
EndProcedure
  
MessageRequester("", Str(WeekNumberISO(2013, 08, 11)))

Re: ISO weeknumber

Posted: Sun Aug 11, 2013 10:32 pm
by falsam
@TI-994A & @wilbert : Interesting code. Thanks for sharing. :)

Re: ISO weeknumber

Posted: Mon Aug 12, 2013 10:03 am
by Little John
Here is my version.

//edit: Code improved.

Code: Select all

EnableExplicit

Procedure.i ISOdayOfWeek (date.i)
   Protected d.i
   
   d = DayOfWeek(date)
   If d = 0
      d = 7             ; for Sunday, return 7 instead of 0
   EndIf
   ProcedureReturn d
EndProcedure


Procedure.i ISOweek (date.i)
   ; The calculations are based on the fact that the first week of a year
   ; always contains January 4.
   ; [according to http://en.wikipedia.org/wiki/Seven-day_week#Week_numbering
   ;  or better    http://de.wikipedia.org/wiki/Woche#Kalenderwoche]
   
   Protected doy.i=DayOfYear(date), year.i=Year(date)
   Protected lastPrev.i  ; last day of last week of previous year
   Protected lastThis.i  ; last day of last week of current  year
   
   lastPrev = 4 - ISOdayOfWeek(Date(year, 1, 4, 0,0,0))
   lastThis = 4 - ISOdayOfWeek(Date(year,12,28, 0,0,0)) + DayOfYear(Date(year,12,31, 0,0,0))
   
   If doy <= lastThis
      If doy <= lastPrev
         ; The given day is in the last week of the previous year.
         doy + DayOfYear(Date(year-1,12,31, 0,0,0))
         lastPrev = 4 - ISOdayOfWeek(Date(year-1,1,4, 0,0,0))
      EndIf
      ProcedureReturn Round((doy-lastPrev)/7, #PB_Round_Up)
   Else
      ; The given day is in the first week of the next year.
      ProcedureReturn 1
   EndIf
EndProcedure


; -- Demo
Debug ISOweek(Date(2009,12,31, 0,0,0))  ; 53

Debug ISOweek(Date(2010, 1, 1, 0,0,0))  ; 53
Debug ISOweek(Date(2010, 1, 2, 0,0,0))  ; 53
Debug ISOweek(Date(2010, 1, 3, 0,0,0))  ; 53
Debug ISOweek(Date(2010, 1, 4, 0,0,0))  ;  1
Debug ISOweek(Date(2010,12,31, 0,0,0))  ; 52

Debug ISOweek(Date(2011, 1, 1, 0,0,0))  ; 52
Debug ISOweek(Date(2011, 1, 2, 0,0,0))  ; 52
Debug ISOweek(Date(2011, 1, 3, 0,0,0))  ;  1
Debug ISOweek(Date(2011,12,31, 0,0,0))  ; 52

Debug ISOweek(Date(2012, 1, 1, 0,0,0))  ; 52
Debug ISOweek(Date(2012, 1, 2, 0,0,0))  ;  1
Debug ISOweek(Date(2012,12,30, 0,0,0))  ; 52
Debug ISOweek(Date(2012,12,31, 0,0,0))  ;  1

Re: ISO weeknumber

Posted: Mon Aug 12, 2013 10:29 am
by Little John
Hi TI-994A,

I think I've found a bug in your code. :-)

Try

Code: Select all

Debug ISOWeek(Date(2012,12,31, 0,0,0))
That yields 53, but it should be 1 (according to my paper calendar, or e.g. to this webpage).

Re: ISO weeknumber

Posted: Mon Aug 12, 2013 4:53 pm
by TI-994A
Little John wrote:I think I've found a bug in your code. :-)
Hello Little John. You're right; thank you for the catch. I've modified the code in my earlier post, and it now includes a check to validate the 53rd week. :)

Re: ISO weeknumber

Posted: Mon Aug 12, 2013 7:56 pm
by blueznl
The brilliance in this forum never fails to amaze me... thanks all! (Weeknumber made it into my little graphical experiment.)

Re: ISO weeknumber

Posted: Wed Mar 30, 2016 5:53 pm
by Michael Vogel
I did a short one including some prime numbers...

Code: Select all

Procedure ISOWeek(date)
	date=date/86400+3
	ProcedureReturn (date-(Date(Year((date-date%7)*86400),1,date%7+5,0,0,0)/86400-11))/7
EndProcedure

Debug ISOWeek(Date())
Debug ISOWeek(Date(1997, 12, 29, 0, 0, 0)) ;week #1
Debug ISOWeek(Date(2012, 12, 31, 0, 0, 0)) ;week #1
Debug ISOWeek(Date(2012, 1, 1, 0, 0, 0))   ;week #52
Debug ISOWeek(Date(2016, 1, 1, 0, 0, 0))   ;week #53

Re: ISO weeknumber

Posted: Mon Sep 06, 2021 6:40 pm
by Fig
Sorry, Mickael, your code is wrong, I just discovered it today (I was using your snipet in a software ^^)
Today we are in the 35 week and your snipet gives 36...

Too bad, your solution was pretty elegant... :wink: