Example on how to calculate the week number of the year from a date
function WeekNumber returns integer ( ptDate as date ):
define var iDay as int no-undo.
iDay = ptDate - date( 1, 1, year( ptDate ) ) + 1. /* days from the beginning of the year */
return int( trunc( iDay / 7, 0 ) ) /* weeks past */
+ ( if iDay mod 7 <> 0 then 1 else 0 ). /* if entered another week also count that week */
end function. /* WeekNumber */
function QuarterNumber returns integer ( ptDate as date ):
define var iMonth as int no-undo.
iMonth = month( ptDate ).
return int( trunc( iMonth / 3, 0 ) ) /* quarters past */
+ ( if iMonth mod 3 <> 0 then 1 else 0 ). /* if entered another quarter also count that quarter */
end function. /* QuarterNumber */
FUNCTION ISOWeekDay returns INTEGER ( ptDate AS DATE ):
DEF VAR v_Weekday AS INTE EXTENT 7 NO-UNDO INITIAL [7,1,2,3,4,5,6].
RETURN v_Weekday[WEEKDAY(ptdate)].
END FUNCTION.
FUNCTION ISOWeekNumber returns INTEGER ( ptDate AS DATE ):
/* Returns the ISO week number
Don't use the progress function WEEKDAY, as that starts on Sunday when the ISO weeks start on Monday! */
DEF VAR v_Offset AS INTE NO-UNDO.
DEF VAR v_Days AS INTE NO-UNDO.
DEF VAR v_WeekNumber AS INTE NO-UNDO.
IF ISOWeekday(ptDate) LT 5 THEN v_offset = 1. /* Offset by Thursdays */
v_Days = ptDate - DATE( 1, 1, year( ptDate ) ) + 1. /* get number of days */
v_WeekNumber = INTE(ROUND(v_days / 7,0 )) + v_offset. /* calculate week number */
IF v_WeekNumber = 53 AND v_OffSet = 1 THEN v_WeekNumber = 1. /* last week of the year is actually the first week of the next year */
IF v_WeekNumber = 0 AND v_OffSet = 0 THEN v_WeekNumber = 53. /* First week in the year is actually the last week of the previous year */
RETURN v_WeekNumber.
END FUNCTION. /* ISOWeekNumber */
Code:function WeekNumber returns integer ( ptDate as date ): define var iDay as int no-undo. iDay = ptDate - date( 1, 1, year( ptDate ) ) + 1. /* days from the beginning of the year */ return int( trunc( iDay / 7, 0 ) ) /* weeks past */ + ( if iDay mod 7 <> 0 then 1 else 0 ). /* if entered another week also count that week */ end function. /* WeekNumber */ function QuarterNumber returns integer ( ptDate as date ): define var iMonth as int no-undo. iMonth = month( ptDate ). return int( trunc( iMonth / 3, 0 ) ) /* quarters past */ + ( if iMonth mod 3 <> 0 then 1 else 0 ). /* if entered another quarter also count that quarter */ end function. /* QuarterNumber */
Hope this helps.
This actually calculates from the first day of the year... For example, if the frist day of the year falls on a wednesday, that becomes the first day of the "week", and calculations are done against that...
This should do the trick, and I think it is ISO compliant (at least, what I could test)...
Code:instead of ROUND(v_days / 7,0 ) you should be using TRUNC(v_days/7,0) FUNCTION ISOWeekDay returns INTEGER ( ptDate AS DATE ): DEF VAR v_Weekday AS INTE EXTENT 7 NO-UNDO INITIAL [7,1,2,3,4,5,6]. RETURN v_Weekday[WEEKDAY(ptdate)]. END FUNCTION. FUNCTION ISOWeekNumber returns INTEGER ( ptDate AS DATE ): /* Returns the ISO week number Don't use the progress function WEEKDAY, as that starts on Sunday when the ISO weeks start on Monday! */ DEF VAR v_Offset AS INTE NO-UNDO. DEF VAR v_Days AS INTE NO-UNDO. DEF VAR v_WeekNumber AS INTE NO-UNDO. IF ISOWeekday(ptDate) LT 5 THEN v_offset = 1. /* Offset by Thursdays */ v_Days = ptDate - DATE( 1, 1, year( ptDate ) ) + 1. /* get number of days */ v_WeekNumber = INTE(ROUND(v_days / 7,0 )) + v_offset. /* calculate week number */ IF v_WeekNumber = 53 AND v_OffSet = 1 THEN v_WeekNumber = 1. /* last week of the year is actually the first week of the next year */ IF v_WeekNumber = 0 AND v_OffSet = 0 THEN v_WeekNumber = 53. /* First week in the year is actually the last week of the previous year */ RETURN v_WeekNumber. END FUNCTION. /* ISOWeekNumber */
Comments, suggestions?
FUNCTION ISOWeekDay returns INTEGER ( ptDate AS DATE ):
DEF VAR v_Weekday AS INTE EXTENT 7 NO-UNDO INITIAL [7,1,2,3,4,5,6].
RETURN v_Weekday[WEEKDAY(ptdate)].
END FUNCTION.
FUNCTION ISOWeekNumber returns INTEGER ( ptDate AS DATE ):
/* Returns the ISO week number
Don't use the progress function WEEKDAY, as that starts on Sunday when the ISO weeks start on Monday! */
DEF VAR v_Offset AS INTE NO-UNDO.
DEF VAR v_Days AS INTE NO-UNDO.
DEF VAR v_WeekNumber AS INTE NO-UNDO.
IF ISOWeekday(ptDate) LT 5 THEN v_offset = 1. /* Offset by Thursdays */
v_Days = ptDate - DATE( 1, 1, year( ptDate ) ) + 1. /* get number of days */
v_WeekNumber = INTE(TRUNC(v_days / 7,0 )) + v_offset. /* calculate week number */
IF v_WeekNumber = 53 AND v_OffSet = 1 THEN v_WeekNumber = 1. /* last week of the year is actually the first week of the next year */
IF v_WeekNumber = 0 AND v_OffSet = 0 THEN v_WeekNumber = 53. /* First week in the year is actually the last week of the previous year */
RETURN v_WeekNumber.
END FUNCTION. /* ISOWeekNumber */
FUNCTION ISOWeekDay returns INTEGER ( ptDate AS DATE ):
DEF VAR v_Weekday AS INTE EXTENT 7 NO-UNDO INITIAL [7,1,2,3,4,5,6].
RETURN v_Weekday[WEEKDAY(ptdate)].
END FUNCTION.
FUNCTION ISOWeekNumber returns INTEGER ( ptDate AS DATE ):
/* Returns the ISO week number
Don't use the progress function WEEKDAY, as that starts on Sunday when the ISO weeks start on Monday! */
DEF VAR v_Days AS INTE NO-UNDO.
DEF VAR v_WeekNumber AS INTE NO-UNDO.
DEF VAR v_WeekMonday AS DATE NO-UNDO.
DEF VAR v_WeekThursday AS DATE NO-UNDO.
DEF VAR v_WeekSunday AS DATE NO-UNDO.
v_WeekMonday = ptDate - ISOWeekDay( ptDate ) + 1. /* Start of week */
v_WeekThursday = v_WeekMonday + 3.
v_WeekSunday = v_WeekMonday + 6.
v_Days = v_WeekMonday - DATE( 1, 1, YEAR( ptDate ) ). /* get number of days for monday*/
v_WeekNumber = INTE(ROUND(v_Days / 7,0 ) ) + 1. /* calculate week number */
IF v_WeekNumber = 53 THEN DO /* work where the overlapping week sits */
:
IF YEAR(v_WeekThursday) = YEAR(ptDate)
THEN v_WeekNumber = 53.
ELSE v_WeekNumber = 1.
END.
IF v_WeekNumber = 0 THEN v_WeekNumber = 53.
RETURN v_WeekNumber.
END FUNCTION. /* ISOWeekNumber */
Are you working on a Windows or *nix solution?I'm new to progress and checking out the solution but still the logic doesn't seem correct
For date 01/01/2022 it should give 52 (in ISO date) but actually it gives 53. Please correct me if I'm wrong.
can anyone provide a solution that can actually gives ISO week number
thanks in advance..
windows 10, progress 11.7Are you working on a Windows or *nix solution?
/* own construction!! based on ISO-8601 rules for weeks of the year (week always starts with a Monday)
week 1 is the week with the first Thursday of the year
Verified output with https://www.calendar-12.com/week_number
*/
define variable v-DAfirst as date no-undo.
define variable v-NRweek as integer no-undo.
/* ISO-rule (also see Online calculator: Week number of a given date
The first week of the year is the week that includes the first thursday of the year or week with the 4 jan in it */
assign v-DAfirst = date(substitute("01/01/&1", year(p-DAin))).
if weekday(v-DAfirst) eq 1 or weekday(v-DAfirst) gt 5 then
assign v-DAfirst = date(substitute("4/1/&1", year(p-DAin))). /* 4 jan always falls in the first week of the year */
/* if the provided date is earlier then the Monday of the calculated first week of the year of the requested date
then search for the first day of the previous year because it will be week 52/53 */
if p-DAin < v-DAfirst then
do:
assign v-DAfirst = date(month(p-DAin), 1, year(p-DAin) - 1).
if weekday(v-DAfirst) eq 1 or weekday(v-DAfirst) gt 5 then
assign v-DAfirst = date(substitute("4/1/&1", year(v-DAfirst))). /* 4 jan always falls in the first week of the year */
end.
assign v-DAfirst = v-DAfirst - weekday(v-DAfirst) + 2
v-NRweek = truncate(interval(p-DAin, v-DAfirst, "day") / 7, 0) + 1.
/* when the calculated week is 53 and the month of the requested date is december (could also be januari)
then check is it's not the first week of the next year */
if v-NRweek = 53 and month(p-DAin) eq 12 then
do:
assign v-DAfirst = date(substitute("01/01/&1", year(p-DAin) + 1)).
if weekday(v-DAfirst) gt 5 then
assign v-DAfirst = date(substitute("4/1/&1", year(p-DAin))). /* 4 jan always falls in the first week of the year */
if truncate(interval(p-DAin, v-DAfirst, "day") / 7, 0) + 1 eq 1 then
assign v-NRweek = 1.
end.
I agree but for me that is not an issue ... we are sure about the seRepeatedly dating a substituted string with an assumed session DMY format is asking for trouble.
Use the date function with three integer inputs for month, day and year, it will work regardless of the session settings:
mhhhh, indeed ...hey Den... normally it seems fine. correct me if I'm wrong but for date 01/03/2022 it should give 1 but it gives 53
thank you.
// SOURCE https://docs.microsoft.com/en-us/dotnet/api/system.globalization.calendar.getweekofyear?view=net-6.0
using System.*.
using System.Globalization.*.
function getWeekNumber returns integer (input pDateTime as datetime ):
DEFINE VARIABLE myCI as class CultureInfo NO-UNDO.
DEFINE variable myCal as class Calendar NO-UNDO.
DEFINE VARIABLE myCWR as class CalendarWeekRule NO-UNDO.
DEFINE VARIABLE myFirstDOW as class DayOfWeek NO-UNDO.
// Gets the Calendar instance associated with a CultureInfo.
myCI = new CultureInfo("en-NZ").
myCal = myCI:Calendar.
// Gets the DTFI properties required by GetWeekOfYear.
myFirstDOW = myCI:DateTimeFormat:FirstDayOfWeek.
myCWR = myCI:DateTimeFormat:CalendarWeekRule.
return myCal:GetWeekOfYear( pDateTime , myCWR, myFirstDOW ).
finally:
if valid-object(myCI) Then
delete object myCI.
end.
end function.
message "Date:" string(today,"99/99/9999") skip
"Week Number:"getWeekNumber(input datetime(today) )
view-as alert-box info title "Get Week Number".
// SOURCE https://docs.microsoft.com/en-us/dotnet/api/system.globalization.calendar.getweekofyear?view=net-6.0
using System.*.
using System.Globalization.*.
function getWeekNumber returns integer (input pDateTime as datetime ):
DEFINE VARIABLE myCI as class CultureInfo NO-UNDO.
DEFINE variable myCal as class Calendar NO-UNDO.
DEFINE VARIABLE myCWR as class CalendarWeekRule NO-UNDO.
DEFINE VARIABLE myFirstDOW as class DayOfWeek NO-UNDO.
// Gets the Calendar instance associated with a CultureInfo.
myCI = new CultureInfo("en-NZ").
myCal = myCI:Calendar.
// Gets the DTFI properties required by GetWeekOfYear.
myFirstDOW = myCI:DateTimeFormat:FirstDayOfWeek. // FirstDayOfWeek System Defined
myCWR = myCI:DateTimeFormat:CalendarWeekRule. // CalendarWeekRule System Defined
//Debug
// message myFirstDOW:ToString().
// message myCWR:ToString().
// Override the systems CalendarWeekRule
// myCWR = CalendarWeekRule:FirstDay. // Indicates that the first week of the year starts on the first day of the year and ends before the following designated first day of the week.
// myCWR = CalendarWeekRule:FirstFourDayWeek. //Indicates that the first week of the year is the first week with four or more days before the designated first day of the week.
myCWR = CalendarWeekRule:FirstFullWeek. // Indicates that the first week of the year begins on the first occurrence of the designated first day of the week on or after the first day of the year
// message myCWR:ToString().
return myCal:GetWeekOfYear( pDateTime , myCWR, myFirstDOW ).
finally:
if valid-object(myCI) Then
delete object myCI.
end.
end function.
message "Date:" string(today,"99/99/9999") skip
"Week Number:"getWeekNumber(input datetime(today) )
view-as alert-box info title "Get Week Number".