current number of the week in a year



IBM's Command List programming language & Restructured Extended Executor

current number of the week in a year

Postby dohara » Sat Jul 31, 2010 3:39 pm

I need to calculate the number of the current week in a year in ISO 8601 form. I thought it is easy but so far i have tried 5 times and failed 5 times.

Can you think of any built in functions in REXX, JCL, ISPF, etc... that I could use or anyone has managed to put together a code that is working fine?
Normally i do not ask anyone to write a code to me as i can go with redbooks and guidance but here i give up
Probably i've become too obsessed with this weeknumber thing and can't see where i get it wrong.

thanks,
david



Please see the below description of what ISO 8601 calendar format means:

"The ISO 8601 Calendar
This week numbering scheme was introduced earlier by the ISO with the standard ISO 2015:1976 (Numbering of Weeks) and was repealed on 1 June 1988 with the imminent introduction of ISO 8601. The calendar defined in the ISO standards 2015 and 8601 is commonly referred to as the “ISO calendar”.

The ISO calendar corresponds with the Gregorian calendar (sect. 3.2.1 on pp. 7-8) and uses the same year number but as its length is defined to be an integral number of weeks, its beginning can deviate up to a few days from 1 January and its end likewise can deviate up to a few days from 31 December. On average, however, it remains in step with the Gregorian calendar.

The week in the ISO calendar is defined (sect. 2.2.8 on p. 5) as a:

time interval of seven calendar days starting with a Monday [...] identified by its ordinal number within its calendar year.
The numbering of the ISO calendar weeks is defined (sect. 2.2.10 on p. 5) as:

[...] the first calendar week of a year is that one which includes the first Thursday of that year and [...] the last calendar week of a calendar year is the week immediately preceding the first calendar week of the next calendar year.
Another way of stating the above rule is that the first week of the ISO calendar year is the earliest week that contains at least four days of the month of January. Likewise, the last week of the ISO calendar year is the last week that contains at least four days of the month of December."
dohara
 
Posts: 42
Joined: Thu Apr 09, 2009 3:15 pm
Has thanked: 0 time
Been thanked: 1 time

Re: current number of the week in a year

Postby NicC » Sat Jul 31, 2010 10:04 pm

JCL does not have sub-routines, or even routines. ISPF likewise. I think you can do what you want using the Rexx date function with different parameters. DATE('W',20100101,'S'), for example, gives the first day of the year 2010 (Friday). This should give you a start.
The problem I have is that people can explain things quickly but I can only comprehend slowly.
Regards
Nic
NicC
Global moderator
 
Posts: 3025
Joined: Sun Jul 04, 2010 12:13 am
Location: Pushing up the daisies (almost)
Has thanked: 4 times
Been thanked: 136 times

Re: current number of the week in a year

Postby dohara » Tue Aug 03, 2010 4:22 am

Hi

At last i put it together.
If any of you ever needed to calculate the current week number of a year in ISO 8601 format, then here it goes.

cheers,
David


/* rexx - calculate weekno in ISO_8601 format */

indate = '20100102'

cyear = Substr(indate,1,4) /* current year */
fcday = date('W','1 Jan 'cyear) /* Jan 1 of curr year */
lcday = date('W','31 Dec 'cyear) /* Dec 31 of curr year */
cdate = date("B",indate,"S") /* current date in BASE format */

pyear = cyear - 1 /* previous year */
fpday = date('W','1 Jan 'pyear) /* Jan 1 of previous year */
lpday = date('W','31 Dec 'pyear) /* Dec 31 of previous year */

Call CALCPYSE /* Calc prev year's START&END date */
Call CALCCYSE /* Calc curr year's START&END date */

Select
When cdate < scy then cweekno = pweekno
When cdate > ecy then cweekno = 1
When cdate >= scy & cdate <= ecy then
Do
cdayno = (cdate - scy) + 1 /* number of the curr day in BASE */
weekraw = cdayno / 7
Parse var weekraw cweekno '.' rest
If rest <> '' then
cweekno = cweekno + 1
End
Otherwise nop
End

Say 'Current weekno of the year is:' cweekno

Exit 0
/*-------------------------------------------------------*/
/* Get start and end dates of the previous year */
/*-------------------------------------------------------*/
CALCPYSE:

