diff --git a/core/src/components/datetime/datetime-util.ts b/core/src/components/datetime/datetime-util.ts index b11693839f..0c3ba61d55 100644 --- a/core/src/components/datetime/datetime-util.ts +++ b/core/src/components/datetime/datetime-util.ts @@ -241,7 +241,38 @@ export function parseDate(val: string | undefined | null): DatetimeData | undefi }; } +/** + * Converts a valid UTC datetime string + * To the user's local timezone + * Note: This is not meant for time strings + * such as "01:47" + */ +export const getLocalDateTime = (dateString = ''): Date => { + const date = (dateString.length > 0) ? new Date(dateString) : new Date(); + + return new Date( + Date.UTC( + date.getFullYear(), + date.getMonth(), + date.getDate(), + date.getHours(), + date.getMinutes(), + date.getSeconds(), + date.getMilliseconds() + ) + ); +}; + export function updateDate(existingData: DatetimeData, newData: any): boolean { + + if (!newData || typeof newData === 'string') { + const localDateTime = getLocalDateTime(newData); + + if (!Number.isNaN(localDateTime.getTime())) { + newData = localDateTime.toISOString(); + } + } + if (newData && newData !== '') { if (typeof newData === 'string') { @@ -368,6 +399,7 @@ export function convertDataToISO(data: DatetimeData): string { rtn += 'Z'; } else { + // YYYY-MM-DDTHH:mm:SS+/-HH:mm rtn += (data.tzOffset > 0 ? '+' : '-') + twoDigit(Math.floor(Math.abs(data.tzOffset / 60))) + ':' + twoDigit(data.tzOffset % 60); } diff --git a/core/src/components/datetime/datetime.tsx b/core/src/components/datetime/datetime.tsx index 30110fd0aa..4f2e966e81 100644 --- a/core/src/components/datetime/datetime.tsx +++ b/core/src/components/datetime/datetime.tsx @@ -307,6 +307,19 @@ export class Datetime implements ComponentInterface { text: this.doneText, handler: (data: any) => { this.updateDatetimeValue(data); + + /** + * Prevent convertDataToISO from doing any + * kind of transformation based on timezone + * This cancels out any change it attempts to make + * + * Important: Take the timezone offset based on + * the date that is currently selected, otherwise + * there can be 1 hr difference when dealing w/ DST + */ + const date = new Date(convertDataToISO(this.datetimeValue)); + this.datetimeValue.tzOffset = date.getTimezoneOffset() * -1; + this.value = convertDataToISO(this.datetimeValue); } } @@ -360,6 +373,7 @@ export class Datetime implements ComponentInterface { // cool, we've loaded up the columns with options // preselect the option for this column const optValue = getDateValue(this.datetimeValue, format); + const selectedIndex = colOptions.findIndex(opt => opt.value === optValue); return { @@ -527,6 +541,7 @@ export class Datetime implements ComponentInterface { private getText() { // create the text of the formatted data const template = this.displayFormat || this.pickerFormat || DEFAULT_FORMAT; + return renderDatetime(template, this.datetimeValue, this.locale); } diff --git a/core/src/components/datetime/test/datetime.spec.ts b/core/src/components/datetime/test/datetime.spec.ts index dc2fe54f6e..362bc8fa00 100644 --- a/core/src/components/datetime/test/datetime.spec.ts +++ b/core/src/components/datetime/test/datetime.spec.ts @@ -1,5 +1,4 @@ -import { DatetimeOptions } from '../datetime-interface'; -import { DatetimeData, getDateValue } from '../datetime-util'; +import { DatetimeData, getDateValue, getLocalDateTime } from '../datetime-util'; describe('Datetime', () => { describe('getDateValue()', () => { @@ -32,4 +31,30 @@ describe('Datetime', () => { expect(yearValue).toEqual(date.getFullYear()); }); }); -}); \ No newline at end of file + + describe('getLocalDateTime()', () => { + it('should format a datetime string according to the local timezone', () => { + + const dateStringTests = [ + { expectedHourUTC: 12, input: `2019-03-02T12:08:06.601-00:00`, expectedOutput: `2019-03-02T%HOUR%:08:06.601Z` }, + { expectedHourUTC: 12, input: `2019-11-02T12:08:06.601-00:00`, expectedOutput: `2019-11-02T%HOUR%:08:06.601Z` }, + { expectedHourUTC: 8, input: `1994-12-15T13:47:20.789+05:00`, expectedOutput: `1994-12-15T%HOUR%:47:20.789Z` }, + { expectedHourUTC: 18, input: `1994-12-15T13:47:20.789-05:00`, expectedOutput: `1994-12-15T%HOUR%:47:20.789Z` }, + { expectedHourUTC: 9, input: `2019-02-14T09:00:00.000Z`, expectedOutput: `2019-02-14T%HOUR%:00:00.000Z` } + ]; + + dateStringTests.forEach(test => { + const convertToLocal = getLocalDateTime(test.input); + + const timeZoneOffset = convertToLocal.getTimezoneOffset() / 60; + const expectedDateString = test.expectedOutput.replace('%HOUR%', padNumber(test.expectedHourUTC - timeZoneOffset)); + + expect(convertToLocal.toISOString()).toEqual(expectedDateString); + }); + }); + }); +}); + +function padNumber(number: number, totalLength: number = 2): string { + return number.toString().padStart(totalLength, '0'); +} \ No newline at end of file