Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

Commit

Permalink
fix(calendar, datepicker): fix issues with GMT+X timezones
Browse files Browse the repository at this point in the history
- simplify `$$mdDateUtil.removeLocalTzAndReparseDate()`

Fixes #12000
  • Loading branch information
Splaktar committed Aug 31, 2020
1 parent dd150fa commit a897a67
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 13 deletions.
12 changes: 9 additions & 3 deletions src/components/datepicker/js/calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@
/**
* Sets up the controller's reference to ngModelController.
* @param {!ngModel.NgModelController} ngModelCtrl Instance of the ngModel controller.
* @param {Object} inputDirective Config for Angular's `input` directive.
* @param {Object} inputDirective Config for AngularJS's `input` directive.
*/
CalendarCtrl.prototype.configureNgModel = function(ngModelCtrl, inputDirective) {
var self = this;
Expand All @@ -326,7 +326,7 @@
// In the case where a conversion is needed, the $viewValue here will be a string like
// "2020-05-10" instead of a Date object.
if (!self.dateUtil.isValidDate(value)) {
convertedDate = self.dateUtil.removeLocalTzAndReparseDate(new Date(this.$viewValue));
convertedDate = self.dateUtil.removeLocalTzAndReparseDate(new Date(value));
if (self.dateUtil.isValidDate(convertedDate)) {
value = convertedDate;
}
Expand Down Expand Up @@ -360,7 +360,13 @@
var value = this.dateUtil.createDateAtMidnight(date);
this.focusDate(value);
this.$scope.$emit('md-calendar-change', value);
this.ngModelCtrl.$setViewValue(this.ngDateFilter(value, 'yyyy-MM-dd', timezone), 'default');
// Using the timezone when the offset is negative (GMT+X) causes the previous day to be
// selected here. This check avoids that.
if (timezone == null || value.getTimezoneOffset() < 0) {
this.ngModelCtrl.$setViewValue(this.ngDateFilter(value, 'yyyy-MM-dd'), 'default');
} else {
this.ngModelCtrl.$setViewValue(this.ngDateFilter(value, 'yyyy-MM-dd', timezone), 'default');
}
this.ngModelCtrl.$render();
return value;
};
Expand Down
9 changes: 2 additions & 7 deletions src/components/datepicker/js/dateUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -311,15 +311,10 @@

/**
* @param {Date} value date in local timezone
* @return {Date} date with local timezone removed
* @return {Date} date with local timezone offset removed
*/
function removeLocalTzAndReparseDate(value) {
var dateValue, formattedDate;
// Remove the local timezone offset before calling formatDate.
dateValue = new Date(value.getTime() + 60000 * value.getTimezoneOffset());
formattedDate = $mdDateLocale.formatDate(dateValue);
// parseDate only works with a date formatted by formatDate when using Moment validation.
return $mdDateLocale.parseDate(formattedDate);
return $mdDateLocale.parseDate(value.getTime() + 60000 * value.getTimezoneOffset());
}
});
})();
18 changes: 15 additions & 3 deletions src/components/datepicker/js/datepickerDirective.js
Original file line number Diff line number Diff line change
Expand Up @@ -990,7 +990,13 @@
*/
DatePickerCtrl.prototype.setModelValue = function(value) {
var timezone = this.$mdUtil.getModelOption(this.ngModelCtrl, 'timezone');
this.ngModelCtrl.$setViewValue(this.ngDateFilter(value, 'yyyy-MM-dd', timezone), 'default');
// Using the timezone when the offset is negative (GMT+X) causes the previous day to be
// set as the model value here. This check avoids that.
if (timezone == null || value.getTimezoneOffset() < 0) {
this.ngModelCtrl.$setViewValue(this.ngDateFilter(value, 'yyyy-MM-dd'), 'default');
} else {
this.ngModelCtrl.$setViewValue(this.ngDateFilter(value, 'yyyy-MM-dd', timezone), 'default');
}
};

/**
Expand All @@ -1001,12 +1007,18 @@
var self = this;
var timezone = this.$mdUtil.getModelOption(this.ngModelCtrl, 'timezone');

if (this.dateUtil.isValidDate(value) && timezone != null) {
if (this.dateUtil.isValidDate(value) && timezone != null && value.getTimezoneOffset() >= 0) {
this.date = this.dateUtil.removeLocalTzAndReparseDate(value);
} else {
this.date = value;
}
this.inputElement.value = this.locale.formatDate(value, timezone);
// Using the timezone when the offset is negative (GMT+X) causes the previous day to be
// used here. This check avoids that.
if (timezone == null || value.getTimezoneOffset() < 0) {
this.inputElement.value = this.locale.formatDate(value);
} else {
this.inputElement.value = this.locale.formatDate(value, timezone);
}
this.mdInputContainer && this.mdInputContainer.setHasValue(!!value);
this.resizeInputElement();
// This is often called from the $formatters section of the $validators pipeline.
Expand Down

0 comments on commit a897a67

Please sign in to comment.