diff --git a/api/js/etemplate/Et2Date/Et2Date.ts b/api/js/etemplate/Et2Date/Et2Date.ts index 6eb703428c..a006cc1993 100644 --- a/api/js/etemplate/Et2Date/Et2Date.ts +++ b/api/js/etemplate/Et2Date/Et2Date.ts @@ -16,7 +16,8 @@ import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget"; /** - * To parse a date into the right format + * Parse a date string into a Date object + * Time will be 00:00:00 UTC * * @param {string} dateString * @returns {Date | undefined} @@ -65,15 +66,15 @@ export function parseDate(dateString) } const [year, month, day] = parsedString.split('/').map(Number); - const parsedDate = new Date(year, month - 1, day); + const parsedDate = new Date(`${year}-${month < 10 ? "0" + month : month}-${day < 10 ? "0" + day : day}T00:00:00Z`); // Check if parsedDate is not `Invalid Date` or that the date has changed (e.g. the not existing 31.02.2020) - if ( + if( year > 0 && month > 0 && day > 0 && - parsedDate.getDate() === day && - parsedDate.getMonth() === month - 1 + parsedDate.getUTCDate() === day && + parsedDate.getUTCMonth() === month - 1 ) { return parsedDate; @@ -82,8 +83,8 @@ export function parseDate(dateString) } /** - * To parse a time into the right format - * Date will be 1970-01-01 + * To parse a time into a Date object + * Date will be 1970-01-01, time is in UTC to avoid browser issues * * @param {string} timeString * @returns {Date | undefined} @@ -108,8 +109,16 @@ export function parseTime(timeString) } let am_pm = timeString.endsWith("pm") || timeString.endsWith("PM") ? 12 : 0; - timeString = timeString.replaceAll(/[^0-9:]/gi, ''); - const [hour, minute] = timeString.split(':').map(Number); + + let strippedString = timeString.replaceAll(/[^0-9:]/gi, ''); + + if(timeString.startsWith("12") && strippedString != timeString) + { + // 12:xx am -> 0:xx, 12:xx pm -> 12:xx + am_pm -= 12; + } + + const [hour, minute] = strippedString.split(':').map(Number); const parsedDate = new Date("1970-01-01T00:00:00Z"); parsedDate.setUTCHours(hour + am_pm); @@ -128,6 +137,7 @@ export function parseTime(timeString) /** * To parse a date+time into an object + * Time is in UTC to avoid browser issues * * @param {string} dateTimeString * @returns {Date | undefined} @@ -180,7 +190,7 @@ export function parseDateTime(dateTimeString) * set 'dateFormat': "Y-m-d" to specify a particular format * @returns {string} */ -export function formatDate(date : Date, options) : string +export function formatDate(date : Date, options = {dateFormat: ""}) : string { if(!date || !(date instanceof Date)) { @@ -213,7 +223,7 @@ export function formatDate(date : Date, options) : string * set 'timeFormat': "12" to specify a particular format * @returns {string} */ -export function formatTime(date : Date, options) : string +export function formatTime(date : Date, options = {timeFormat: ""}) : string { if(!date || !(date instanceof Date)) { @@ -221,7 +231,7 @@ export function formatTime(date : Date, options) : string } let _value = ''; - let timeformat = options.timeFormat || window.egw.preference("timeformat") || '24'; + let timeformat = options.timeFormat || window.egw.preference("timeformat") || "24"; let hours = (timeformat == "12" && date.getUTCHours() > 12) ? (date.getUTCHours() - 12) : date.getUTCHours(); if(timeformat == "12" && hours == 0) { @@ -244,7 +254,7 @@ export function formatTime(date : Date, options) : string * set 'dateFormat': "Y-m-d", 'timeFormat': "12" to specify a particular format * @returns {string} */ -export function formatDateTime(date : Date, options) : string +export function formatDateTime(date : Date, options = {dateFormat: "", timeFormat: ""}) : string { if(!date || !(date instanceof Date)) { diff --git a/api/js/etemplate/Et2Date/test/Formatter.test.ts b/api/js/etemplate/Et2Date/test/Formatter.test.ts new file mode 100644 index 0000000000..d94efea836 --- /dev/null +++ b/api/js/etemplate/Et2Date/test/Formatter.test.ts @@ -0,0 +1,97 @@ +/** + * Test file for Etemplate date formatting + */ +import {assert} from '@open-wc/testing'; +import {formatDate, formatTime} from "../Et2Date"; + +describe("Date formatting", () => +{ + // Function under test + let formatter = formatDate; + + // Setup run before each test + beforeEach(async() => + { + // Stub global egw for preference + // @ts-ignore + window.egw = { + preference: () => 'Y-m-d' + }; + }); + + it("Handles Y-m-d", () => + { + let test_string = '2021-09-22'; + let test_date = new Date(2021, 8, 22, 0, 0, 0); + + let formatted = formatter(test_date); + + assert.equal(formatted, test_string); + }); + + it("Handles Y.d.m", () => + { + let test_string = '2021.22.09'; + let test_date = new Date(2021, 8, 22, 0, 0, 0); + + //@ts-ignore + window.egw = { + preference: () => 'Y.d.m' + }; + let formatted = formatter(test_date); + + assert.equal(formatted, test_string); + }); +}); + +describe("Time formatting", () => +{ + // Function under test + let formatter = formatTime; + + // Setup run before each test + beforeEach(async() => + { + // Stub global egw for preference + // @ts-ignore + window.egw = { + preference: () => 'Y-m-d' + }; + }); + + it("Handles 12h", () => + { + const test_data = { + "9:15 am": new Date('2021-09-22T09:15:00Z'), + "12:00 am": new Date('2021-09-22T00:00:00Z'), + "12:00 pm": new Date('2021-09-22T12:00:00Z'), + "5:00 pm": new Date('2021-09-22T17:00:00Z'), + }; + for(let test_string of Object.keys(test_data)) + { + let test_date = test_data[test_string]; + let formatted = formatter(test_date, {timeFormat: "12"}); + + assert.equal(formatted, test_string); + + } + }); + + it("Handles 24h", () => + { + const test_data = { + "09:15": new Date('2021-09-22T09:15:00Z'), + "00:00": new Date('2021-09-22T00:00:00Z'), + "12:00": new Date('2021-09-22T12:00:00Z'), + "17:00": new Date('2021-09-22T17:00:00Z'), + }; + for(let test_string of Object.keys(test_data)) + { + let test_date = test_data[test_string]; + let formatted = formatter(test_date, {timeFormat: "24"}); + + assert.equal(formatted, test_string); + + } + }); +}); \ No newline at end of file diff --git a/api/js/etemplate/Et2Date/test/Parser.test.ts b/api/js/etemplate/Et2Date/test/Parser.test.ts index e869d6c0a8..3fa8ae9f72 100644 --- a/api/js/etemplate/Et2Date/test/Parser.test.ts +++ b/api/js/etemplate/Et2Date/test/Parser.test.ts @@ -1,10 +1,8 @@ /** * Test file for Etemplate date parsing */ -import {assert, fixture} from '@open-wc/testing'; -import {Et2Date, parseDate} from "../Et2Date"; -import {html} from "lit-element"; -import * as sinon from 'sinon'; +import {assert} from '@open-wc/testing'; +import {parseDate, parseTime} from "../Et2Date"; describe("Date parsing", () => { @@ -36,7 +34,7 @@ describe("Date parsing", () => it("Handles Y-m-d", () => { let test_string = '2021-09-22'; - let test_date = new Date(2021, 8, 22, 0, 0, 0); + let test_date = new Date("2021-09-22T00:00:00Z"); let parsed = parser(test_string); @@ -46,7 +44,7 @@ describe("Date parsing", () => it("Handles Y.d.m", () => { let test_string = '2021.22.09'; - let test_date = new Date(2021, 8, 22, 0, 0, 0); + let test_date = new Date("2021-09-22T00:00:00Z"); //@ts-ignore window.egw = { @@ -56,4 +54,78 @@ describe("Date parsing", () => assert.equal(parsed.toJSON(), test_date.toJSON()); }); +}); + + +describe("Time parsing", () => +{ + // Setup run before each test + beforeEach(async() => + { + // Stub global egw for preference + // @ts-ignore + window.egw = { + preference: () => 'Y-m-d' + }; + }); + + + it("Handles 12h", () => + { + const test_data = { + // As expected + "9:15 am": new Date('1970-01-01T09:15:00Z'), + "12:00 am": new Date('1970-01-01T00:00:00Z'), + "12:00 pm": new Date('1970-01-01T12:00:00Z'), + "5:00 pm": new Date('1970-01-01T17:00:00Z'), + "11:59 pm": new Date('1970-01-01T23:59:00Z'), + + // Not valid, should be undefined + "invalid": undefined, + "23:45 pm": undefined + }; + for(let test_string of Object.keys(test_data)) + { + let test_date = test_data[test_string]; + let parsed = parseTime(test_string); + + if(typeof test_date == "undefined") + { + assert.isUndefined(parsed); + } + else + { + assert.equal(parsed.toJSON(), test_date.toJSON()); + } + } + }); + + it("Handles 24h", () => + { + const test_data = { + "09:15": new Date('1970-01-01T09:15:00Z'), + "00:00": new Date('1970-01-01T00:00:00Z'), + "12:00": new Date('1970-01-01T12:00:00Z'), + "17:00": new Date('1970-01-01T17:00:00Z'), + "23:59": new Date('1970-01-01T23:59:00Z'), + + // Not valid, should be undefined + "invalid": undefined, + "23:45 pm": undefined + }; + for(let test_string of Object.keys(test_data)) + { + let test_date = test_data[test_string]; + let parsed = parseTime(test_string); + + if(typeof test_date == "undefined") + { + assert.isUndefined(parsed); + } + else + { + assert.equal(parsed.toJSON(), test_date.toJSON()); + } + } + }); }); \ No newline at end of file