Skip to content

Commit

Permalink
fix #1809 Wrong week numbers displayed in aria:Calendar (and aria:Dat…
Browse files Browse the repository at this point in the history
…ePicker)

The calendar widget now uses aria.utils.Date.getWeekNumber (which is compliant
with standard rules) to compute the week number, instead of considering
that the first week of the year is the first full week.
For example, in 2019, if the first day of the week is Monday, week 1
should start on 31/12/2018 and not on 07/01/2019.

This commit extends aria.utils.Date.getWeekNumber to allow any day of the
week to be specified as the first day of the week.
If Monday is selected, rules from ISO 8601 are applied (the first week of
the year is the week containing January 4th).
Otherwise, the first week of the year is the week containing January 1st.

PTR 16422165
  • Loading branch information
divdavem committed Jan 25, 2019
1 parent 40b097e commit ab43afe
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 112 deletions.
84 changes: 35 additions & 49 deletions src/aria/utils/Date.js
Expand Up @@ -188,8 +188,6 @@ var parseNextSteps = function(state, options) {

};



/**
* This class contains utilities to manipulate Dates.
*/
Expand Down Expand Up @@ -509,7 +507,6 @@ var ariaUtilsDate = module.exports = Aria.classDefinition({
INVALID_FORMAT_TYPE : "'pattern' parameter passed to Date.format has to be a string or a function",
INVALID_INPUT_PATTERN_TYPE : "Defined pattern : %1 inputPattern can only be a string, a function or an array of strings and/or functions",
INVALID_INPUT_PATTERN_DUPLICATE : "Invalid pattern in inputPattern property definition: %1 year, month or day is duplicated",
INVALID_FIRST_DAY_OF_WEEK : "Invalid first day of week. Received: %1 while allowed values are: 0, 1, 6.",

// DAYS OF WEEK FOR WEEK-START:
SUNDAY : 0,
Expand Down Expand Up @@ -1608,6 +1605,20 @@ var ariaUtilsDate = module.exports = Aria.classDefinition({

},

/**
* Returns the position of the date in the week.
* @param {Date} date
* @param {Number} firstDayOfWeek [optional, default depending on the regional settings] day to be defined as
* the first in the week, 0 = sunday, 1 = monday ...
* @returns 0 if the date is the first day in its week
*/
getDayInWeek: function (date, firstDayOfWeek) {
if (firstDayOfWeek == null) {
firstDayOfWeek = this._environment.getFirstDayOfWeek();
}
return (7 + date.getDay() - firstDayOfWeek) % 7;
},

/**
* Return the first day of the week which contains date.
* @public
Expand All @@ -1617,15 +1628,8 @@ var ariaUtilsDate = module.exports = Aria.classDefinition({
* @return {Date} the first day of the week which contains date.
*/
getStartOfWeek : function (date, firstDayOfWeek) {
if (firstDayOfWeek == null) {
firstDayOfWeek = this._environment.getFirstDayOfWeek();
}
var res = new Date(date);
var difference = date.getDay() - firstDayOfWeek;
if (difference < 0) {
difference += 7;
}
res.setDate(res.getDate() - difference);
res.setDate(res.getDate() - this.getDayInWeek(date, firstDayOfWeek));
return res;
},

Expand All @@ -1643,7 +1647,7 @@ var ariaUtilsDate = module.exports = Aria.classDefinition({
// in the summer
var d1 = Date.UTC(date1.getFullYear(), date1.getMonth(), date1.getDate());
var d2 = Date.UTC(date2.getFullYear(), date2.getMonth(), date2.getDate());
var res = (d2 - d1) / (1000 * 60 * 60 * 24);
var res = (d2 - d1) / this.MS_IN_A_DAY;
this.$assert(949, res == Math.round(res));
return res;
},
Expand Down Expand Up @@ -1679,21 +1683,20 @@ var ariaUtilsDate = module.exports = Aria.classDefinition({
dayOfWeekNbrSinceStartOfYear : function (date) {
var d1 = Date.UTC(date.getFullYear(), 0, 1);
var d2 = Date.UTC(date.getFullYear(), date.getMonth(), date.getDate());
var nbOfDays = (d2 - d1) / (1000 * 60 * 60 * 24); // number of days since
var nbOfDays = (d2 - d1) / this.MS_IN_A_DAY; // number of days since
// the begining of the
// year
this.$assert(981, nbOfDays == Math.round(nbOfDays));
return 1 + Math.floor(nbOfDays / 7);
},

/**
* Computes the week number for given date. It is locale-aware (week can start on Monday, Saturday or Sunday)
* and follows standards about week calculations for different cultures. Use this function in preference to
* Computes the week number for given date. It is locale-aware and follows standards
* about week calculations for different cultures. Use this function in preference to
* <code>dayOfWeekNbrSinceStartOfYear</code>.
* @param {Date} date The date you want to operate on.
* @param {Integer} firstDayOfWeek [optional] first day of week in the locale. Allowed values:
* <code>aria.utils.Date.{MONDAY|SUNDAY|SATURDAY}</code>. If not provided, it is read from the configuration
* environment. If disallowed value provided, an error is logged and the function returns.
* @param {Integer} firstDayOfWeek [optional] first day of week in the locale.
* If not provided, it is read from the configuration environment.
* @return {Integer} standardized week number for given inputs.
*/
getWeekNumber : function (date, firstDayOfWeek) {
Expand All @@ -1706,37 +1709,20 @@ var ariaUtilsDate = module.exports = Aria.classDefinition({
firstDayOfWeek = this._environment.getFirstDayOfWeek();
}

var refDay;
var refDate = new Date(date.getTime());

// we subtract certain amount of days, and then add fixed number to
// get reference day of the week
switch (firstDayOfWeek) {
case this.MONDAY :
// week starts on MON, we look for the following THU
refDay = refDate.getDate() + 4 - (refDate.getDay() || 7);
break;

case this.SUNDAY :
// week starts on SUN, we look for the following SAT
refDay = refDate.getDate() + 6 - (refDate.getDay());
break;

case this.SATURDAY :
// week starts on SAT, we look for the following FRI
refDay = refDate.getDate() + 6 - (refDate.getDay() + 1) % 7;
break;

default :
this.$logError(this.INVALID_FIRST_DAY_OF_WEEK, [firstDayOfWeek]);
return;
}
refDate.setDate(refDay); // can be negative, but JS handles it nicely
var refTime = refDate.getTime();

var january1 = new Date(refDate.getFullYear(), 0, 1);

return Math.floor(Math.round((refTime - january1) / this.MS_IN_A_DAY) / 7) + 1;
var isISO8601 = firstDayOfWeek === this.MONDAY;
// In ISO 8601 standard (i.e. the first day of the week is Monday), the first week of the year is the
// week containing January 4th, so the Thursday of a week determines the year the week belongs to.
// In other cases (non-ISO), the first week of the year is the week containing January 1st, so the last
// day of the week determines the year the week belongs to.

var dayInWeek = this.getDayInWeek(date, firstDayOfWeek);
var dayToDecideYear = isISO8601 ?
3 /* Thursday (0 is Monday in this case) */
: 6 /* Last day of the week */;
var dateToDecideYear = new Date(date.getFullYear(), date.getMonth(), date.getDate() - dayInWeek + dayToDecideYear, 12);
var firstWeekOfYear = new Date(dateToDecideYear.getFullYear(), 0, isISO8601 ? 4 /* January 4th*/ : 1 /* January 1st*/, 12);
var daysFromStartOfFirstWeek = this.dayDifference(this.getStartOfWeek(firstWeekOfYear, firstDayOfWeek), date);
return Math.floor(daysFromStartOfFirstWeek / 7) + 1;
},

/**
Expand Down
2 changes: 1 addition & 1 deletion src/aria/widgets/calendar/CalendarController.js
Expand Up @@ -720,7 +720,7 @@ module.exports = Aria.classDefinition({
var res = {
days : days,
indexInMonth : 1 + Math.floor((currentDate.getDate() - 2) / 7),
weekNumber : dateUtils.dayOfWeekNbrSinceStartOfYear(currentDate)
weekNumber : dateUtils.getWeekNumber(currentDate, currentDate.getDay())
};
for (var i = 0; i < 7; i++) {
var day = this._createDay(currentDate);
Expand Down
115 changes: 53 additions & 62 deletions test/aria/utils/DateTestCase.js
Expand Up @@ -472,26 +472,27 @@ Aria.classDefinition({
};
var monday = aria.utils.Date.MONDAY; // firstDayOdWeek

for (var year = 2010; year < 2022; year++) { // Test for 12 years

var firstJan = new Date(year, 0, 1, 0, 0, 0, 0); // Create the 1st January for each year
var first = aria.utils.Date.getWeekNumber(firstJan, monday);
this.assertEquals(firstIso[year], first, "Test 1st Jan " + year + " failed: " + firstIso[year] + " = "
+ first);

var fourthJan = new Date(year, 0, 4, 0, 0, 0, 0); // Create the 4th January for each year
var fourth = aria.utils.Date.getWeekNumber(fourthJan, monday);
this.assertEquals(1, fourth, "Test 4th Jan " + year + " failed: " + 1 + " = " + fourth);

var endYear = new Date(year, 11, 31, 0, 0, 0, 0); // Create the 31st December for each year
var end = aria.utils.Date.getWeekNumber(endYear, monday);
this.assertEquals(endIso[year], end, "Test end of the year " + year + " failed: " + endIso[year]
+ " = " + end);

var randomDate = new Date(year, 9, 28, 0, 0, 0, 0); // Create the 28th October for each year
var rand = aria.utils.Date.getWeekNumber(randomDate, monday);
this.assertEquals(random[year], rand, "Test random date " + year + " failed: " + random[year] + " = "
+ rand);
for (var hour = 0; hour < 24; hour++) { // Test for different hours in the day
for (var year = 2010; year < 2022; year++) { // Test for 12 years
var firstJan = new Date(year, 0, 1, hour, 0, 0, 0); // Create the 1st January for each year
var first = aria.utils.Date.getWeekNumber(firstJan, monday);
this.assertEquals(firstIso[year], first, "Test 1st Jan " + year + " failed: " + firstIso[year] + " = "
+ first);

var fourthJan = new Date(year, 0, 4, hour, 0, 0, 0); // Create the 4th January for each year
var fourth = aria.utils.Date.getWeekNumber(fourthJan, monday);
this.assertEquals(1, fourth, "Test 4th Jan " + year + " failed: " + 1 + " = " + fourth);

var endYear = new Date(year, 11, 31, hour, 0, 0, 0); // Create the 31st December for each year
var end = aria.utils.Date.getWeekNumber(endYear, monday);
this.assertEquals(endIso[year], end, "Test end of the year " + year + " failed: " + endIso[year]
+ " = " + end);

var randomDate = new Date(year, 9, 28, hour, 0, 0, 0); // Create the 28th October for each year
var rand = aria.utils.Date.getWeekNumber(randomDate, monday);
this.assertEquals(random[year], rand, "Test random date " + year + " failed: " + random[year] + " = "
+ rand);
}
}
},

Expand Down Expand Up @@ -529,21 +530,22 @@ Aria.classDefinition({
"2020" : 44,
"2021" : 44
}; // Values for the week number of Oct 28th

for (var year = 2010; year < 2022; year++) { // Test for 12 years
var firstJan = new Date(year, 0, 1, 0, 0, 0, 0); // Create the 1st January for each year
var first = aria.utils.Date.getWeekNumber(firstJan, sunday);
this.assertEquals(1, first, "Test 1st Jan " + year + " failed: " + 1 + " = " + first);

var endYear = new Date(year, 11, 31, 0, 0, 0, 0); // Create the 31st December for each year
var end = aria.utils.Date.getWeekNumber(endYear, sunday);
this.assertEquals(endUs[year], end, "Test end of the year " + year + " failed: " + endUs[year] + " = "
+ end);

var randomDate = new Date(year, 9, 28, 0, 0, 0, 0); // Create the 28th October for each year
var rand = aria.utils.Date.getWeekNumber(randomDate, sunday);
this.assertEquals(random[year], rand, "Test random date " + year + " failed: " + random[year] + " = "
+ rand);
for (var hour = 0; hour < 24; hour++) { // Test for different hours in the day
for (var year = 2010; year < 2022; year++) { // Test for 12 years
var firstJan = new Date(year, 0, 1, hour, 0, 0, 0); // Create the 1st January for each year
var first = aria.utils.Date.getWeekNumber(firstJan, sunday);
this.assertEquals(1, first, "Test 1st Jan " + year + " failed: " + 1 + " = " + first);

var endYear = new Date(year, 11, 31, hour, 0, 0, 0); // Create the 31st December for each year
var end = aria.utils.Date.getWeekNumber(endYear, sunday);
this.assertEquals(endUs[year], end, "Test end of the year " + year + " failed: " + endUs[year] + " = "
+ end);

var randomDate = new Date(year, 9, 28, hour, 0, 0, 0); // Create the 28th October for each year
var rand = aria.utils.Date.getWeekNumber(randomDate, sunday);
this.assertEquals(random[year], rand, "Test random date " + year + " failed: " + random[year] + " = "
+ rand);
}
}
},

Expand Down Expand Up @@ -582,20 +584,22 @@ Aria.classDefinition({
"2021" : 44
}; // Values for the week number of Oct 28th

for (var year = 2010; year < 2022; year++) { // Test for 12 years
var firstJan = new Date(year, 0, 1, 0, 0, 0, 0); // Create the 1st January for each year
var first = aria.utils.Date.getWeekNumber(firstJan, saturday);
this.assertEquals(1, first, "Test 1st Jan " + year + " failed: " + 1 + " = " + first);

var endYear = new Date(year, 11, 31, 0, 0, 0, 0); // Create the 31st December for each year
var end = aria.utils.Date.getWeekNumber(endYear, saturday);
this.assertEquals(endMe[year], end, "Test end of the year " + year + " failed: " + endMe[year] + " = "
+ end);

var randomDate = new Date(year, 9, 28, 0, 0, 0, 0); // Create the 28th October for each year
var rand = aria.utils.Date.getWeekNumber(randomDate, saturday);
this.assertEquals(random[year], rand, "Test random date " + year + " failed: " + random[year] + " = "
+ rand);
for (var hour = 0; hour < 24; hour++) { // Test for different hours in the day
for (var year = 2010; year < 2022; year++) { // Test for 12 years
var firstJan = new Date(year, 0, 1, hour, 0, 0, 0); // Create the 1st January for each year
var first = aria.utils.Date.getWeekNumber(firstJan, saturday);
this.assertEquals(1, first, "Test 1st Jan " + year + " failed: " + 1 + " = " + first);

var endYear = new Date(year, 11, 31, hour, 0, 0, 0); // Create the 31st December for each year
var end = aria.utils.Date.getWeekNumber(endYear, saturday);
this.assertEquals(endMe[year], end, "Test end of the year " + year + " failed: " + endMe[year] + " = "
+ end);

var randomDate = new Date(year, 9, 28, hour, 0, 0, 0); // Create the 28th October for each year
var rand = aria.utils.Date.getWeekNumber(randomDate, saturday);
this.assertEquals(random[year], rand, "Test random date " + year + " failed: " + random[year] + " = "
+ rand);
}
}
},

Expand Down Expand Up @@ -725,19 +729,6 @@ Aria.classDefinition({
+ rand);
}

// Check the log error for a wrong firstDayOfWeekParam
aria.core.AppEnvironment.setEnvironment({
"firstDayOfWeek" : 10
});
aria.utils.Date.getWeekNumber(new Date(year, 0, 1, 0, 0, 0, 0));
this.assertErrorInLogs(aria.utils.Date.INVALID_FIRST_DAY_OF_WEEK);

aria.core.AppEnvironment.setEnvironment({
"firstDayOfWeek" : 3
});
aria.utils.Date.getWeekNumber(new Date(year, 0, 1, 0, 0, 0, 0));
this.assertErrorInLogs(aria.utils.Date.INVALID_FIRST_DAY_OF_WEEK);

try {
aria.core.AppEnvironment.setEnvironment({
"firstDayOfWeek" : 0
Expand Down

0 comments on commit ab43afe

Please sign in to comment.