Select
When fpday = 'Monday' then spy = pyear!!'01'!!'01'
When fpday = 'Tuesday' then spy = pyear-1!!'12'!!'31'
When fpday = 'Wednesday' then spy = pyear-1!!'12'!!'30'
When fpday = 'Thursday' then spy = pyear-1!!'12'!!'29'
When fpday = 'Friday' then spy = pyear!!'01'!!'04'
When fpday = 'Saturday' then spy = pyear!!'01'!!'03'
When fpday = 'Sunday' then spy = pyear!!'01'!!'02'
Otherwise nop
End

Select
When lpday = 'Monday' then epy = pyear!!'12'!!'30'
When lpday = 'Tuesday' then epy = pyear!!'12'!!'29'
When lpday = 'Wednesday' then epy = pyear!!'12'!!'28'
When lpday = 'Thursday' then epy = cyear!!'01'!!'03'
When lpday = 'Friday' then epy = cyear!!'01'!!'02'
When lpday = 'Saturday' then epy = cyear!!'01'!!'01'
When lpday = 'Sunday' then epy = pyear!!'12'!!'31'
Otherwise nop
End

spy = date("B",spy,"S") /* Start date of the prev year BASE*/
epy = date("B",epy,"S") /* End date of the prev year BASE*/
allpd = (epy - spy) + 1 /* All days of the prev year */
weekraw = allpd / 7
Parse var weekraw pweekno '.' rest
If rest <> '' then
pweekno = pweekno + 1 /* All weeks of the prev year */

Return

/*-------------------------------------------------------*/
/* get start and end dates of the current year */
/*-------------------------------------------------------*/
CALCCYSE:

Select
When fcday = 'Monday' then scy = cyear!!'01'!!'01'
When fcday = 'Tuesday' then scy = pyear!!'12'!!'31'
When fcday = 'Wednesday' then scy = pyear!!'12'!!'30'
When fcday = 'Thursday' then scy = pyear!!'12'!!'29'
When fcday = 'Friday' then scy = cyear!!'01'!!'04'
When fcday = 'Saturday' then scy = cyear!!'01'!!'03'
When fcday = 'Sunday' then scy = cyear!!'01'!!'02'
Otherwise nop
End

Select
When lcday = 'Monday' then ecy = cyear!!'12'!!'30'
When lcday = 'Tuesday' then ecy = cyear!!'12'!!'29'
When lcday = 'Wednesday' then ecy = cyear!!'12'!!'28'
When lcday = 'Thursday' then ecy = cyear+1!!'01'!!'03'
When lcday = 'Friday' then ecy = cyear+1!!'01'!!'02'
When lcday = 'Saturday' then ecy = cyear+1!!'01'!!'01'
When lcday = 'Sunday' then ecy = cyear!!'12'!!'31'
Otherwise nop
End

scy = date("B",scy,"S") /* Start date of the curr year BASE*/
ecy = date("B",ecy,"S") /* End date of the curr year BASE*/

Return
dohara
 
Posts: 42
Joined: Thu Apr 09, 2009 3:15 pm
Has thanked: 0 time
Been thanked: 1 time

Re: current number of the week in a year

Postby enrico-sorichetti » Thu Aug 05, 2010 9:18 pm

the request as posted does not make any sense!

when expressing a date as an ISO-date also the year might change
for example jan 1, 2010 is 2009-53-04
telling simply the week is kind of incomplete info

so in might be better to ask the powers of Your organization about the exact requirement!

also the suggestion about the usage of date("W", ... ) made You follow a complicated approach

here are two algorithmic samples
no checking is done on the validity of the dates

the first one uses as input to the date2iso function the YYYYMMDD format
/* REXX
   y      year
   d      day
   w      week

   s      date sorted   yyyymmdd
   b      date base   ( as per rexx definition 0 = monday/00010101 )

   fwky   procedure,
         returnd the base date of the monday of the first week of a year
         the week containin the thursday

   iso1   procedure,
         format the iso date appropriately
*/

do   y = 2001 to 2010
   say right(y, 4, "0" ) "0101" date2iso(right(y, 4, "0" ) || "0101" ) "1231" date2iso(right(y, 4, "0" ) || "1231")
end
exit

