From e8b9d0c2250911f125c664c8df3404d33bbf4eab Mon Sep 17 00:00:00 2001 From: giulianovarriale <giuliano.oca@gmail.com> Date: Fri, 11 Nov 2016 10:57:51 -0200 Subject: [PATCH] Pass date as integer params on instantiate new Date in order to avoid time zone inconsistency --- app/assets/javascripts/due_date_select.js.es6 | 11 +++++-- .../javascripts/lib/utils/datetime_utility.js | 13 ++++++++ .../fix-timezone-due-date-picker.yml | 4 +++ spec/javascripts/datetime_utility_spec.js.es6 | 32 +++++++++++++++++++ spec/javascripts/due_date_select_spec.js.es6 | 25 +++++++++++++++ .../fixtures/due_date_select.html.haml | 29 +++++++++++++++++ 6 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/fix-timezone-due-date-picker.yml create mode 100644 spec/javascripts/due_date_select_spec.js.es6 create mode 100644 spec/javascripts/fixtures/due_date_select.html.haml diff --git a/app/assets/javascripts/due_date_select.js.es6 b/app/assets/javascripts/due_date_select.js.es6 index 2b7d57d86c6..f35c024e716 100644 --- a/app/assets/javascripts/due_date_select.js.es6 +++ b/app/assets/javascripts/due_date_select.js.es6 @@ -2,9 +2,10 @@ (function(global) { class DueDateSelect { - constructor({ $dropdown, $loading } = {}) { + constructor({ $dropdown, $loading, $context } = {}) { const $dropdownParent = $dropdown.closest('.dropdown'); const $block = $dropdown.closest('.block'); + this.$context = $context || $('body'); this.$loading = $loading; this.$dropdown = $dropdown; this.$dropdownParent = $dropdownParent; @@ -80,9 +81,12 @@ } parseSelectedDate() { - this.rawSelectedDate = $("input[name='" + this.fieldName + "']").val(); + this.rawSelectedDate = this.$context.find(`input[name='${this.fieldName}']`).val(); + if (this.rawSelectedDate.length) { - let dateObj = new Date(this.rawSelectedDate); + // Avoid time zone inconsistency using the utils.createDateObject + // method, instead of the native Date object. + const dateObj = gl.utils.createDateObject(this.rawSelectedDate); this.displayedDate = $.datepicker.formatDate('M d, yy', dateObj); } else { this.displayedDate = 'No due date'; @@ -176,5 +180,6 @@ } global.DueDateSelectors = DueDateSelectors; + global.DueDateSelect = DueDateSelect; })(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js index e8e502694d6..7a136a355ec 100644 --- a/app/assets/javascripts/lib/utils/datetime_utility.js +++ b/app/assets/javascripts/lib/utils/datetime_utility.js @@ -16,6 +16,19 @@ } w.gl.utils.days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; + // createDateObject must be used instead of using native Date object + // to create a new Date instance using string as param - '2016-11-10' or + // '2016/11/10' in order to avoid time zone inconsistency. + w.gl.utils.createDateObject = function(string) { + var dateSeparator = string.indexOf('-') > -1 ? '-' : '/'; + + var dateArray = string.split(dateSeparator).map(function(dateItem) { + return parseInt(dateItem, 10); + }); + + return new Date(dateArray[0], dateArray[1] - 1, dateArray[2]); + } + w.gl.utils.formatDate = function(datetime) { return dateFormat(datetime, 'mmm d, yyyy h:MMtt Z'); }; diff --git a/changelogs/unreleased/fix-timezone-due-date-picker.yml b/changelogs/unreleased/fix-timezone-due-date-picker.yml new file mode 100644 index 00000000000..02f5ed890c6 --- /dev/null +++ b/changelogs/unreleased/fix-timezone-due-date-picker.yml @@ -0,0 +1,4 @@ +--- +title: Fix date inconsistency on due date picker +merge_request: +author: Giuliano Varriale diff --git a/spec/javascripts/datetime_utility_spec.js.es6 b/spec/javascripts/datetime_utility_spec.js.es6 index 8ece24555c5..756c888cad7 100644 --- a/spec/javascripts/datetime_utility_spec.js.es6 +++ b/spec/javascripts/datetime_utility_spec.js.es6 @@ -2,6 +2,38 @@ (() => { describe('Date time utils', () => { + describe('create date object', () => { + describe('using dashes', () => { + it('should instantiate the date object using integer params', () => { + spyOn(window, 'Date') + gl.utils.createDateObject('2016-11-12'); + expect(window.Date).toHaveBeenCalledWith(2016, 10, 12); + }); + + it('should return the right date object ', () => { + const date = gl.utils.createDateObject('2016-11-12'); + expect(date.getDate()).toBe(12); + expect(date.getMonth()).toBe(10); + expect(date.getFullYear()).toBe(2016); + }); + }); + + describe('using slashes', () => { + it('should instantiate the date object using integer params', () => { + spyOn(window, 'Date') + gl.utils.createDateObject('2016/08/02'); + expect(window.Date).toHaveBeenCalledWith(2016, 7, 2); + }); + + it('should return the right date object', () => { + const date = gl.utils.createDateObject('2016/08/02'); + expect(date.getDate()).toBe(2); + expect(date.getMonth()).toBe(7); + expect(date.getFullYear()).toBe(2016); + }); + }); + }); + describe('get day name', () => { it('should return Sunday', () => { const day = gl.utils.getDayName(new Date('07/17/2016')); diff --git a/spec/javascripts/due_date_select_spec.js.es6 b/spec/javascripts/due_date_select_spec.js.es6 new file mode 100644 index 00000000000..d491c25b6fe --- /dev/null +++ b/spec/javascripts/due_date_select_spec.js.es6 @@ -0,0 +1,25 @@ +/* eslint-disable */ +//= require lib/utils/datetime_utility +//= require jquery +/*= require jquery-ui/datepicker */ +/*= require gl_dropdown */ +//= require due_date_select +(() => { + describe('Due Date Select', () => { + describe('parseSelectedDate()', () => { + it('call create date object', () => { + const $dom = $(fixture.preload('due_date_select.html')[0]); + + const dueDateSelect = new gl.DueDateSelect({ + $context: $dom, + $dropdown: $dom.find('.js-due-date-select'), + $loading: $dom.find('.block-loading') + }); + + spyOn(gl.utils, 'createDateObject'); + dueDateSelect.parseSelectedDate(); + expect(gl.utils.createDateObject).toHaveBeenCalledWith('2016-11-20'); + }); + }); + }); +})(); diff --git a/spec/javascripts/fixtures/due_date_select.html.haml b/spec/javascripts/fixtures/due_date_select.html.haml new file mode 100644 index 00000000000..ed7dcb0d658 --- /dev/null +++ b/spec/javascripts/fixtures/due_date_select.html.haml @@ -0,0 +1,29 @@ +.block.due_date + .sidebar-collapsed-icon + %i.fa.fa-calendar + %span.js-due-date-sidebar-value + Nov 20, 2016 + .title.hide-collapsed + Due date + %i.fa.fa-spinner.fa-spin.block-loading + %a.edit-link.pull-right{ href: "#"} Edit + .value.hide-collapsed + %span.value-content + %span.bold + Nov 20, 2016 + %span.no-value.js-remove-due-date-holder + %a.js-remove-due-date{ href: "#", role: "button" } + remove due date + .selectbox.hide-collapsed + %input{type: "hidden", name: "issue[due_date]", id: "issue[due_date]", value: "2016-11-20"} + .dropdown + %button.dropdown-menu-toggle.js-due-date-select{ type: 'button', data: { toggle: 'dropdown', field_name: "issue[due_date]", ability_name: "issue", issue_update: "/h5bp/html5-boilerplate/issues/10.json" } } + %span.dropdown-toggle-text Due date + %i.fa.fa-chevron-down + .dropdown-menu.dropdown-menu-due-date + .dropdown-title + %span Due Date + %button.dropdown-title-button.dropdown-menu-close{ type: "button" } + %i.fa.fa-times.dropdown-menu-close-icon + .dropdown-content + .js-due-date-calendar -- GitLab