aboutsummaryrefslogtreecommitdiffstats
path: root/external/globalize/globalize-runtime/date.js
diff options
context:
space:
mode:
Diffstat (limited to 'external/globalize/globalize-runtime/date.js')
-rw-r--r--external/globalize/globalize-runtime/date.js1289
1 files changed, 1289 insertions, 0 deletions
diff --git a/external/globalize/globalize-runtime/date.js b/external/globalize/globalize-runtime/date.js
new file mode 100644
index 000000000..118a5da05
--- /dev/null
+++ b/external/globalize/globalize-runtime/date.js
@@ -0,0 +1,1289 @@
+/**
+ * Globalize Runtime v1.1.0-rc.6
+ *
+ * http://github.com/jquery/globalize
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2015-11-18T10:38Z
+ */
+/*!
+ * Globalize Runtime v1.1.0-rc.6 2015-11-18T10:38Z 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,
+ 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 "'":
+ current = current.replace( /''/, "'" );
+ if ( length > 2 ) {
+ current = current.slice( 1, -1 );
+ }
+ ret = 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, 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;
+ }
+ dateSetMonth( date, value - 1 );
+ 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 - date.getTimezoneOffset();
+ 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 ( 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 ) {
+ date.setMinutes( date.getMinutes() + timezoneOffset );
+ }
+
+ // Truncate date at the most precise unit defined. Eg.
+ // If value is "12/31", and pattern is "MM/dd":
+ // => new Date( <current Year>, 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 + ")(" + regexpN.source + ")?" );
+ }
+ }
+
+ function twoDigitsIfLengthTwo() {
+ if ( length === 2 ) {
+
+ // Unicode equivalent to /\d\d/
+ numeric = true;
+ return tokenRe = new RegExp( "(" + regexpN.source + ")(" + regexpN.source + ")" );
+ }
+ }
+
+ // 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 ) {
+
+ // Unicode equivalent to /\d\d/
+ tokenRe = new RegExp( "(" + regexpN.source + ")(" + regexpN.source + ")" );
+ } 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...
+ oneOrTwoDigitsIfLengthOne() || twoDigitsIfLengthTwo() || lookup([
+ "gregorian/months",
+ chr === "M" ? "format" : "stand-alone",
+ widths[ length - 3 ]
+ ]);
+ break;
+
+ // Day
+ case "D":
+
+ // number {l,3}.
+ if ( length <= 3 ) {
+
+ // Unicode 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, Day, Hour, Minute, or Second
+ case "w":
+ case "d":
+ case "h":
+ case "H":
+ case "K":
+ case "k":
+ case "j":
+ case "m":
+ case "s":
+
+ // number l1:{1,2}, l2:{2}.
+ oneOrTwoDigitsIfLengthOne() || twoDigitsIfLengthTwo();
+ 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";
+ current = current.replace( /''/, "'" );
+ if ( length > 2 ) {
+ current = current.slice( 1, -1 );
+ }
+ tokenRe = new RegExp( regexpEscape( current ) );
+ break;
+
+ default:
+ token.type = "literal";
+ tokenRe = /./;
+ }
+
+ 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;
+ });
+
+ 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;
+
+
+
+
+}));