date2iso : procedure
   parse arg s
   b = date("B", s, "S")
   y = left(s, 4 )

   /* the easy one first */
   if   b >= fwky(y+1 ) then ,
      return iso1(y+1, 1, b // 7 + 1 )

   if   b >= fwky(y ) then do
      w = b % 7 - fwky(y ) % 7 + 1
      return iso1(y,   w, b // 7 + 1 )
   end

   w = b % 7 - fwky(y-1 ) % 7 + 1
   return iso1(y-1, w, b // 7 + 1 )

fwky: procedure
   /* base date of the first week of the year */
   parse arg y
   w = date("b", right(y, 4, "0" ) || "01" || "01", "s" )
   d = w // 7 + 1
   if   d <= 4 then ,
      return w + 1 - d
   else
      return w + 1 - d + 7

iso1: procedure
   parse arg y, w, d
   return right(y, 4, "0" ) || right(w, 2, "0" ) || right(d, 2, "0" )


the second one uses as input to the date2iso function year, month, day
/* REXX
   y      year
   m      month
   d      day
   w      week

   bday   procedure,
         returns the base date of a given y, m, d

   fwky   procedure,
         returnd the base date of the monday of the first week of a year
         the week containin the thursday

   dofw   procedure,
         returnd the day of the week ( 1-monday ... 7-sunday )

   iso1   procedure,
         format the iso date appropriately

*/

do   y = 2001 to 2010
   say right(y, 4, "0" ) "0101" date2iso(y, 1, 1 ) "1231" date2iso(y, 12, 31 )
end

exit

date2iso : procedure
   parse arg y, m, d

   /* the easy one first */
   if   bday(y, m, d ) >= fwky(y+1 ) then ,
      return iso1(y+1, 1, dofw(y, m, d ) )

   if   bday(y, m, d ) >= fwky(y ) then do
      w = bday(y, m, d ) % 7 - fwky(y ) % 7 + 1
      return iso1(y, w, dofw(y, m, d ) )
   end

   w = bday(y, m, d ) % 7 - fwky(y-1 ) % 7 + 1
   return iso1(y-1, w, dofw(y, m, d ) )

fwky: procedure
   /* base date of the first week of the year */
   parse arg y
   w = date("b", right(y, 4, "0" ) || "01" || "01", "s" )
   d = w // 7 + 1
   if   d <= 4 then ,
      return w + 1 - d
   else
      return w + 1 - d + 7

bday: procedure
   /* base date of a bday  */
   parse arg y, m, d
   return date("b", right(y, 4, "0" ) || right(m, 2, "0" ) || right(d, 2, "0" ), "s" )

dofw: procedure
   /* bday of week ( 1-Monday to 7-Sunday )  */
   parse arg y, m, d
   return date("b", right(y, 4, "0" ) || right(m, 2, "0" ) || right(d, 2, "0" ), "s" ) // 7 + 1

iso1: procedure
   parse arg y, w, d
   return right(y, 4, "0" ) || right(w, 2, "0" ) || right(d, 2, "0" )

exit




I developed the above on my own,
googling for ISO DATE ALGORITHM[S] will give lots of interesting links
even a cobol written one !
cheers
enrico
When I tell somebody to RTFM or STFW I usually have the page open in another tab/window of my browser,
so that I am sure that the information requested can be reached with a very small effort
enrico-sorichetti
Global moderator
 
Posts: 2994
Joined: Fri Apr 18, 2008 11:25 pm
Has thanked: 0 time
Been thanked: 164 times

Re: current number of the week in a year

Postby dohara » Sat Aug 07, 2010 9:10 pm

Hi Enrico


thanks for the point.

Cheers
David
dohara
 
Posts: 42
Joined: Thu Apr 09, 2009 3:15 pm
Has thanked: 0 time
Been thanked: 1 time

Re: current number of the week in a year

Postby enrico-sorichetti » Sat Aug 07, 2010 9:58 pm

since I am in a very good mood ...
here is a a new REXX wich contains

a DATE2ISO
an ISO2DATE

the new format of the ISO date was chosen according to the common practice yyyyWwwd

the script takes as input a Year and an optional count and it will check that the iso2date of a date2iso gives back the original

tested using ... scriptname 1 4000 and no errors were found
the elapsed was 3 minutes
here is the shebang
/* REXX
   y      year
   d      day
   w       week

   s      date sorted   yyyymmdd
   b      date base   ( as per rexx definition 0 = monday/00010101 )

   fwky   procedure,
         returnd the base date of the monday of the first week of a year
         the week containin the thursday

   iso1   procedure,
         format the iso date appropriately

*/

parse arg s k
if k = "" then k = 1

f = date("b",right(s,4,"0") || "0101", "S")
t = date("b",right(s+k,4,"0") || "0101", "S" ) - 1

do   b  = f to t
   s = date("S",b,"B")
   i = date2iso(s)
   if   s !=  i then do
      say "error for" b s i
      exit
   end
   if   k = 1 then ,
      say s b i
end

exit

date2iso : procedure
   parse arg s
   b = date("B", s, "S")
   y = left(s, 4 )

   /* the easy one first */
   if   b >= fwky(y+1 ) then ,
      return iso1(y+1, 1, b // 7 + 1 )

   if   b >= fwky(y ) then do
      w = b % 7 - fwky(y ) % 7 + 1
      return iso1(y, w, b // 7 + 1 )
   end

   w = b % 7 - fwky(y-1 ) % 7 + 1
   return iso1(y-1, w, b // 7 + 1 )

iso1: procedure
   parse arg y, w, d
   return right(y, 4, "0" ) || "W" || right(w, 2, "0" ) || d

iso2date:procedure
   parse arg i
   parse var i with 1 y 5 . 6 w 8 d
   b = fwky(y ) + (w - 1 )*7 + d - 1
   return date("S", b, "B")

fwky: procedure
   /* base date of the first week of the year */
   parse arg y
   w = date("b", right(y, 4, "0" ) || "01" || "01", "s" )
   d = w // 7 + 1
   if   d <= 4 then ,
      return w + 1 - d
   else
      return w + 1 - d + 7


having a REXX optimized initial algorithm the reverse was very quick to implement
the whole trick resides in the proper computation of the first week of the year
and the awareness of the power of the REXX base date representation
cheers
enrico
When I tell somebody to RTFM or STFW I usually have the page open in another tab/window of my browser,
so that I am sure that the information requested can be reached with a very small effort
enrico-sorichetti
Global moderator
 
Posts: 2994
Joined: Fri Apr 18, 2008 11:25 pm
Has thanked: 0 time
Been thanked: 164 times

Re: current number of the week in a year

Postby enrico-sorichetti » Sun Aug 15, 2010 5:25 pm

follow on ...
in my previous post there was a double typo

the section
   if   s !=  i then do
      say "error for" b s i
      exit
   end


should be
   if   s \=  iso2date(i) then do
      say "error for" b s i
      exit
   end


the first typo was not calling the iso2date to reverse the format
the second typo was an error in the compound operator

note note note...
on the rexx related forums there is a lot of discussion about whitespaces and
double chars operators

rexx does not require that the char of double chars operators should be contiguous

so apart the missing call to iso2date
the statement
if s != i then   

is interpreted as ( in plain words )
if s concatenated to ! is equal to i

so all the rexxers beware about not comparisons :D

for example ...
if a \     = b then

is considered a valid not equal comparison

on the other said contiguous unrelated chars is considered as a concatenation
as shown in my code snippet

just for the sake of completeness the script works correctly also after the correction

the interested people should find by themselves why the false positive check :D
cheers
enrico
When I tell somebody to RTFM or STFW I usually have the page open in another tab/window of my browser,
so that I am sure that the information requested can be reached with a very small effort
enrico-sorichetti
Global moderator
 
Posts: 2994
Joined: Fri Apr 18, 2008 11:25 pm
Has thanked: 0 time
Been thanked: 164 times

Re: current number of the week in a year

Postby enrico-sorichetti » Mon Aug 16, 2010 4:22 pm

another follow on...
about the NOT operator and | vs. !
I am working with different rexx interpreters on my mac
and the scripts I post usually follow the syntax and conventions
of the last interpreter used on a successful run

so before using any script posted please check for single chars incompatibilities
for example the ^= vs. vs. |= != vs. \= vs. /= vs. <>
most probably the <> even if the worst looking is the safer one not relying on any odd char
cheers
enrico
When I tell somebody to RTFM or STFW I usually have the page open in another tab/window of my browser,
so that I am sure that the information requested can be reached with a very small effort
enrico-sorichetti
Global moderator
 
Posts: 2994
Joined: Fri Apr 18, 2008 11:25 pm
Has thanked: 0 time
Been thanked: 164 times


Return to CLIST & REXX

 


  • Related topics
    Replies
    Views
    Last post