diff --git a/django/contrib/admin/static/admin/js/core.js b/django/contrib/admin/static/admin/js/core.js index 34f99262c5..1840948d1b 100644 --- a/django/contrib/admin/static/admin/js/core.js +++ b/django/contrib/admin/static/admin/js/core.js @@ -240,7 +240,10 @@ function findPosY(obj) { } ++i; } - return new Date(year, month, day); + // Create Date object from UTC since the parsed value is supposed to be + // in UTC, not local time. Also, the calendar uses UTC functions for + // date extraction. + return new Date(Date.UTC(year, month, day)); }; })(); diff --git a/docs/releases/1.8.9.txt b/docs/releases/1.8.9.txt index 823bd9b3eb..5525eca84a 100644 --- a/docs/releases/1.8.9.txt +++ b/docs/releases/1.8.9.txt @@ -14,3 +14,7 @@ Bugfixes * Fixed a crash in the translations system when the current language has no translations (:ticket:`26046`). + +* Fixed a regression that caused the incorrect day to be selected when opening + the admin calendar widget for timezones from GMT+0100 to GMT+1200 + (:ticket:`24980`). diff --git a/docs/releases/1.9.2.txt b/docs/releases/1.9.2.txt index f486d00311..375fe3edaa 100644 --- a/docs/releases/1.9.2.txt +++ b/docs/releases/1.9.2.txt @@ -17,3 +17,7 @@ Bugfixes * Fixed a crash in the translations system when the current language has no translations (:ticket:`26046`). + +* Fixed a regression that caused the incorrect day to be selected when opening + the admin calendar widget for timezones from GMT+0100 to GMT+1200 + (:ticket:`24980`). diff --git a/js_tests/admin/core.test.js b/js_tests/admin/core.test.js index 0d6a12d44c..43fb27a7af 100644 --- a/js_tests/admin/core.test.js +++ b/js_tests/admin/core.test.js @@ -57,7 +57,47 @@ test('Date.strftime', function(assert) { }); test('String.strptime', function(assert) { - var date = new Date(1988, 1, 26); - assert.equal('1988-02-26'.strptime('%Y-%m-%d').toString(), date.toString()); - assert.equal('26/02/88'.strptime('%d/%m/%y').toString(), date.toString()); + // Use UTC functions for extracting dates since the calendar uses them as + // well. Month numbering starts with 0 (January). + var firstParsedDate = '1988-02-26'.strptime('%Y-%m-%d'); + assert.equal(firstParsedDate.getUTCDate(), 26); + assert.equal(firstParsedDate.getUTCMonth(), 1); + assert.equal(firstParsedDate.getUTCFullYear(), 1988); + + var secondParsedDate = '26/02/88'.strptime('%d/%m/%y'); + assert.equal(secondParsedDate.getUTCDate(), 26); + assert.equal(secondParsedDate.getUTCMonth(), 1); + assert.equal(secondParsedDate.getUTCFullYear(), 1988); + + var format = django.get_format('DATE_INPUT_FORMATS')[0]; + var thirdParsedDate = '1983-11-20'.strptime(format); + + assert.equal(thirdParsedDate.getUTCDate(), 20); + assert.equal(thirdParsedDate.getUTCMonth(), 10); + assert.equal(thirdParsedDate.getUTCFullYear(), 1983); + + // Extracting from a Date object with local time must give the correct + // result. Without proper conversion, timezones from GMT+0100 to GMT+1200 + // gives a date one day earlier than necessary, e.g. converting local time + // Feb 26, 1988 00:00:00 EEST is Feb 25, 21:00:00 UTC. + + // Checking timezones from GMT+0100 to GMT+1200 + var i, tz, date; + for (i = 1; i <= 12; i++) { + tz = i > 9 ? '' + i : '0' + i; + date = new Date(Date.parse('Feb 26, 1988 00:00:00 GMT+' + tz + '00')); + assert.notEqual(date.getUTCDate(), 26); + assert.equal(date.getUTCDate(), 25); + assert.equal(date.getUTCMonth(), 1); + assert.equal(date.getUTCFullYear(), 1988); + } + + // Checking timezones from GMT+0000 to GMT-1100 + for (i = 0; i <= 11; i++) { + tz = i > 9 ? '' + i : '0' + i; + date = new Date(Date.parse('Feb 26, 1988 00:00:00 GMT-' + tz + '00')); + assert.equal(date.getUTCDate(), 26); + assert.equal(date.getUTCMonth(), 1); + assert.equal(date.getUTCFullYear(), 1988); + } });