//! moment-timezone-utils.js //! version : 0.4.1 //! author : Tim Wood //! license : MIT //! github.com/moment/moment-timezone (function (root, factory) { "use strict"; /*global define*/ if (typeof define === 'function' && define.amd) { define(['moment'], factory); // AMD } else if (typeof exports === 'object') { module.exports = factory(require('./')); // Node } else { factory(root.moment); // Browser } }(this, function (moment) { "use strict"; if (!moment.tz) { throw new Error("moment-timezone-utils.js must be loaded after moment-timezone.js"); } /************************************ Pack Base 60 ************************************/ var BASE60 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX', EPSILON = 0.000001; // Used to fix floating point rounding errors function packBase60Fraction(fraction, precision) { var buffer = '.', output = '', current; while (precision > 0) { precision -= 1; fraction *= 60; current = Math.floor(fraction + EPSILON); buffer += BASE60[current]; fraction -= current; // Only add buffer to output once we have a non-zero value. // This makes '.000' output '', and '.100' output '.1' if (current) { output += buffer; buffer = ''; } } return output; } function packBase60(number, precision) { var output = '', absolute = Math.abs(number), whole = Math.floor(absolute), fraction = packBase60Fraction(absolute - whole, Math.min(~~precision, 10)); while (whole > 0) { output = BASE60[whole % 60] + output; whole = Math.floor(whole / 60); } if (number < 0) { output = '-' + output; } if (output && fraction) { return output + fraction; } if (!fraction && output === '-') { return '0'; } return output || fraction || '0'; } /************************************ Pack ************************************/ function packUntils(untils) { var out = [], last = 0, i; for (i = 0; i < untils.length - 1; i++) { out[i] = packBase60(Math.round((untils[i] - last) / 1000) / 60, 1); last = untils[i]; } return out.join(' '); } function packAbbrsAndOffsets(source) { var index = 0, abbrs = [], offsets = [], indices = [], map = {}, i, key; for (i = 0; i < source.abbrs.length; i++) { key = source.abbrs[i] + '|' + source.offsets[i]; if (map[key] === undefined) { map[key] = index; abbrs[index] = source.abbrs[i]; offsets[index] = packBase60(Math.round(source.offsets[i] * 60) / 60, 1); index++; } indices[i] = packBase60(map[key], 0); } return abbrs.join(' ') + '|' + offsets.join(' ') + '|' + indices.join(''); } function validatePackData (source) { if (!source.name) { throw new Error("Missing name"); } if (!source.abbrs) { throw new Error("Missing abbrs"); } if (!source.untils) { throw new Error("Missing untils"); } if (!source.offsets) { throw new Error("Missing offsets"); } if ( source.offsets.length !== source.untils.length || source.offsets.length !== source.abbrs.length ) { throw new Error("Mismatched array lengths"); } } function pack (source) { validatePackData(source); return source.name + '|' + packAbbrsAndOffsets(source) + '|' + packUntils(source.untils); } /************************************ Create Links ************************************/ function arraysAreEqual(a, b) { var i; if (a.length !== b.length) { return false; } for (i = 0; i < a.length; i++) { if (a[i] !== b[i]) { return false; } } return true; } function zonesAreEqual(a, b) { return arraysAreEqual(a.offsets, b.offsets) && arraysAreEqual(a.abbrs, b.abbrs) && arraysAreEqual(a.untils, b.untils); } function findAndCreateLinks (input, output, links) { var i, j, a, b, isUnique; for (i = 0; i < input.length; i++) { isUnique = true; a = input[i]; for (j = 0; j < output.length; j++) { b = output[j]; if (zonesAreEqual(a, b)) { links.push(b.name + '|' + a.name); isUnique = false; continue; } } if (isUnique) { output.push(a); } } } function createLinks (source) { var zones = [], links = []; if (source.links) { links = source.links.slice(); } findAndCreateLinks(source.zones, zones, links); return { version : source.version, zones : zones, links : links.sort() }; } /************************************ Filter Years ************************************/ function findStartAndEndIndex (untils, start, end) { var startI = 0, endI = untils.length + 1, untilYear, i; if (!end) { end = start; } if (start > end) { i = start; start = end; end = i; } for (i = 0; i < untils.length; i++) { if (untils[i] == null) { continue; } untilYear = new Date(untils[i]).getUTCFullYear(); if (untilYear < start) { startI = i + 1; } if (untilYear > end) { endI = Math.min(endI, i + 1); } } return [startI, endI]; } function filterYears (source, start, end) { var slice = Array.prototype.slice, indices = findStartAndEndIndex(source.untils, start, end), untils = slice.apply(source.untils, indices); untils[untils.length - 1] = null; return { name : source.name, abbrs : slice.apply(source.abbrs, indices), untils : untils, offsets : slice.apply(source.offsets, indices) }; } /************************************ Filter, Link, and Pack ************************************/ function filterLinkPack (input, start, end) { var i, inputZones = input.zones, outputZones = [], output; for (i = 0; i < inputZones.length; i++) { outputZones[i] = filterYears(inputZones[i], start, end); } output = createLinks({ zones : outputZones, links : input.links.slice(), version : input.version }); for (i = 0; i < output.zones.length; i++) { output.zones[i] = pack(output.zones[i]); } return output; } /************************************ Exports ************************************/ moment.tz.pack = pack; moment.tz.packBase60 = packBase60; moment.tz.createLinks = createLinks; moment.tz.filterYears = filterYears; moment.tz.filterLinkPack = filterLinkPack; return moment; }));