UNPKG

@bmqube/xmlrpc

Version:

A pure TypeScript XML-RPC client and server. Forked from (https://github.com/baalexander/node-xmlrpc)

132 lines (131 loc) 4.93 kB
// date_formatter.mts /** * @class DateFormatter * The DateFormatter supports decoding from and encoding to * ISO8601 formatted strings. Accepts formats with and without * hyphen/colon separators and correctly parses zoning info. */ export class DateFormatter { constructor(opts) { this.opts = { ...DateFormatter.DEFAULT_OPTIONS }; this.setOpts(opts); } /** * Sets options for encoding Date objects to ISO8601 strings. * Omitting the 'opts' argument will reset all options to the default. */ setOpts(opts) { const source = opts ?? DateFormatter.DEFAULT_OPTIONS; const next = { ...DateFormatter.DEFAULT_OPTIONS }; Object.keys(DateFormatter.DEFAULT_OPTIONS).forEach((k) => { next[k] = (Object.prototype.hasOwnProperty.call(source, k) ? source[k] : DateFormatter.DEFAULT_OPTIONS[k]); }); this.opts = next; } /** * Converts ISO8601 string to a Date. */ decodeIso8601(time) { const dateParts = time.toString().match(DateFormatter.ISO8601); if (!dateParts) { throw new Error("Expected a ISO8601 datetime but got '" + time + "'"); } const date = [ [dateParts[1], dateParts[3] || "01", dateParts[5] || "01"].join("-"), "T", [dateParts[7] || "00", dateParts[11] || "00", dateParts[14] || "00"].join(":"), ".", dateParts[16] || "000", ].join("") + (dateParts[17] !== undefined ? dateParts[17] + (dateParts[19] && dateParts[20] === undefined ? "00" : "") : DateFormatter.formatCurrentOffset(new Date())); return new Date(date); // Note: original used `new Date(date)` where `date` was built then offset appended. } /** * Converts a Date to ISO8601 string using current options. */ encodeIso8601(date) { const parts = this.opts.local ? DateFormatter.getLocalDateParts(date) : DateFormatter.getUTCDateParts(date); return [ [parts[0], parts[1], parts[2]].join(this.opts.hyphens ? "-" : ""), "T", [parts[3], parts[4], parts[5]].join(this.opts.colons ? ":" : ""), this.opts.ms ? "." + parts[6] : "", this.opts.local ? (this.opts.offset ? DateFormatter.formatCurrentOffset(date) : "") : "Z", ].join(""); } /** * UTC parts (YYYY, MM, DD, hh, mm, ss, mmm) with zero-padding where needed. */ static getUTCDateParts(date) { return [ date.getUTCFullYear(), DateFormatter.zeroPad(date.getUTCMonth() + 1, 2), DateFormatter.zeroPad(date.getUTCDate(), 2), DateFormatter.zeroPad(date.getUTCHours(), 2), DateFormatter.zeroPad(date.getUTCMinutes(), 2), DateFormatter.zeroPad(date.getUTCSeconds(), 2), DateFormatter.zeroPad(date.getUTCMilliseconds(), 3), ]; } /** * Local parts (YYYY, MM, DD, hh, mm, ss, mmm) with zero-padding where needed. */ static getLocalDateParts(date) { return [ date.getFullYear(), DateFormatter.zeroPad(date.getMonth() + 1, 2), DateFormatter.zeroPad(date.getDate(), 2), DateFormatter.zeroPad(date.getHours(), 2), DateFormatter.zeroPad(date.getMinutes(), 2), DateFormatter.zeroPad(date.getSeconds(), 2), DateFormatter.zeroPad(date.getMilliseconds(), 3), ]; } /** * Left-pad a number with zeros to the specified length. */ static zeroPad(digit, length) { let padded = "" + digit; while (padded.length < length) padded = "0" + padded; return padded; } /** * Returns timezone offset in "Z" or "+/-HH:MM" form (for the given date or now). */ static formatCurrentOffset(d) { const offset = (d || new Date()).getTimezoneOffset(); // minutes, positive = behind UTC if (offset === 0) return "Z"; const sign = offset < 0 ? "+" : "-"; const hh = DateFormatter.zeroPad(Math.abs(Math.floor(offset / 60)), 2); const mm = DateFormatter.zeroPad(Math.abs(offset % 60), 2); return `${sign}${hh}:${mm}`; } } /** * Default options for DateFormatter */ DateFormatter.DEFAULT_OPTIONS = { colons: true, hyphens: false, local: true, ms: false, offset: false, }; /** * Regular Expression that dissects ISO 8601 formatted strings into parts. */ DateFormatter.ISO8601 = new RegExp("([0-9]{4})([-]?([0-9]{2}))([-]?([0-9]{2}))" + "(T([0-9]{2})(((:?([0-9]{2}))?((:?([0-9]{2}))?(\\.([0-9]+))?))?)" + "(Z|([+-]([0-9]{2}(:?([0-9]{2}))?)))?)?"); // Export an instance (matches original CommonJS default behavior) const dateFormatter = new DateFormatter(); export default dateFormatter;