All Downloads are FREE. Search and download functionalities are using the official Maven repository.

META-INF.resources.bower_components.globalize.dist.globalize-runtime.date.js Maven / Gradle / Ivy

There is a newer version: 1.2.2.1-jre17
Show newest version
/**
 * Globalize Runtime v1.2.3
 *
 * http://github.com/jquery/globalize
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license
 * http://jquery.org/license
 *
 * Date: 2017-03-17T01:41Z
 */
/*!
 * Globalize Runtime v1.2.3 2017-03-17T01:41Z Released under the MIT license
 * http://git.io/TrdQbw
 */
(function (root, factory) {

    // UMD returnExports
    if (typeof define === "function" && define.amd) {

        // AMD
        define([
            "../globalize-runtime",
            "./number"
        ], factory);
    } else if (typeof exports === "object") {

        // Node, CommonJS
        module.exports = factory(
            require("../globalize-runtime"),
            require("./number")
        );
    } else {

        // Extend global
        factory(root.Globalize);
    }
}(this, function (Globalize) {

    var createErrorUnsupportedFeature = Globalize._createErrorUnsupportedFeature,
        regexpEscape = Globalize._regexpEscape,
        removeLiteralQuotes = Globalize._removeLiteralQuotes,
        runtimeKey = Globalize._runtimeKey,
        stringPad = Globalize._stringPad,
        validateParameterPresence = Globalize._validateParameterPresence,
        validateParameterType = Globalize._validateParameterType,
        validateParameterTypeString = Globalize._validateParameterTypeString;


    var validateParameterTypeDate = function (value, name) {
        validateParameterType(value, name, value === undefined || value instanceof Date, "Date");
    };


    /**
     * dayOfWeek( date, firstDay )
     *
     * @date
     *
     * @firstDay the result of `dateFirstDayOfWeek( cldr )`
     *
     * Return the day of the week normalized by the territory's firstDay [0-6].
     * Eg for "mon":
     * - return 0 if territory is GB, or BR, or DE, or FR (week starts on "mon");
     * - return 1 if territory is US (week starts on "sun");
     * - return 2 if territory is EG (week starts on "sat");
     */
    var dateDayOfWeek = function (date, firstDay) {
        return (date.getDay() - firstDay + 7) % 7;
    };


    /**
     * distanceInDays( from, to )
     *
     * Return the distance in days between from and to Dates.
     */
    var dateDistanceInDays = function (from, to) {
        var inDays = 864e5;
        return (to.getTime() - from.getTime()) / inDays;
    };


    /**
     * startOf changes the input to the beginning of the given unit.
     *
     * For example, starting at the start of a day, resets hours, minutes
     * seconds and milliseconds to 0. Starting at the month does the same, but
     * also sets the date to 1.
     *
     * Returns the modified date
     */
    var dateStartOf = function (date, unit) {
        date = new Date(date.getTime());
        switch (unit) {
            case "year":
                date.setMonth(0);
            /* falls through */
            case "month":
                date.setDate(1);
            /* falls through */
            case "day":
                date.setHours(0);
            /* falls through */
            case "hour":
                date.setMinutes(0);
            /* falls through */
            case "minute":
                date.setSeconds(0);
            /* falls through */
            case "second":
                date.setMilliseconds(0);
        }
        return date;
    };


    /**
     * dayOfYear
     *
     * Return the distance in days of the date to the begin of the year [0-d].
     */
    var dateDayOfYear = function (date) {
        return Math.floor(dateDistanceInDays(dateStartOf(date, "year"), date));
    };


    /**
     * millisecondsInDay
     */
    var dateMillisecondsInDay = function (date) {

        // TODO Handle daylight savings discontinuities
        return date - dateStartOf(date, "day");
    };


    var datePatternRe = (/([a-z])\1*|'([^']|'')+'|''|./ig);


    /**
     * hourFormat( date, format, timeSeparator, formatNumber )
     *
     * Return date's timezone offset according to the format passed.
     * Eg for format when timezone offset is 180:
     * - "+H;-H": -3
     * - "+HHmm;-HHmm": -0300
     * - "+HH:mm;-HH:mm": -03:00
     */
    var dateTimezoneHourFormat = function (date, format, timeSeparator, formatNumber) {
        var absOffset,
            offset = date.getTimezoneOffset();

        absOffset = Math.abs(offset);
        formatNumber = formatNumber || {
            1: function (value) {
                return stringPad(value, 1);
            },
            2: function (value) {
                return stringPad(value, 2);
            }
        };

        return format

        // Pick the correct sign side (+ or -).
            .split(";")[offset > 0 ? 1 : 0]

        // Localize time separator
            .replace(":", timeSeparator)

            // Update hours offset.
            .replace(/HH?/, function (match) {
                return formatNumber[match.length](Math.floor(absOffset / 60));
            })

            // Update minutes offset and return.
            .replace(/mm/, function () {
                return formatNumber[2](absOffset % 60);
            });
    };


    var dateWeekDays = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];


    /**
     * format( date, properties )
     *
     * @date [Date instance].
     *
     * @properties
     *
     * TODO Support other calendar types.
     *
     * Disclosure: this function borrows excerpts of dojo/date/locale.
     */
    var dateFormat = function (date, numberFormatters, properties) {
        var timeSeparator = properties.timeSeparator;

        return properties.pattern.replace(datePatternRe, function (current) {
            var ret,
                chr = current.charAt(0),
                length = current.length;

            if (chr === "j") {

                // Locale preferred hHKk.
                // http://www.unicode.org/reports/tr35/tr35-dates.html#Time_Data
                chr = properties.preferredTime;
            }

            if (chr === "Z") {

                // Z..ZZZ: same as "xxxx".
                if (length < 4) {
                    chr = "x";
                    length = 4;

                    // ZZZZ: same as "OOOO".
                } else if (length < 5) {
                    chr = "O";
                    length = 4;

                    // ZZZZZ: same as "XXXXX"
                } else {
                    chr = "X";
                    length = 5;
                }
            }

            switch (chr) {

                // Era
                case "G":
                    ret = properties.eras[date.getFullYear() < 0 ? 0 : 1];
                    break;

                // Year
                case "y":

                    // Plain year.
                    // The length specifies the padding, but for two letters it also specifies the
                    // maximum length.
                    ret = date.getFullYear();
                    if (length === 2) {
                        ret = String(ret);
                        ret = +ret.substr(ret.length - 2);
                    }
                    break;

                case "Y":

                    // Year in "Week of Year"
                    // The length specifies the padding, but for two letters it also specifies the
                    // maximum length.
                    // yearInWeekofYear = date + DaysInAWeek - (dayOfWeek - firstDay) - minDays
                    ret = new Date(date.getTime());
                    ret.setDate(
                        ret.getDate() + 7 -
                        dateDayOfWeek(date, properties.firstDay) -
                        properties.firstDay -
                        properties.minDays
                    );
                    ret = ret.getFullYear();
                    if (length === 2) {
                        ret = String(ret);
                        ret = +ret.substr(ret.length - 2);
                    }
                    break;

                // Quarter
                case "Q":
                case "q":
                    ret = Math.ceil((date.getMonth() + 1) / 3);
                    if (length > 2) {
                        ret = properties.quarters[chr][length][ret];
                    }
                    break;

                // Month
                case "M":
                case "L":
                    ret = date.getMonth() + 1;
                    if (length > 2) {
                        ret = properties.months[chr][length][ret];
                    }
                    break;

                // Week
                case "w":

                    // Week of Year.
                    // woy = ceil( ( doy + dow of 1/1 ) / 7 ) - minDaysStuff ? 1 : 0.
                    // TODO should pad on ww? Not documented, but I guess so.
                    ret = dateDayOfWeek(dateStartOf(date, "year"), properties.firstDay);
                    ret = Math.ceil((dateDayOfYear(date) + ret) / 7) -
                        (7 - ret >= properties.minDays ? 0 : 1);
                    break;

                case "W":

                    // Week of Month.
                    // wom = ceil( ( dom + dow of `1/month` ) / 7 ) - minDaysStuff ? 1 : 0.
                    ret = dateDayOfWeek(dateStartOf(date, "month"), properties.firstDay);
                    ret = Math.ceil((date.getDate() + ret) / 7) -
                        (7 - ret >= properties.minDays ? 0 : 1);
                    break;

                // Day
                case "d":
                    ret = date.getDate();
                    break;

                case "D":
                    ret = dateDayOfYear(date) + 1;
                    break;

                case "F":

                    // Day of Week in month. eg. 2nd Wed in July.
                    ret = Math.floor(date.getDate() / 7) + 1;
                    break;

                // Week day
                case "e":
                case "c":
                    if (length <= 2) {

                        // Range is [1-7] (deduced by example provided on documentation)
                        // TODO Should pad with zeros (not specified in the docs)?
                        ret = dateDayOfWeek(date, properties.firstDay) + 1;
                        break;
                    }

                /* falls through */
                case "E":
                    ret = dateWeekDays[date.getDay()];
                    ret = properties.days[chr][length][ret];
                    break;

                // Period (AM or PM)
                case "a":
                    ret = properties.dayPeriods[date.getHours() < 12 ? "am" : "pm"];
                    break;

                // Hour
                case "h": // 1-12
                    ret = (date.getHours() % 12) || 12;
                    break;

                case "H": // 0-23
                    ret = date.getHours();
                    break;

                case "K": // 0-11
                    ret = date.getHours() % 12;
                    break;

                case "k": // 1-24
                    ret = date.getHours() || 24;
                    break;

                // Minute
                case "m":
                    ret = date.getMinutes();
                    break;

                // Second
                case "s":
                    ret = date.getSeconds();
                    break;

                case "S":
                    ret = Math.round(date.getMilliseconds() * Math.pow(10, length - 3));
                    break;

                case "A":
                    ret = Math.round(dateMillisecondsInDay(date) * Math.pow(10, length - 3));
                    break;

                // Zone
                case "z":
                case "O":

                    // O: "{gmtFormat}+H;{gmtFormat}-H" or "{gmtZeroFormat}", eg. "GMT-8" or "GMT".
                    // OOOO: "{gmtFormat}{hourFormat}" or "{gmtZeroFormat}", eg. "GMT-08:00" or "GMT".
                    if (date.getTimezoneOffset() === 0) {
                        ret = properties.gmtZeroFormat;
                    } else {
                        ret = dateTimezoneHourFormat(
                            date,
                            length < 4 ? "+H;-H" : properties.tzLongHourFormat,
                            timeSeparator,
                            numberFormatters
                        );
                        ret = properties.gmtFormat.replace(/\{0\}/, ret);
                    }
                    break;

                case "X":

                    // Same as x*, except it uses "Z" for zero offset.
                    if (date.getTimezoneOffset() === 0) {
                        ret = "Z";
                        break;
                    }

                /* falls through */
                case "x":

                    // x: hourFormat("+HH;-HH")
                    // xx or xxxx: hourFormat("+HHmm;-HHmm")
                    // xxx or xxxxx: hourFormat("+HH:mm;-HH:mm")
                    ret = length === 1 ? "+HH;-HH" : (length % 2 ? "+HH:mm;-HH:mm" : "+HHmm;-HHmm");
                    ret = dateTimezoneHourFormat(date, ret, ":");
                    break;

                // timeSeparator
                case ":":
                    ret = timeSeparator;
                    break;

                // ' literals.
                case "'":
                    ret = removeLiteralQuotes(current);
                    break;

                // Anything else is considered a literal, including [ ,:/.@#], chinese, japonese, and
                // arabic characters.
                default:
                    ret = current;
            }
            if (typeof ret === "number") {
                ret = numberFormatters[length](ret);
            }
            return ret;
        });
    };


    var dateFormatterFn = function (numberFormatters, properties) {
        return function dateFormatter(value) {
            validateParameterPresence(value, "value");
            validateParameterTypeDate(value, "value");

            return dateFormat(value, numberFormatters, properties);
        };

    };


    /**
     * isLeapYear( year )
     *
     * @year [Number]
     *
     * Returns an indication whether the specified year is a leap year.
     */
    var dateIsLeapYear = function (year) {
        return new Date(year, 1, 29).getMonth() === 1;
    };


    /**
     * lastDayOfMonth( date )
     *
     * @date [Date]
     *
     * Return the last day of the given date's month
     */
    var dateLastDayOfMonth = function (date) {
        return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
    };


    /**
     * Differently from native date.setDate(), this function returns a date whose
     * day remains inside the month boundaries. For example:
     *
     * setDate( FebDate, 31 ): a "Feb 28" date.
     * setDate( SepDate, 31 ): a "Sep 30" date.
     */
    var dateSetDate = function (date, day) {
        var lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();

        date.setDate(day < 1 ? 1 : day < lastDay ? day : lastDay);
    };


    /**
     * Differently from native date.setMonth(), this function adjusts date if
     * needed, so final month is always the one set.
     *
     * setMonth( Jan31Date, 1 ): a "Feb 28" date.
     * setDate( Jan31Date, 8 ): a "Sep 30" date.
     */
    var dateSetMonth = function (date, month) {
        var originalDate = date.getDate();

        date.setDate(1);
        date.setMonth(month);
        dateSetDate(date, originalDate);
    };


    var outOfRange = function (value, low, high) {
        return value < low || value > high;
    };


    /**
     * parse( value, tokens, properties )
     *
     * @value [String] string date.
     *
     * @tokens [Object] tokens returned by date/tokenizer.
     *
     * @properties [Object] output returned by date/tokenizer-properties.
     *
     * ref: http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
     */
    var dateParse = function (value, tokens, properties) {
        var amPm, day, daysOfYear, month, era, hour, hour12, timezoneOffset, valid,
            YEAR = 0,
            MONTH = 1,
            DAY = 2,
            HOUR = 3,
            MINUTE = 4,
            SECOND = 5,
            MILLISECONDS = 6,
            date = new Date(),
            truncateAt = [],
            units = ["year", "month", "day", "hour", "minute", "second", "milliseconds"];

        if (!tokens.length) {
            return null;
        }

        valid = tokens.every(function (token) {
            var century, chr, value, length;

            if (token.type === "literal") {

                // continue
                return true;
            }

            chr = token.type.charAt(0);
            length = token.type.length;

            if (chr === "j") {

                // Locale preferred hHKk.
                // http://www.unicode.org/reports/tr35/tr35-dates.html#Time_Data
                chr = properties.preferredTimeData;
            }

            switch (chr) {

                // Era
                case "G":
                    truncateAt.push(YEAR);
                    era = +token.value;
                    break;

                // Year
                case "y":
                    value = token.value;
                    if (length === 2) {
                        if (outOfRange(value, 0, 99)) {
                            return false;
                        }

                        // mimic dojo/date/locale: choose century to apply, according to a sliding
                        // window of 80 years before and 20 years after present year.
                        century = Math.floor(date.getFullYear() / 100) * 100;
                        value += century;
                        if (value > date.getFullYear() + 20) {
                            value -= 100;
                        }
                    }
                    date.setFullYear(value);
                    truncateAt.push(YEAR);
                    break;

                case "Y": // Year in "Week of Year"
                    throw createErrorUnsupportedFeature({
                        feature: "year pattern `" + chr + "`"
                    });

                // Quarter (skip)
                case "Q":
                case "q":
                    break;

                // Month
                case "M":
                case "L":
                    if (length <= 2) {
                        value = token.value;
                    } else {
                        value = +token.value;
                    }
                    if (outOfRange(value, 1, 12)) {
                        return false;
                    }

                    // Setting the month later so that we have the correct year and can determine
                    // the correct last day of February in case of leap year.
                    month = value;
                    truncateAt.push(MONTH);
                    break;

                // Week (skip)
                case "w": // Week of Year.
                case "W": // Week of Month.
                    break;

                // Day
                case "d":
                    day = token.value;
                    truncateAt.push(DAY);
                    break;

                case "D":
                    daysOfYear = token.value;
                    truncateAt.push(DAY);
                    break;

                case "F":

                    // Day of Week in month. eg. 2nd Wed in July.
                    // Skip
                    break;

                // Week day
                case "e":
                case "c":
                case "E":

                    // Skip.
                    // value = arrayIndexOf( dateWeekDays, token.value );
                    break;

                // Period (AM or PM)
                case "a":
                    amPm = token.value;
                    break;

                // Hour
                case "h": // 1-12
                    value = token.value;
                    if (outOfRange(value, 1, 12)) {
                        return false;
                    }
                    hour = hour12 = true;
                    date.setHours(value === 12 ? 0 : value);
                    truncateAt.push(HOUR);
                    break;

                case "K": // 0-11
                    value = token.value;
                    if (outOfRange(value, 0, 11)) {
                        return false;
                    }
                    hour = hour12 = true;
                    date.setHours(value);
                    truncateAt.push(HOUR);
                    break;

                case "k": // 1-24
                    value = token.value;
                    if (outOfRange(value, 1, 24)) {
                        return false;
                    }
                    hour = true;
                    date.setHours(value === 24 ? 0 : value);
                    truncateAt.push(HOUR);
                    break;

                case "H": // 0-23
                    value = token.value;
                    if (outOfRange(value, 0, 23)) {
                        return false;
                    }
                    hour = true;
                    date.setHours(value);
                    truncateAt.push(HOUR);
                    break;

                // Minute
                case "m":
                    value = token.value;
                    if (outOfRange(value, 0, 59)) {
                        return false;
                    }
                    date.setMinutes(value);
                    truncateAt.push(MINUTE);
                    break;

                // Second
                case "s":
                    value = token.value;
                    if (outOfRange(value, 0, 59)) {
                        return false;
                    }
                    date.setSeconds(value);
                    truncateAt.push(SECOND);
                    break;

                case "A":
                    date.setHours(0);
                    date.setMinutes(0);
                    date.setSeconds(0);

                /* falls through */
                case "S":
                    value = Math.round(token.value * Math.pow(10, 3 - length));
                    date.setMilliseconds(value);
                    truncateAt.push(MILLISECONDS);
                    break;

                // Zone
                case "Z":
                case "z":
                case "O":
                case "X":
                case "x":
                    timezoneOffset = token.value;
                    break;
            }

            return true;
        });

        if (!valid) {
            return null;
        }

        // 12-hour format needs AM or PM, 24-hour format doesn't, ie. return null
        // if amPm && !hour12 || !amPm && hour12.
        if (hour && !(!amPm ^ hour12)) {
            return null;
        }

        if (era === 0) {

            // 1 BC = year 0
            date.setFullYear(date.getFullYear() * -1 + 1);
        }

        if (month !== undefined) {
            dateSetMonth(date, month - 1);
        }

        if (day !== undefined) {
            if (outOfRange(day, 1, dateLastDayOfMonth(date))) {
                return null;
            }
            date.setDate(day);
        } else if (daysOfYear !== undefined) {
            if (outOfRange(daysOfYear, 1, dateIsLeapYear(date.getFullYear()) ? 366 : 365)) {
                return null;
            }
            date.setMonth(0);
            date.setDate(daysOfYear);
        }

        if (hour12 && amPm === "pm") {
            date.setHours(date.getHours() + 12);
        }

        if (timezoneOffset !== undefined) {
            date.setMinutes(date.getMinutes() + timezoneOffset - date.getTimezoneOffset());
        }

        // Truncate date at the most precise unit defined. Eg.
        // If value is "12/31", and pattern is "MM/dd":
        // => new Date( , 12, 31, 0, 0, 0, 0 );
        truncateAt = Math.max.apply(null, truncateAt);
        date = dateStartOf(date, units[truncateAt]);

        return date;
    };


    /**
     * Generated by:
     *
     * regenerate().add( require( "unicode-7.0.0/categories/N/symbols" ) ).toString();
     *
     * https://github.com/mathiasbynens/regenerate
     * https://github.com/mathiasbynens/unicode-7.0.0
     */
    var regexpN = /[0-9\xB2\xB3\xB9\xBC-\xBE\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F\u09E6-\u09EF\u09F4-\u09F9\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0B72-\u0B77\u0BE6-\u0BF2\u0C66-\u0C6F\u0C78-\u0C7E\u0CE6-\u0CEF\u0D66-\u0D75\u0DE6-\u0DEF\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F33\u1040-\u1049\u1090-\u1099\u1369-\u137C\u16EE-\u16F0\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1946-\u194F\u19D0-\u19DA\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\u2070\u2074-\u2079\u2080-\u2089\u2150-\u2182\u2185-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2CFD\u3007\u3021-\u3029\u3038-\u303A\u3192-\u3195\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\uA620-\uA629\uA6E6-\uA6EF\uA830-\uA835\uA8D0-\uA8D9\uA900-\uA909\uA9D0-\uA9D9\uA9F0-\uA9F9\uAA50-\uAA59\uABF0-\uABF9\uFF10-\uFF19]|\uD800[\uDD07-\uDD33\uDD40-\uDD78\uDD8A\uDD8B\uDEE1-\uDEFB\uDF20-\uDF23\uDF41\uDF4A\uDFD1-\uDFD5]|\uD801[\uDCA0-\uDCA9]|\uD802[\uDC58-\uDC5F\uDC79-\uDC7F\uDCA7-\uDCAF\uDD16-\uDD1B\uDE40-\uDE47\uDE7D\uDE7E\uDE9D-\uDE9F\uDEEB-\uDEEF\uDF58-\uDF5F\uDF78-\uDF7F\uDFA9-\uDFAF]|\uD803[\uDE60-\uDE7E]|\uD804[\uDC52-\uDC6F\uDCF0-\uDCF9\uDD36-\uDD3F\uDDD0-\uDDD9\uDDE1-\uDDF4\uDEF0-\uDEF9]|\uD805[\uDCD0-\uDCD9\uDE50-\uDE59\uDEC0-\uDEC9]|\uD806[\uDCE0-\uDCF2]|\uD809[\uDC00-\uDC6E]|\uD81A[\uDE60-\uDE69\uDF50-\uDF59\uDF5B-\uDF61]|\uD834[\uDF60-\uDF71]|\uD835[\uDFCE-\uDFFF]|\uD83A[\uDCC7-\uDCCF]|\uD83C[\uDD00-\uDD0C]/;


    /**
     * tokenizer( value, pattern, properties )
     *
     * @value [String] string date.
     *
     * @properties [Object] output returned by date/tokenizer-properties.
     *
     * Returns an Array of tokens, eg. value "5 o'clock PM", pattern "h 'o''clock' a":
     * [{
 *   type: "h",
 *   lexeme: "5"
 * }, {
 *   type: "literal",
 *   lexeme: " "
 * }, {
 *   type: "literal",
 *   lexeme: "o'clock"
 * }, {
 *   type: "literal",
 *   lexeme: " "
 * }, {
 *   type: "a",
 *   lexeme: "PM",
 *   value: "pm"
 * }]
     *
     * OBS: lexeme's are always String and may return invalid ranges depending of the token type.
     * Eg. "99" for month number.
     *
     * Return an empty Array when not successfully parsed.
     */
    var dateTokenizer = function (value, numberParser, properties) {
        var valid,
            timeSeparator = properties.timeSeparator,
            tokens = [],
            widths = ["abbreviated", "wide", "narrow"];

        valid = properties.pattern.match(datePatternRe).every(function (current) {
            var chr, length, numeric, tokenRe,
                token = {};

            function hourFormatParse(tokenRe, numberParser) {
                var aux = value.match(tokenRe);
                numberParser = numberParser || function (value) {
                    return +value;
                };

                if (!aux) {
                    return false;
                }

                // hourFormat containing H only, e.g., `+H;-H`
                if (aux.length < 8) {
                    token.value =
                        (aux[1] ? -numberParser(aux[1]) : numberParser(aux[4])) * 60;

                    // hourFormat containing H and m, e.g., `+HHmm;-HHmm`
                } else {
                    token.value =
                        (aux[1] ? -numberParser(aux[1]) : numberParser(aux[7])) * 60 +
                        (aux[1] ? -numberParser(aux[4]) : numberParser(aux[10]));
                }

                return true;
            }

            // Transform:
            // - "+H;-H" -> /\+(\d\d?)|-(\d\d?)/
            // - "+HH;-HH" -> /\+(\d\d)|-(\d\d)/
            // - "+HHmm;-HHmm" -> /\+(\d\d)(\d\d)|-(\d\d)(\d\d)/
            // - "+HH:mm;-HH:mm" -> /\+(\d\d):(\d\d)|-(\d\d):(\d\d)/
            //
            // If gmtFormat is GMT{0}, the regexp must fill {0} in each side, e.g.:
            // - "+H;-H" -> /GMT\+(\d\d?)|GMT-(\d\d?)/
            function hourFormatRe(hourFormat, gmtFormat, timeSeparator) {
                var re;

                if (!gmtFormat) {
                    gmtFormat = "{0}";
                }

                re = hourFormat
                    .replace("+", "\\+")

                    // Unicode equivalent to (\\d\\d)
                    .replace(/HH|mm/g, "((" + regexpN.source + ")(" + regexpN.source + "))")

                    // Unicode equivalent to (\\d\\d?)
                    .replace(/H|m/g, "((" + regexpN.source + ")(" + regexpN.source + ")?)");

                if (timeSeparator) {
                    re = re.replace(/:/g, timeSeparator);
                }

                re = re.split(";").map(function (part) {
                    return gmtFormat.replace("{0}", part);
                }).join("|");

                return new RegExp(re);
            }

            function oneDigitIfLengthOne() {
                if (length === 1) {

                    // Unicode equivalent to /\d/
                    numeric = true;
                    return tokenRe = regexpN;
                }
            }

            function oneOrTwoDigitsIfLengthOne() {
                if (length === 1) {

                    // Unicode equivalent to /\d\d?/
                    numeric = true;
                    return tokenRe = new RegExp("(" + regexpN.source + "){1,2}");
                }
            }

            function oneOrTwoDigitsIfLengthOneOrTwo() {
                if (length === 1 || length === 2) {

                    // Unicode equivalent to /\d\d?/
                    numeric = true;
                    return tokenRe = new RegExp("(" + regexpN.source + "){1,2}");
                }
            }

            function twoDigitsIfLengthTwo() {
                if (length === 2) {

                    // Unicode equivalent to /\d\d/
                    numeric = true;
                    return tokenRe = new RegExp("(" + regexpN.source + "){2}");
                }
            }

            // Brute-force test every locale entry in an attempt to match the given value.
            // Return the first found one (and set token accordingly), or null.
            function lookup(path) {
                var i, re,
                    data = properties[path.join("/")];

                for (i in data) {
                    re = new RegExp("^" + data[i]);
                    if (re.test(value)) {
                        token.value = i;
                        return tokenRe = new RegExp(data[i]);
                    }
                }
                return null;
            }

            token.type = current;
            chr = current.charAt(0),
                length = current.length;

            if (chr === "Z") {

                // Z..ZZZ: same as "xxxx".
                if (length < 4) {
                    chr = "x";
                    length = 4;

                    // ZZZZ: same as "OOOO".
                } else if (length < 5) {
                    chr = "O";
                    length = 4;

                    // ZZZZZ: same as "XXXXX"
                } else {
                    chr = "X";
                    length = 5;
                }
            }

            switch (chr) {

                // Era
                case "G":
                    lookup([
                        "gregorian/eras",
                        length <= 3 ? "eraAbbr" : (length === 4 ? "eraNames" : "eraNarrow")
                    ]);
                    break;

                // Year
                case "y":
                case "Y":
                    numeric = true;

                    // number l=1:+, l=2:{2}, l=3:{3,}, l=4:{4,}, ...
                    if (length === 1) {

                        // Unicode equivalent to /\d+/.
                        tokenRe = new RegExp("(" + regexpN.source + ")+");
                    } else if (length === 2) {

                        // Lenient parsing: there's no year pattern to indicate non-zero-padded 2-digits
                        // year, so parser accepts both zero-padded and non-zero-padded for `yy`.
                        //
                        // Unicode equivalent to /\d\d?/
                        tokenRe = new RegExp("(" + regexpN.source + "){1,2}");
                    } else {

                        // Unicode equivalent to /\d{length,}/
                        tokenRe = new RegExp("(" + regexpN.source + "){" + length + ",}");
                    }
                    break;

                // Quarter
                case "Q":
                case "q":

                    // number l=1:{1}, l=2:{2}.
                    // lookup l=3...
                    oneDigitIfLengthOne() || twoDigitsIfLengthTwo() ||
                    lookup([
                        "gregorian/quarters",
                        chr === "Q" ? "format" : "stand-alone",
                        widths[length - 3]
                    ]);
                    break;

                // Month
                case "M":
                case "L":

                    // number l=1:{1,2}, l=2:{2}.
                    // lookup l=3...
                    //
                    // Lenient parsing: skeleton "yMd" (i.e., one M) may include MM for the pattern,
                    // therefore parser accepts both zero-padded and non-zero-padded for M and MM.
                    // Similar for L.
                    oneOrTwoDigitsIfLengthOneOrTwo() || lookup([
                        "gregorian/months",
                        chr === "M" ? "format" : "stand-alone",
                        widths[length - 3]
                    ]);
                    break;

                // Day
                case "D":

                    // number {l,3}.
                    if (length <= 3) {

                        // Equivalent to /\d{length,3}/
                        numeric = true;
                        tokenRe = new RegExp("(" + regexpN.source + "){" + length + ",3}");
                    }
                    break;

                case "W":
                case "F":

                    // number l=1:{1}.
                    oneDigitIfLengthOne();
                    break;

                // Week day
                case "e":
                case "c":

                    // number l=1:{1}, l=2:{2}.
                    // lookup for length >=3.
                    if (length <= 2) {
                        oneDigitIfLengthOne() || twoDigitsIfLengthTwo();
                        break;
                    }

                /* falls through */
                case "E":
                    if (length === 6) {

                        // Note: if short day names are not explicitly specified, abbreviated day
                        // names are used instead http://www.unicode.org/reports/tr35/tr35-dates.html#months_days_quarters_eras
                        lookup([
                            "gregorian/days",
                            [chr === "c" ? "stand-alone" : "format"],
                            "short"
                        ]) || lookup([
                            "gregorian/days",
                            [chr === "c" ? "stand-alone" : "format"],
                            "abbreviated"
                        ]);
                    } else {
                        lookup([
                            "gregorian/days",
                            [chr === "c" ? "stand-alone" : "format"],
                            widths[length < 3 ? 0 : length - 3]
                        ]);
                    }
                    break;

                // Period (AM or PM)
                case "a":
                    lookup([
                        "gregorian/dayPeriods/format/wide"
                    ]);
                    break;

                // Week
                case "w":

                    // number l1:{1,2}, l2:{2}.
                    oneOrTwoDigitsIfLengthOne() || twoDigitsIfLengthTwo();
                    break;

                // Day, Hour, Minute, or Second
                case "d":
                case "h":
                case "H":
                case "K":
                case "k":
                case "j":
                case "m":
                case "s":

                    // number l1:{1,2}, l2:{2}.
                    //
                    // Lenient parsing:
                    // - skeleton "hms" (i.e., one m) always includes mm for the pattern, i.e., it's
                    //   impossible to use a different skeleton to parse non-zero-padded minutes,
                    //   therefore parser accepts both zero-padded and non-zero-padded for m. Similar
                    //   for seconds s.
                    // - skeleton "hms" (i.e., one h) may include h or hh for the pattern, i.e., it's
                    //   impossible to use a different skeleton to parser non-zero-padded hours for some
                    //   locales, therefore parser accepts both zero-padded and non-zero-padded for h.
                    //   Similar for d (in skeleton yMd).
                    oneOrTwoDigitsIfLengthOneOrTwo();
                    break;

                case "S":

                    // number {l}.

                    // Unicode equivalent to /\d{length}/
                    numeric = true;
                    tokenRe = new RegExp("(" + regexpN.source + "){" + length + "}");
                    break;

                case "A":

                    // number {l+5}.

                    // Unicode equivalent to /\d{length+5}/
                    numeric = true;
                    tokenRe = new RegExp("(" + regexpN.source + "){" + (length + 5) + "}");
                    break;

                // Zone
                case "z":
                case "O":

                    // O: "{gmtFormat}+H;{gmtFormat}-H" or "{gmtZeroFormat}", eg. "GMT-8" or "GMT".
                    // OOOO: "{gmtFormat}{hourFormat}" or "{gmtZeroFormat}", eg. "GMT-08:00" or "GMT".
                    if (value === properties["timeZoneNames/gmtZeroFormat"]) {
                        token.value = 0;
                        tokenRe = new RegExp(properties["timeZoneNames/gmtZeroFormat"]);
                    } else {
                        tokenRe = hourFormatRe(
                            length < 4 ? "+H;-H" : properties["timeZoneNames/hourFormat"],
                            properties["timeZoneNames/gmtFormat"],
                            timeSeparator
                        );
                        if (!hourFormatParse(tokenRe, numberParser)) {
                            return null;
                        }
                    }
                    break;

                case "X":

                    // Same as x*, except it uses "Z" for zero offset.
                    if (value === "Z") {
                        token.value = 0;
                        tokenRe = /Z/;
                        break;
                    }

                /* falls through */
                case "x":

                    // x: hourFormat("+HH;-HH")
                    // xx or xxxx: hourFormat("+HHmm;-HHmm")
                    // xxx or xxxxx: hourFormat("+HH:mm;-HH:mm")
                    tokenRe = hourFormatRe(
                        length === 1 ? "+HH;-HH" : (length % 2 ? "+HH:mm;-HH:mm" : "+HHmm;-HHmm")
                    );
                    if (!hourFormatParse(tokenRe)) {
                        return null;
                    }
                    break;

                case "'":
                    token.type = "literal";
                    tokenRe = new RegExp(regexpEscape(removeLiteralQuotes(current)));
                    break;

                default:
                    token.type = "literal";
                    tokenRe = new RegExp(regexpEscape(current));
            }

            if (!tokenRe) {
                return false;
            }

            // Get lexeme and consume it.
            value = value.replace(new RegExp("^" + tokenRe.source), function (lexeme) {
                token.lexeme = lexeme;
                if (numeric) {
                    token.value = numberParser(lexeme);
                }
                return "";
            });

            if (!token.lexeme) {
                return false;
            }

            tokens.push(token);
            return true;
        });

        if (value !== "") {
            valid = false;
        }

        return valid ? tokens : [];
    };


    var dateParserFn = function (numberParser, parseProperties, tokenizerProperties) {
        return function dateParser(value) {
            var tokens;

            validateParameterPresence(value, "value");
            validateParameterTypeString(value, "value");

            tokens = dateTokenizer(value, numberParser, tokenizerProperties);
            return dateParse(value, tokens, parseProperties) || null;
        };
    };


    Globalize._dateFormatterFn = dateFormatterFn;
    Globalize._dateParserFn = dateParserFn;
    Globalize._dateFormat = dateFormat;
    Globalize._dateParser = dateParse;
    Globalize._dateTokenizer = dateTokenizer;
    Globalize._validateParameterTypeDate = validateParameterTypeDate;

    Globalize.dateFormatter =
        Globalize.prototype.dateFormatter = function (options) {
            options = options || {skeleton: "yMd"};
            return Globalize[runtimeKey("dateFormatter", this._locale, [options])];
        };

    Globalize.dateParser =
        Globalize.prototype.dateParser = function (options) {
            options = options || {skeleton: "yMd"};
            return Globalize[runtimeKey("dateParser", this._locale, [options])];
        };

    Globalize.formatDate =
        Globalize.prototype.formatDate = function (value, options) {
            validateParameterPresence(value, "value");
            validateParameterTypeDate(value, "value");

            return this.dateFormatter(options)(value);
        };

    Globalize.parseDate =
        Globalize.prototype.parseDate = function (value, options) {
            validateParameterPresence(value, "value");
            validateParameterTypeString(value, "value");

            return this.dateParser(options)(value);
        };

    return Globalize;


}));




© 2015 - 2024 Weber Informatics LLC | Privacy Policy