123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- "use strict";
- function padWithZeros(vNumber, width) {
- var numAsString = vNumber.toString();
- while (numAsString.length < width) {
- numAsString = "0" + numAsString;
- }
- return numAsString;
- }
- function addZero(vNumber) {
- return padWithZeros(vNumber, 2);
- }
- /**
- * Formats the TimeOffset
- * Thanks to http://www.svendtofte.com/code/date_format/
- * @private
- */
- function offset(timezoneOffset) {
- var os = Math.abs(timezoneOffset);
- var h = String(Math.floor(os / 60));
- var m = String(os % 60);
- if (h.length === 1) {
- h = "0" + h;
- }
- if (m.length === 1) {
- m = "0" + m;
- }
- return timezoneOffset < 0 ? "+" + h + m : "-" + h + m;
- }
- function asString(format, date) {
- if (typeof format !== "string") {
- date = format;
- format = module.exports.ISO8601_FORMAT;
- }
- if (!date) {
- date = module.exports.now();
- }
- // Issue # 14 - Per ISO8601 standard, the time string should be local time
- // with timezone info.
- // See https://en.wikipedia.org/wiki/ISO_8601 section "Time offsets from UTC"
- var vDay = addZero(date.getDate());
- var vMonth = addZero(date.getMonth() + 1);
- var vYearLong = addZero(date.getFullYear());
- var vYearShort = addZero(vYearLong.substring(2, 4));
- var vYear = format.indexOf("yyyy") > -1 ? vYearLong : vYearShort;
- var vHour = addZero(date.getHours());
- var vMinute = addZero(date.getMinutes());
- var vSecond = addZero(date.getSeconds());
- var vMillisecond = padWithZeros(date.getMilliseconds(), 3);
- var vTimeZone = offset(date.getTimezoneOffset());
- var formatted = format
- .replace(/dd/g, vDay)
- .replace(/MM/g, vMonth)
- .replace(/y{1,4}/g, vYear)
- .replace(/hh/g, vHour)
- .replace(/mm/g, vMinute)
- .replace(/ss/g, vSecond)
- .replace(/SSS/g, vMillisecond)
- .replace(/O/g, vTimeZone);
- return formatted;
- }
- function setDatePart(date, part, value, local) {
- date['set' + (local ? '' : 'UTC') + part](value);
- }
- function extractDateParts(pattern, str, missingValuesDate) {
- // Javascript Date object doesn't support custom timezone. Sets all felds as
- // GMT based to begin with. If the timezone offset is provided, then adjust
- // it using provided timezone, otherwise, adjust it with the system timezone.
- var local = pattern.indexOf('O') < 0;
- var matchers = [
- {
- pattern: /y{1,4}/,
- regexp: "\\d{1,4}",
- fn: function(date, value) {
- setDatePart(date, 'FullYear', value, local);
- }
- },
- {
- pattern: /MM/,
- regexp: "\\d{1,2}",
- fn: function(date, value) {
- setDatePart(date, 'Month', (value - 1), local);
- }
- },
- {
- pattern: /dd/,
- regexp: "\\d{1,2}",
- fn: function(date, value) {
- setDatePart(date, 'Date', value, local);
- }
- },
- {
- pattern: /hh/,
- regexp: "\\d{1,2}",
- fn: function(date, value) {
- setDatePart(date, 'Hours', value, local);
- }
- },
- {
- pattern: /mm/,
- regexp: "\\d\\d",
- fn: function(date, value) {
- setDatePart(date, 'Minutes', value, local);
- }
- },
- {
- pattern: /ss/,
- regexp: "\\d\\d",
- fn: function(date, value) {
- setDatePart(date, 'Seconds', value, local);
- }
- },
- {
- pattern: /SSS/,
- regexp: "\\d\\d\\d",
- fn: function(date, value) {
- setDatePart(date, 'Milliseconds', value, local);
- }
- },
- {
- pattern: /O/,
- regexp: "[+-]\\d{3,4}|Z",
- fn: function(date, value) {
- if (value === "Z") {
- value = 0;
- }
- var offset = Math.abs(value);
- var timezoneOffset = (value > 0 ? -1 : 1 ) * ((offset % 100) + Math.floor(offset / 100) * 60);
- // Per ISO8601 standard: UTC = local time - offset
- //
- // For example, 2000-01-01T01:00:00-0700
- // local time: 2000-01-01T01:00:00
- // ==> UTC : 2000-01-01T08:00:00 ( 01 - (-7) = 8 )
- //
- // To make it even more confusing, the date.getTimezoneOffset() is
- // opposite sign of offset string in the ISO8601 standard. So if offset
- // is '-0700' the getTimezoneOffset() would be (+)420. The line above
- // calculates timezoneOffset to matche Javascript's behavior.
- //
- // The date/time of the input is actually the local time, so the date
- // object that was constructed is actually local time even thought the
- // UTC setters are used. This means the date object's internal UTC
- // representation was wrong. It needs to be fixed by substracting the
- // offset (or adding the offset minutes as they are opposite sign).
- //
- // Note: the time zone has to be processed after all other fileds are
- // set. The result would be incorrect if the offset was calculated
- // first then overriden by the other filed setters.
- date.setUTCMinutes(date.getUTCMinutes() + timezoneOffset);
- }
- }
- ];
- var parsedPattern = matchers.reduce(
- function(p, m) {
- if (m.pattern.test(p.regexp)) {
- m.index = p.regexp.match(m.pattern).index;
- p.regexp = p.regexp.replace(m.pattern, "(" + m.regexp + ")");
- } else {
- m.index = -1;
- }
- return p;
- },
- { regexp: pattern, index: [] }
- );
- var dateFns = matchers.filter(function(m) {
- return m.index > -1;
- });
- dateFns.sort(function(a, b) {
- return a.index - b.index;
- });
- var matcher = new RegExp(parsedPattern.regexp);
- var matches = matcher.exec(str);
- if (matches) {
- var date = missingValuesDate || module.exports.now();
- dateFns.forEach(function(f, i) {
- f.fn(date, matches[i + 1]);
- });
- return date;
- }
- throw new Error(
- "String '" + str + "' could not be parsed as '" + pattern + "'"
- );
- }
- function parse(pattern, str, missingValuesDate) {
- if (!pattern) {
- throw new Error("pattern must be supplied");
- }
- return extractDateParts(pattern, str, missingValuesDate);
- }
- /**
- * Used for testing - replace this function with a fixed date.
- */
- function now() {
- return new Date();
- }
- module.exports = asString;
- module.exports.asString = asString;
- module.exports.parse = parse;
- module.exports.now = now;
- module.exports.ISO8601_FORMAT = "yyyy-MM-ddThh:mm:ss.SSS";
- module.exports.ISO8601_WITH_TZ_OFFSET_FORMAT = "yyyy-MM-ddThh:mm:ss.SSSO";
- module.exports.DATETIME_FORMAT = "dd MM yyyy hh:mm:ss.SSS";
- module.exports.ABSOLUTETIME_FORMAT = "hh:mm:ss.SSS";
|