From 2104e7d4479381326a6e0d71ff1967a5ca8dfd11 Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Thu, 22 Oct 2020 01:58:01 +0200 Subject: [PATCH] Convert `Date/Util` to TypeScript --- .../files/js/WoltLabSuite/Core/Date/Util.js | 463 +++++++++--------- .../files/ts/WoltLabSuite/Core/Date/Util.js | 273 ----------- .../files/ts/WoltLabSuite/Core/Date/Util.ts | 248 ++++++++++ 3 files changed, 482 insertions(+), 502 deletions(-) delete mode 100644 wcfsetup/install/files/ts/WoltLabSuite/Core/Date/Util.js create mode 100644 wcfsetup/install/files/ts/WoltLabSuite/Core/Date/Util.ts diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Date/Util.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Date/Util.js index 1765535b4d..c6b3235ab0 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Date/Util.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Date/Util.js @@ -1,239 +1,244 @@ /** * Provides utility functions for date operations. * - * @author Alexander Ebert - * @copyright 2001-2019 WoltLab GmbH - * @license GNU Lesser General Public License - * @module DateUtil (alias) - * @module WoltLabSuite/Core/Date/Util + * @author Alexander Ebert + * @copyright 2001-2019 WoltLab GmbH + * @license GNU Lesser General Public License + * @module DateUtil (alias) + * @module WoltLabSuite/Core/Date/Util */ -define(['Language'], function (Language) { +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +define(["require", "exports", "../Language"], function (require, exports, Language) { "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.getTimezoneDate = exports.getTimeElement = exports.gmdate = exports.format = exports.formatDateTime = exports.formatTime = exports.formatDate = void 0; + Language = __importStar(Language); /** - * @exports WoltLabSuite/Core/Date/Util + * Returns the formatted date. */ - var DateUtil = { - /** - * Returns the formatted date. - * - * @param {Date} date date object - * @returns {string} formatted date - */ - formatDate: function (date) { - return this.format(date, Language.get('wcf.date.dateFormat')); - }, - /** - * Returns the formatted time. - * - * @param {Date} date date object - * @returns {string} formatted time - */ - formatTime: function (date) { - return this.format(date, Language.get('wcf.date.timeFormat')); - }, - /** - * Returns the formatted date time. - * - * @param {Date} date date object - * @returns {string} formatted date time - */ - formatDateTime: function (date) { - return this.format(date, Language.get('wcf.date.dateTimeFormat').replace(/%date%/, Language.get('wcf.date.dateFormat')).replace(/%time%/, Language.get('wcf.date.timeFormat'))); - }, - /** - * Formats a date using PHP's `date()` modifiers. - * - * @param {Date} date date object - * @param {string} format output format - * @returns {string} formatted date - */ - format: function (date, format) { - var char; - var out = ''; - // ISO 8601 date, best recognition by PHP's strtotime() - if (format === 'c') { - format = 'Y-m-dTH:i:sP'; - } - for (var i = 0, length = format.length; i < length; i++) { - switch (format[i]) { - // seconds - case 's': - // `00` through `59` - char = ('0' + date.getSeconds().toString()).slice(-2); - break; - // minutes - case 'i': - // `00` through `59` - char = date.getMinutes(); - if (char < 10) - char = "0" + char; - break; - // hours - case 'a': - // `am` or `pm` - char = (date.getHours() > 11) ? 'pm' : 'am'; - break; - case 'g': - // `1` through `12` - char = date.getHours(); - if (char === 0) - char = 12; - else if (char > 12) - char -= 12; - break; - case 'h': - // `01` through `12` - char = date.getHours(); - if (char === 0) - char = 12; - else if (char > 12) - char -= 12; - char = ('0' + char.toString()).slice(-2); - break; - case 'A': - // `AM` or `PM` - char = (date.getHours() > 11) ? 'PM' : 'AM'; - break; - case 'G': - // `0` through `23` - char = date.getHours(); - break; - case 'H': - // `00` through `23` - char = date.getHours(); - char = ('0' + char.toString()).slice(-2); - break; - // day - case 'd': - // `01` through `31` - char = date.getDate(); - char = ('0' + char.toString()).slice(-2); - break; - case 'j': - // `1` through `31` - char = date.getDate(); - break; - case 'l': - // `Monday` through `Sunday` (localized) - char = Language.get('__days')[date.getDay()]; - break; - case 'D': - // `Mon` through `Sun` (localized) - char = Language.get('__daysShort')[date.getDay()]; - break; - case 'S': - // ignore english ordinal suffix - char = ''; - break; - // month - case 'm': - // `01` through `12` - char = date.getMonth() + 1; - char = ('0' + char.toString()).slice(-2); - break; - case 'n': - // `1` through `12` - char = date.getMonth() + 1; - break; - case 'F': - // `January` through `December` (localized) - char = Language.get('__months')[date.getMonth()]; - break; - case 'M': - // `Jan` through `Dec` (localized) - char = Language.get('__monthsShort')[date.getMonth()]; - break; - // year - case 'y': - // `00` through `99` - char = date.getFullYear().toString().substr(2); - break; - case 'Y': - // Examples: `1988` or `2015` - char = date.getFullYear(); - break; - // timezone - case 'P': - var offset = date.getTimezoneOffset(); - char = (offset > 0) ? '-' : '+'; - offset = Math.abs(offset); - char += ('0' + (~~(offset / 60)).toString()).slice(-2); - char += ':'; - char += ('0' + (offset % 60).toString()).slice(-2); - break; - // specials - case 'r': - char = date.toString(); - break; - case 'U': - char = Math.round(date.getTime() / 1000); - break; - // escape sequence - case '\\': - char = ''; - if (i + 1 < length) { - char = format[++i]; - } - break; - default: - char = format[i]; - break; - } - out += char; - } - return out; - }, - /** - * Returns UTC timestamp, if date is not given, current time will be used. - * - * @param {Date} date target date - * @return {int} UTC timestamp in seconds - */ - gmdate: function (date) { - if (!(date instanceof Date)) { - date = new Date(); - } - return Math.round(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDay(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()) / 1000); - }, - /** - * Returns a `time` element based on the given date just like a `time` - * element created by `wcf\system\template\plugin\TimeModifierTemplatePlugin`. - * - * Note: The actual content of the element is empty and is expected - * to be automatically updated by `WoltLabSuite/Core/Date/Time/Relative` - * (for dates not in the future) after the DOM change listener has been triggered. - * - * @param {Date} date displayed date - * @return {HTMLElement} `time` element - */ - getTimeElement: function (date) { - var time = elCreate('time'); - time.className = 'datetime'; - var formattedDate = this.formatDate(date); - var formattedTime = this.formatTime(date); - elAttr(time, 'datetime', this.format(date, 'c')); - elData(time, 'timestamp', (date.getTime() - date.getMilliseconds()) / 1000); - elData(time, 'date', formattedDate); - elData(time, 'time', formattedTime); - elData(time, 'offset', date.getTimezoneOffset() * 60); // PHP returns minutes, JavaScript returns seconds - if (date.getTime() > Date.now()) { - elData(time, 'is-future-date', 'true'); - time.textContent = Language.get('wcf.date.dateTimeFormat').replace('%time%', formattedTime).replace('%date%', formattedDate); + function formatDate(date) { + return format(date, Language.get('wcf.date.dateFormat')); + } + exports.formatDate = formatDate; + /** + * Returns the formatted time. + */ + function formatTime(date) { + return format(date, Language.get('wcf.date.timeFormat')); + } + exports.formatTime = formatTime; + /** + * Returns the formatted date time. + */ + function formatDateTime(date) { + const dateTimeFormat = Language.get('wcf.date.dateTimeFormat'); + const dateFormat = Language.get('wcf.date.dateFormat'); + const timeFormat = Language.get('wcf.date.timeFormat'); + return format(date, dateTimeFormat.replace(/%date%/, dateFormat).replace(/%time%/, timeFormat)); + } + exports.formatDateTime = formatDateTime; + /** + * Formats a date using PHP's `date()` modifiers. + */ + function format(date, format) { + let char; + let out = ''; + // ISO 8601 date, best recognition by PHP's strtotime() + if (format === 'c') { + format = 'Y-m-dTH:i:sP'; + } + for (let i = 0, length = format.length; i < length; i++) { + let hours; + switch (format[i]) { + // seconds + case 's': + // `00` through `59` + char = ('0' + date.getSeconds().toString()).slice(-2); + break; + // minutes + case 'i': + // `00` through `59` + char = date.getMinutes().toString().padStart(2, '0'); + break; + // hours + case 'a': + // `am` or `pm` + char = (date.getHours() > 11) ? 'pm' : 'am'; + break; + case 'g': + // `1` through `12` + hours = date.getHours(); + if (hours === 0) + char = '12'; + else if (hours > 12) + char = (hours - 12).toString(); + else + char = hours.toString(); + break; + case 'h': + // `01` through `12` + hours = date.getHours(); + if (hours === 0) + char = '12'; + else if (hours > 12) + char = (hours - 12).toString(); + else + char = hours.toString(); + char = char.padStart(2, '0'); + break; + case 'A': + // `AM` or `PM` + char = (date.getHours() > 11) ? 'PM' : 'AM'; + break; + case 'G': + // `0` through `23` + char = date.getHours().toString(); + break; + case 'H': + // `00` through `23` + char = date.getHours().toString().padStart(2, '0'); + break; + // day + case 'd': + // `01` through `31` + char = date.getDate().toString().padStart(2, '0'); + break; + case 'j': + // `1` through `31` + char = date.getDate().toString(); + break; + case 'l': + // `Monday` through `Sunday` (localized) + char = Language.get('__days')[date.getDay()]; + break; + case 'D': + // `Mon` through `Sun` (localized) + char = Language.get('__daysShort')[date.getDay()]; + break; + case 'S': + // ignore english ordinal suffix + char = ''; + break; + // month + case 'm': + // `01` through `12` + char = (date.getMonth() + 1).toString().padStart(2, '0'); + break; + case 'n': + // `1` through `12` + char = (date.getMonth() + 1).toString(); + break; + case 'F': + // `January` through `December` (localized) + char = Language.get('__months')[date.getMonth()]; + break; + case 'M': + // `Jan` through `Dec` (localized) + char = Language.get('__monthsShort')[date.getMonth()]; + break; + // year + case 'y': + // `00` through `99` + char = date.getFullYear().toString().substr(2); + break; + case 'Y': + // Examples: `1988` or `2015` + char = date.getFullYear().toString(); + break; + // timezone + case 'P': + let offset = date.getTimezoneOffset(); + char = (offset > 0) ? '-' : '+'; + offset = Math.abs(offset); + char += ('0' + (~~(offset / 60)).toString()).slice(-2); + char += ':'; + char += ('0' + (offset % 60).toString()).slice(-2); + break; + // specials + case 'r': + char = date.toString(); + break; + case 'U': + char = Math.round(date.getTime() / 1000).toString(); + break; + // escape sequence + case '\\': + char = ''; + if (i + 1 < length) { + char = format[++i]; + } + break; + default: + char = format[i]; + break; } - return time; - }, - /** - * Returns a Date object with precise offset (including timezone and local timezone). - * - * @param {int} timestamp timestamp in milliseconds - * @param {int} offset timezone offset in milliseconds - * @return {Date} localized date - */ - getTimezoneDate: function (timestamp, offset) { - var date = new Date(timestamp); - var localOffset = date.getTimezoneOffset() * 60000; - return new Date((timestamp + localOffset + offset)); + out += char; } - }; - return DateUtil; + return out; + } + exports.format = format; + /** + * Returns UTC timestamp, if date is not given, current time will be used. + */ + function gmdate(date) { + if (!(date instanceof Date)) { + date = new Date(); + } + return Math.round(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDay(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()) / 1000); + } + exports.gmdate = gmdate; + /** + * Returns a `time` element based on the given date just like a `time` + * element created by `wcf\system\template\plugin\TimeModifierTemplatePlugin`. + * + * Note: The actual content of the element is empty and is expected + * to be automatically updated by `WoltLabSuite/Core/Date/Time/Relative` + * (for dates not in the future) after the DOM change listener has been triggered. + */ + function getTimeElement(date) { + const time = document.createElement('time'); + time.className = 'datetime'; + const formattedDate = formatDate(date); + const formattedTime = formatTime(date); + time.setAttribute('datetime', format(date, 'c')); + time.dataset.timestamp = ((date.getTime() - date.getMilliseconds()) / 1000).toString(); + time.dataset.date = formattedDate; + time.dataset.time = formattedTime; + time.dataset.offset = (date.getTimezoneOffset() * 60).toString(); // PHP returns minutes, JavaScript returns seconds + if (date.getTime() > Date.now()) { + time.dataset.isFutureDate = 'true'; + time.textContent = Language.get('wcf.date.dateTimeFormat') + .replace('%time%', formattedTime) + .replace('%date%', formattedDate); + } + return time; + } + exports.getTimeElement = getTimeElement; + /** + * Returns a Date object with precise offset (including timezone and local timezone). + */ + function getTimezoneDate(timestamp, offset) { + const date = new Date(timestamp); + const localOffset = date.getTimezoneOffset() * 60000; + return new Date((timestamp + localOffset + offset)); + } + exports.getTimezoneDate = getTimezoneDate; }); diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Date/Util.js b/wcfsetup/install/files/ts/WoltLabSuite/Core/Date/Util.js deleted file mode 100644 index 63991c5d32..0000000000 --- a/wcfsetup/install/files/ts/WoltLabSuite/Core/Date/Util.js +++ /dev/null @@ -1,273 +0,0 @@ -/** - * Provides utility functions for date operations. - * - * @author Alexander Ebert - * @copyright 2001-2019 WoltLab GmbH - * @license GNU Lesser General Public License - * @module DateUtil (alias) - * @module WoltLabSuite/Core/Date/Util - */ -define(['Language'], function(Language) { - "use strict"; - - /** - * @exports WoltLabSuite/Core/Date/Util - */ - var DateUtil = { - /** - * Returns the formatted date. - * - * @param {Date} date date object - * @returns {string} formatted date - */ - formatDate: function(date) { - return this.format(date, Language.get('wcf.date.dateFormat')); - }, - - /** - * Returns the formatted time. - * - * @param {Date} date date object - * @returns {string} formatted time - */ - formatTime: function(date) { - return this.format(date, Language.get('wcf.date.timeFormat')); - }, - - /** - * Returns the formatted date time. - * - * @param {Date} date date object - * @returns {string} formatted date time - */ - formatDateTime: function(date) { - return this.format(date, Language.get('wcf.date.dateTimeFormat').replace(/%date%/, Language.get('wcf.date.dateFormat')).replace(/%time%/, Language.get('wcf.date.timeFormat'))); - }, - - /** - * Formats a date using PHP's `date()` modifiers. - * - * @param {Date} date date object - * @param {string} format output format - * @returns {string} formatted date - */ - format: function(date, format) { - var char; - var out = ''; - - // ISO 8601 date, best recognition by PHP's strtotime() - if (format === 'c') { - format = 'Y-m-dTH:i:sP'; - } - - for (var i = 0, length = format.length; i < length; i++) { - switch (format[i]) { - // seconds - case 's': - // `00` through `59` - char = ('0' + date.getSeconds().toString()).slice(-2); - break; - - // minutes - case 'i': - // `00` through `59` - char = date.getMinutes(); - if (char < 10) char = "0" + char; - break; - - // hours - case 'a': - // `am` or `pm` - char = (date.getHours() > 11) ? 'pm' : 'am'; - break; - case 'g': - // `1` through `12` - char = date.getHours(); - if (char === 0) char = 12; - else if (char > 12) char -= 12; - break; - case 'h': - // `01` through `12` - char = date.getHours(); - if (char === 0) char = 12; - else if (char > 12) char -= 12; - - char = ('0' + char.toString()).slice(-2); - break; - case 'A': - // `AM` or `PM` - char = (date.getHours() > 11) ? 'PM' : 'AM'; - break; - case 'G': - // `0` through `23` - char = date.getHours(); - break; - case 'H': - // `00` through `23` - char = date.getHours(); - char = ('0' + char.toString()).slice(-2); - break; - - // day - case 'd': - // `01` through `31` - char = date.getDate(); - char = ('0' + char.toString()).slice(-2); - break; - case 'j': - // `1` through `31` - char = date.getDate(); - break; - case 'l': - // `Monday` through `Sunday` (localized) - char = Language.get('__days')[date.getDay()]; - break; - case 'D': - // `Mon` through `Sun` (localized) - char = Language.get('__daysShort')[date.getDay()]; - break; - case 'S': - // ignore english ordinal suffix - char = ''; - break; - - // month - case 'm': - // `01` through `12` - char = date.getMonth() + 1; - char = ('0' + char.toString()).slice(-2); - break; - case 'n': - // `1` through `12` - char = date.getMonth() + 1; - break; - case 'F': - // `January` through `December` (localized) - char = Language.get('__months')[date.getMonth()]; - break; - case 'M': - // `Jan` through `Dec` (localized) - char = Language.get('__monthsShort')[date.getMonth()]; - break; - - // year - case 'y': - // `00` through `99` - char = date.getFullYear().toString().substr(2); - break; - case 'Y': - // Examples: `1988` or `2015` - char = date.getFullYear(); - break; - - // timezone - case 'P': - var offset = date.getTimezoneOffset(); - char = (offset > 0) ? '-' : '+'; - - offset = Math.abs(offset); - - char += ('0' + (~~(offset / 60)).toString()).slice(-2); - char += ':'; - char += ('0' + (offset % 60).toString()).slice(-2); - - break; - - // specials - case 'r': - char = date.toString(); - break; - case 'U': - char = Math.round(date.getTime() / 1000); - break; - - // escape sequence - case '\\': - char = ''; - if (i + 1 < length) { - char = format[++i]; - } - break; - - default: - char = format[i]; - break; - } - - out += char; - } - - return out; - }, - - /** - * Returns UTC timestamp, if date is not given, current time will be used. - * - * @param {Date} date target date - * @return {int} UTC timestamp in seconds - */ - gmdate: function(date) { - if (!(date instanceof Date)) { - date = new Date(); - } - - return Math.round(Date.UTC( - date.getUTCFullYear(), - date.getUTCMonth(), - date.getUTCDay(), - date.getUTCHours(), - date.getUTCMinutes(), - date.getUTCSeconds() - ) / 1000); - }, - - /** - * Returns a `time` element based on the given date just like a `time` - * element created by `wcf\system\template\plugin\TimeModifierTemplatePlugin`. - * - * Note: The actual content of the element is empty and is expected - * to be automatically updated by `WoltLabSuite/Core/Date/Time/Relative` - * (for dates not in the future) after the DOM change listener has been triggered. - * - * @param {Date} date displayed date - * @return {HTMLElement} `time` element - */ - getTimeElement: function(date) { - var time = elCreate('time'); - time.className = 'datetime'; - - var formattedDate = this.formatDate(date); - var formattedTime = this.formatTime(date); - - elAttr(time, 'datetime', this.format(date, 'c')); - elData(time, 'timestamp', (date.getTime() - date.getMilliseconds()) / 1000); - elData(time, 'date', formattedDate); - elData(time, 'time', formattedTime); - elData(time, 'offset', date.getTimezoneOffset() * 60); // PHP returns minutes, JavaScript returns seconds - - if (date.getTime() > Date.now()) { - elData(time, 'is-future-date', 'true'); - - time.textContent = Language.get('wcf.date.dateTimeFormat').replace('%time%', formattedTime).replace('%date%', formattedDate); - } - - return time; - }, - - /** - * Returns a Date object with precise offset (including timezone and local timezone). - * - * @param {int} timestamp timestamp in milliseconds - * @param {int} offset timezone offset in milliseconds - * @return {Date} localized date - */ - getTimezoneDate: function(timestamp, offset) { - var date = new Date(timestamp); - var localOffset = date.getTimezoneOffset() * 60000; - - return new Date((timestamp + localOffset + offset)); - } - }; - - return DateUtil; -}); diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Date/Util.ts b/wcfsetup/install/files/ts/WoltLabSuite/Core/Date/Util.ts new file mode 100644 index 0000000000..7373b10beb --- /dev/null +++ b/wcfsetup/install/files/ts/WoltLabSuite/Core/Date/Util.ts @@ -0,0 +1,248 @@ +/** + * Provides utility functions for date operations. + * + * @author Alexander Ebert + * @copyright 2001-2019 WoltLab GmbH + * @license GNU Lesser General Public License + * @module DateUtil (alias) + * @module WoltLabSuite/Core/Date/Util + */ + +import * as Language from '../Language'; + +/** + * Returns the formatted date. + */ +export function formatDate(date: Date): string { + return format(date, Language.get('wcf.date.dateFormat')); +} + +/** + * Returns the formatted time. + */ +export function formatTime(date: Date): string { + return format(date, Language.get('wcf.date.timeFormat')); +} + +/** + * Returns the formatted date time. + */ +export function formatDateTime(date: Date): string { + const dateTimeFormat = Language.get('wcf.date.dateTimeFormat'); + const dateFormat = Language.get('wcf.date.dateFormat'); + const timeFormat = Language.get('wcf.date.timeFormat'); + + return format(date, dateTimeFormat.replace(/%date%/, dateFormat).replace(/%time%/, timeFormat)); +} + +/** + * Formats a date using PHP's `date()` modifiers. + */ +export function format(date: Date, format: string): string { + let char: string; + let out = ''; + + // ISO 8601 date, best recognition by PHP's strtotime() + if (format === 'c') { + format = 'Y-m-dTH:i:sP'; + } + + for (let i = 0, length = format.length; i < length; i++) { + let hours: number; + + switch (format[i]) { + // seconds + case 's': + // `00` through `59` + char = ('0' + date.getSeconds().toString()).slice(-2); + break; + + // minutes + case 'i': + // `00` through `59` + char = date.getMinutes().toString().padStart(2, '0'); + break; + + // hours + case 'a': + // `am` or `pm` + char = (date.getHours() > 11) ? 'pm' : 'am'; + break; + case 'g': + // `1` through `12` + hours = date.getHours(); + if (hours === 0) char = '12'; + else if (hours > 12) char = (hours - 12).toString(); + else char = hours.toString(); + break; + case 'h': + // `01` through `12` + hours = date.getHours(); + if (hours === 0) char = '12'; + else if (hours > 12) char = (hours - 12).toString(); + else char = hours.toString(); + + char = char.padStart(2, '0'); + break; + case 'A': + // `AM` or `PM` + char = (date.getHours() > 11) ? 'PM' : 'AM'; + break; + case 'G': + // `0` through `23` + char = date.getHours().toString(); + break; + case 'H': + // `00` through `23` + char = date.getHours().toString().padStart(2, '0'); + break; + + // day + case 'd': + // `01` through `31` + char = date.getDate().toString().padStart(2, '0'); + break; + case 'j': + // `1` through `31` + char = date.getDate().toString(); + break; + case 'l': + // `Monday` through `Sunday` (localized) + char = Language.get('__days')[date.getDay()]; + break; + case 'D': + // `Mon` through `Sun` (localized) + char = Language.get('__daysShort')[date.getDay()]; + break; + case 'S': + // ignore english ordinal suffix + char = ''; + break; + + // month + case 'm': + // `01` through `12` + char = (date.getMonth() + 1).toString().padStart(2, '0'); + break; + case 'n': + // `1` through `12` + char = (date.getMonth() + 1).toString(); + break; + case 'F': + // `January` through `December` (localized) + char = Language.get('__months')[date.getMonth()]; + break; + case 'M': + // `Jan` through `Dec` (localized) + char = Language.get('__monthsShort')[date.getMonth()]; + break; + + // year + case 'y': + // `00` through `99` + char = date.getFullYear().toString().substr(2); + break; + case 'Y': + // Examples: `1988` or `2015` + char = date.getFullYear().toString(); + break; + + // timezone + case 'P': + let offset = date.getTimezoneOffset(); + char = (offset > 0) ? '-' : '+'; + + offset = Math.abs(offset); + + char += ('0' + (~~(offset / 60)).toString()).slice(-2); + char += ':'; + char += ('0' + (offset % 60).toString()).slice(-2); + + break; + + // specials + case 'r': + char = date.toString(); + break; + case 'U': + char = Math.round(date.getTime() / 1000).toString(); + break; + + // escape sequence + case '\\': + char = ''; + if (i + 1 < length) { + char = format[++i]; + } + break; + + default: + char = format[i]; + break; + } + + out += char; + } + + return out; +} + +/** + * Returns UTC timestamp, if date is not given, current time will be used. + */ +export function gmdate(date: Date): number { + if (!(date instanceof Date)) { + date = new Date(); + } + + return Math.round(Date.UTC( + date.getUTCFullYear(), + date.getUTCMonth(), + date.getUTCDay(), + date.getUTCHours(), + date.getUTCMinutes(), + date.getUTCSeconds(), + ) / 1000); +} + +/** + * Returns a `time` element based on the given date just like a `time` + * element created by `wcf\system\template\plugin\TimeModifierTemplatePlugin`. + * + * Note: The actual content of the element is empty and is expected + * to be automatically updated by `WoltLabSuite/Core/Date/Time/Relative` + * (for dates not in the future) after the DOM change listener has been triggered. + */ +export function getTimeElement(date: Date): HTMLElement { + const time = document.createElement('time'); + time.className = 'datetime'; + + const formattedDate = formatDate(date); + const formattedTime = formatTime(date); + + time.setAttribute('datetime', format(date, 'c')); + time.dataset.timestamp = ((date.getTime() - date.getMilliseconds()) / 1000).toString(); + time.dataset.date = formattedDate; + time.dataset.time = formattedTime; + time.dataset.offset = (date.getTimezoneOffset() * 60).toString(); // PHP returns minutes, JavaScript returns seconds + + if (date.getTime() > Date.now()) { + time.dataset.isFutureDate = 'true'; + + time.textContent = Language.get('wcf.date.dateTimeFormat') + .replace('%time%', formattedTime) + .replace('%date%', formattedDate); + } + + return time; +} + +/** + * Returns a Date object with precise offset (including timezone and local timezone). + */ +export function getTimezoneDate(timestamp: number, offset: number): Date { + const date = new Date(timestamp); + const localOffset = date.getTimezoneOffset() * 60000; + + return new Date((timestamp + localOffset + offset)); +} -- 2.20.1