| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887 |
- /**
- * Globalize v1.0.1
- *
- * http://github.com/jquery/globalize
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license
- * http://jquery.org/license
- *
- * Date: 2016-01-20T16:57Z
- */
- /*!
- * Globalize v1.0.1 2016-01-20T16:57Z Released under the MIT license
- * http://git.io/TrdQbw
- */
- (function( root, factory ) {
- // UMD returnExports
- if ( typeof define === "function" && define.amd ) {
- // AMD
- define([
- "cldr",
- "../globalize",
- "./number",
- "cldr/event",
- "cldr/supplemental"
- ], factory );
- } else if ( typeof exports === "object" ) {
- // Node, CommonJS
- module.exports = factory( require( "cldrjs" ), require( "globalize" ) );
- } else {
- // Extend global
- factory( root.Cldr, root.Globalize );
- }
- }(this, function( Cldr, Globalize ) {
- var createError = Globalize._createError,
- createErrorUnsupportedFeature = Globalize._createErrorUnsupportedFeature,
- formatMessage = Globalize._formatMessage,
- numberSymbol = Globalize._numberSymbol,
- regexpEscape = Globalize._regexpEscape,
- stringPad = Globalize._stringPad,
- validateCldr = Globalize._validateCldr,
- validateDefaultLocale = Globalize._validateDefaultLocale,
- validateParameterPresence = Globalize._validateParameterPresence,
- validateParameterType = Globalize._validateParameterType,
- validateParameterTypePlainObject = Globalize._validateParameterTypePlainObject,
- validateParameterTypeString = Globalize._validateParameterTypeString;
- var validateParameterTypeDate = function( value, name ) {
- validateParameterType( value, name, value === undefined || value instanceof Date, "Date" );
- };
- var createErrorInvalidParameterValue = function( name, value ) {
- return createError( "E_INVALID_PAR_VALUE", "Invalid `{name}` value ({value}).", {
- name: name,
- value: value
- });
- };
- /**
- * expandPattern( options, cldr )
- *
- * @options [Object] if String, it's considered a skeleton. Object accepts:
- * - skeleton: [String] lookup availableFormat;
- * - date: [String] ( "full" | "long" | "medium" | "short" );
- * - time: [String] ( "full" | "long" | "medium" | "short" );
- * - datetime: [String] ( "full" | "long" | "medium" | "short" );
- * - raw: [String] For more info see datetime/format.js.
- *
- * @cldr [Cldr instance].
- *
- * Return the corresponding pattern.
- * Eg for "en":
- * - "GyMMMd" returns "MMM d, y G";
- * - { skeleton: "GyMMMd" } returns "MMM d, y G";
- * - { date: "full" } returns "EEEE, MMMM d, y";
- * - { time: "full" } returns "h:mm:ss a zzzz";
- * - { datetime: "full" } returns "EEEE, MMMM d, y 'at' h:mm:ss a zzzz";
- * - { raw: "dd/mm" } returns "dd/mm";
- */
- var dateExpandPattern = function( options, cldr ) {
- var dateSkeleton, result, skeleton, timeSkeleton, type;
- function combineDateTime( type, datePattern, timePattern ) {
- return formatMessage(
- cldr.main([
- "dates/calendars/gregorian/dateTimeFormats",
- type
- ]),
- [ timePattern, datePattern ]
- );
- }
- switch ( true ) {
- case "skeleton" in options:
- skeleton = options.skeleton;
- result = cldr.main([
- "dates/calendars/gregorian/dateTimeFormats/availableFormats",
- skeleton
- ]);
- if ( !result ) {
- timeSkeleton = skeleton.split( /[^hHKkmsSAzZOvVXx]/ ).slice( -1 )[ 0 ];
- dateSkeleton = skeleton.split( /[^GyYuUrQqMLlwWdDFgEec]/ )[ 0 ];
- if ( /(MMMM|LLLL).*[Ec]/.test( dateSkeleton ) ) {
- type = "full";
- } else if ( /MMMM/g.test( dateSkeleton ) ) {
- type = "long";
- } else if ( /MMM/g.test( dateSkeleton ) || /LLL/g.test( dateSkeleton ) ) {
- type = "medium";
- } else {
- type = "short";
- }
- result = combineDateTime( type,
- cldr.main([
- "dates/calendars/gregorian/dateTimeFormats/availableFormats",
- dateSkeleton
- ]),
- cldr.main([
- "dates/calendars/gregorian/dateTimeFormats/availableFormats",
- timeSkeleton
- ])
- );
- }
- break;
- case "date" in options:
- case "time" in options:
- result = cldr.main([
- "dates/calendars/gregorian",
- "date" in options ? "dateFormats" : "timeFormats",
- ( options.date || options.time )
- ]);
- break;
- case "datetime" in options:
- result = combineDateTime( options.datetime,
- cldr.main([ "dates/calendars/gregorian/dateFormats", options.datetime ]),
- cldr.main([ "dates/calendars/gregorian/timeFormats", options.datetime ])
- );
- break;
- case "raw" in options:
- result = options.raw;
- break;
- default:
- throw createErrorInvalidParameterValue({
- name: "options",
- value: options
- });
- }
- return result;
- };
- /**
- * 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 ) );
- };
- var dateWeekDays = [ "sun", "mon", "tue", "wed", "thu", "fri", "sat" ];
- /**
- * firstDayOfWeek
- */
- var dateFirstDayOfWeek = function( cldr ) {
- return dateWeekDays.indexOf( cldr.supplemental.weekData.firstDay() );
- };
- /**
- * 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 );
- });
- };
- /**
- * 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;
- });
- };
- /**
- * properties( pattern, cldr )
- *
- * @pattern [String] raw pattern.
- * ref: http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
- *
- * @cldr [Cldr instance].
- *
- * Return the properties given the pattern and cldr.
- *
- * TODO Support other calendar types.
- */
- var dateFormatProperties = function( pattern, cldr ) {
- var properties = {
- numberFormatters: {},
- pattern: pattern,
- timeSeparator: numberSymbol( "timeSeparator", cldr )
- },
- widths = [ "abbreviated", "wide", "narrow" ];
- function setNumberFormatterPattern( pad ) {
- properties.numberFormatters[ pad ] = stringPad( "", pad );
- }
- pattern.replace( datePatternRe, function( current ) {
- var formatNumber,
- chr = current.charAt( 0 ),
- length = current.length;
- if ( chr === "j" ) {
- // Locale preferred hHKk.
- // http://www.unicode.org/reports/tr35/tr35-dates.html#Time_Data
- properties.preferredTime = chr = cldr.supplemental.timeData.preferred();
- }
- // ZZZZ: same as "OOOO".
- if ( chr === "Z" && length === 4 ) {
- chr = "O";
- length = 4;
- }
- switch ( chr ) {
- // Era
- case "G":
- properties.eras = cldr.main([
- "dates/calendars/gregorian/eras",
- length <= 3 ? "eraAbbr" : ( length === 4 ? "eraNames" : "eraNarrow" )
- ]);
- break;
- // Year
- case "y":
- // Plain year.
- formatNumber = true;
- break;
- case "Y":
- // Year in "Week of Year"
- properties.firstDay = dateFirstDayOfWeek( cldr );
- properties.minDays = cldr.supplemental.weekData.minDays();
- formatNumber = true;
- break;
- case "u": // Extended year. Need to be implemented.
- case "U": // Cyclic year name. Need to be implemented.
- throw createErrorUnsupportedFeature({
- feature: "year pattern `" + chr + "`"
- });
- // Quarter
- case "Q":
- case "q":
- if ( length > 2 ) {
- if ( !properties.quarters ) {
- properties.quarters = {};
- }
- if ( !properties.quarters[ chr ] ) {
- properties.quarters[ chr ] = {};
- }
- properties.quarters[ chr ][ length ] = cldr.main([
- "dates/calendars/gregorian/quarters",
- chr === "Q" ? "format" : "stand-alone",
- widths[ length - 3 ]
- ]);
- } else {
- formatNumber = true;
- }
- break;
- // Month
- case "M":
- case "L":
- if ( length > 2 ) {
- if ( !properties.months ) {
- properties.months = {};
- }
- if ( !properties.months[ chr ] ) {
- properties.months[ chr ] = {};
- }
- properties.months[ chr ][ length ] = cldr.main([
- "dates/calendars/gregorian/months",
- chr === "M" ? "format" : "stand-alone",
- widths[ length - 3 ]
- ]);
- } else {
- formatNumber = true;
- }
- break;
- // Week - Week of Year (w) or Week of Month (W).
- case "w":
- case "W":
- properties.firstDay = dateFirstDayOfWeek( cldr );
- properties.minDays = cldr.supplemental.weekData.minDays();
- formatNumber = true;
- break;
- // Day
- case "d":
- case "D":
- case "F":
- formatNumber = true;
- break;
- case "g":
- // Modified Julian day. Need to be implemented.
- throw createErrorUnsupportedFeature({
- feature: "Julian day pattern `g`"
- });
- // Week day
- case "e":
- case "c":
- if ( length <= 2 ) {
- properties.firstDay = dateFirstDayOfWeek( cldr );
- formatNumber = true;
- break;
- }
- /* falls through */
- case "E":
- if ( !properties.days ) {
- properties.days = {};
- }
- if ( !properties.days[ chr ] ) {
- properties.days[ chr ] = {};
- }
- if ( length === 6 ) {
- // 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
- // http://unicode.org/cldr/trac/ticket/6790
- properties.days[ chr ][ length ] = cldr.main([
- "dates/calendars/gregorian/days",
- chr === "c" ? "stand-alone" : "format",
- "short"
- ]) || cldr.main([
- "dates/calendars/gregorian/days",
- chr === "c" ? "stand-alone" : "format",
- "abbreviated"
- ]);
- } else {
- properties.days[ chr ][ length ] = cldr.main([
- "dates/calendars/gregorian/days",
- chr === "c" ? "stand-alone" : "format",
- widths[ length < 3 ? 0 : length - 3 ]
- ]);
- }
- break;
- // Period (AM or PM)
- case "a":
- properties.dayPeriods = cldr.main(
- "dates/calendars/gregorian/dayPeriods/format/wide"
- );
- break;
- // Hour
- case "h": // 1-12
- case "H": // 0-23
- case "K": // 0-11
- case "k": // 1-24
- // Minute
- case "m":
- // Second
- case "s":
- case "S":
- case "A":
- formatNumber = true;
- 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".
- properties.gmtFormat = cldr.main( "dates/timeZoneNames/gmtFormat" );
- properties.gmtZeroFormat = cldr.main( "dates/timeZoneNames/gmtZeroFormat" );
- properties.tzLongHourFormat = cldr.main( "dates/timeZoneNames/hourFormat" );
- /* falls through */
- case "Z":
- case "X":
- case "x":
- setNumberFormatterPattern( 1 );
- setNumberFormatterPattern( 2 );
- break;
- case "v":
- case "V":
- throw createErrorUnsupportedFeature({
- feature: "timezone pattern `" + chr + "`"
- });
- }
- if ( formatNumber ) {
- setNumberFormatterPattern( length );
- }
- });
- return 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;
- };
- /**
- * parseProperties( cldr )
- *
- * @cldr [Cldr instance].
- *
- * Return parser properties.
- */
- var dateParseProperties = function( cldr ) {
- return {
- preferredTimeData: cldr.supplemental.timeData.preferred()
- };
- };
- /**
- * 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;
- });
- if ( value !== "" ) {
- valid = false;
- }
- return valid ? tokens : [];
- };
- /**
- * tokenizerProperties( pattern, cldr )
- *
- * @pattern [String] raw pattern.
- *
- * @cldr [Cldr instance].
- *
- * Return Object with data that will be used by tokenizer.
- */
- var dateTokenizerProperties = function( pattern, cldr ) {
- var properties = {
- pattern: pattern,
- timeSeparator: numberSymbol( "timeSeparator", cldr )
- },
- widths = [ "abbreviated", "wide", "narrow" ];
- function populateProperties( path, value ) {
- // The `dates` and `calendars` trim's purpose is to reduce properties' key size only.
- properties[ path.replace( /^.*\/dates\//, "" ).replace( /calendars\//, "" ) ] = value;
- }
- cldr.on( "get", populateProperties );
- pattern.match( datePatternRe ).forEach(function( current ) {
- var chr, length;
- chr = current.charAt( 0 ),
- length = current.length;
- if ( chr === "Z" && length < 5 ) {
- chr = "O";
- length = 4;
- }
- switch ( chr ) {
- // Era
- case "G":
- cldr.main([
- "dates/calendars/gregorian/eras",
- length <= 3 ? "eraAbbr" : ( length === 4 ? "eraNames" : "eraNarrow" )
- ]);
- break;
- // Year
- case "u": // Extended year. Need to be implemented.
- case "U": // Cyclic year name. Need to be implemented.
- throw createErrorUnsupportedFeature({
- feature: "year pattern `" + chr + "`"
- });
- // Quarter
- case "Q":
- case "q":
- if ( length > 2 ) {
- cldr.main([
- "dates/calendars/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...
- if ( length > 2 ) {
- cldr.main([
- "dates/calendars/gregorian/months",
- chr === "M" ? "format" : "stand-alone",
- widths[ length - 3 ]
- ]);
- }
- break;
- // Day
- case "g":
- // Modified Julian day. Need to be implemented.
- throw createErrorUnsupportedFeature({
- feature: "Julian day pattern `g`"
- });
- // Week day
- case "e":
- case "c":
- // lookup for length >=3.
- if ( length <= 2 ) {
- 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
- cldr.main([
- "dates/calendars/gregorian/days",
- [ chr === "c" ? "stand-alone" : "format" ],
- "short"
- ]) || cldr.main([
- "dates/calendars/gregorian/days",
- [ chr === "c" ? "stand-alone" : "format" ],
- "abbreviated"
- ]);
- } else {
- cldr.main([
- "dates/calendars/gregorian/days",
- [ chr === "c" ? "stand-alone" : "format" ],
- widths[ length < 3 ? 0 : length - 3 ]
- ]);
- }
- break;
- // Period (AM or PM)
- case "a":
- cldr.main([
- "dates/calendars/gregorian/dayPeriods/format/wide"
- ]);
- break;
- // Zone
- case "z":
- case "O":
- cldr.main( "dates/timeZoneNames/gmtFormat" );
- cldr.main( "dates/timeZoneNames/gmtZeroFormat" );
- cldr.main( "dates/timeZoneNames/hourFormat" );
- break;
- case "v":
- case "V":
- throw createErrorUnsupportedFeature({
- feature: "timezone pattern `" + chr + "`"
- });
- }
- });
- cldr.off( "get", populateProperties );
- return properties;
- };
- function validateRequiredCldr( path, value ) {
- validateCldr( path, value, {
- skip: [
- /dates\/calendars\/gregorian\/dateTimeFormats\/availableFormats/,
- /dates\/calendars\/gregorian\/days\/.*\/short/,
- /supplemental\/timeData\/(?!001)/,
- /supplemental\/weekData\/(?!001)/
- ]
- });
- }
- /**
- * .dateFormatter( options )
- *
- * @options [Object] see date/expand_pattern for more info.
- *
- * Return a date formatter function (of the form below) according to the given options and the
- * default/instance locale.
- *
- * fn( value )
- *
- * @value [Date]
- *
- * Return a function that formats a date according to the given `format` and the default/instance
- * locale.
- */
- Globalize.dateFormatter =
- Globalize.prototype.dateFormatter = function( options ) {
- var cldr, numberFormatters, pad, pattern, properties;
- validateParameterTypePlainObject( options, "options" );
- cldr = this.cldr;
- options = options || { skeleton: "yMd" };
- validateDefaultLocale( cldr );
- cldr.on( "get", validateRequiredCldr );
- pattern = dateExpandPattern( options, cldr );
- properties = dateFormatProperties( pattern, cldr );
- cldr.off( "get", validateRequiredCldr );
- // Create needed number formatters.
- numberFormatters = properties.numberFormatters;
- delete properties.numberFormatters;
- for ( pad in numberFormatters ) {
- numberFormatters[ pad ] = this.numberFormatter({
- raw: numberFormatters[ pad ]
- });
- }
- return function( value ) {
- validateParameterPresence( value, "value" );
- validateParameterTypeDate( value, "value" );
- return dateFormat( value, numberFormatters, properties );
- };
- };
- /**
- * .dateParser( options )
- *
- * @options [Object] see date/expand_pattern for more info.
- *
- * Return a function that parses a string date according to the given `formats` and the
- * default/instance locale.
- */
- Globalize.dateParser =
- Globalize.prototype.dateParser = function( options ) {
- var cldr, numberParser, parseProperties, pattern, tokenizerProperties;
- validateParameterTypePlainObject( options, "options" );
- cldr = this.cldr;
- options = options || { skeleton: "yMd" };
- validateDefaultLocale( cldr );
- cldr.on( "get", validateRequiredCldr );
- pattern = dateExpandPattern( options, cldr );
- tokenizerProperties = dateTokenizerProperties( pattern, cldr );
- parseProperties = dateParseProperties( cldr );
- cldr.off( "get", validateRequiredCldr );
- numberParser = this.numberParser({ raw: "0" });
- return function( value ) {
- var tokens;
- validateParameterPresence( value, "value" );
- validateParameterTypeString( value, "value" );
- tokens = dateTokenizer( value, numberParser, tokenizerProperties );
- return dateParse( value, tokens, parseProperties ) || null;
- };
- };
- /**
- * .formatDate( value, options )
- *
- * @value [Date]
- *
- * @options [Object] see date/expand_pattern for more info.
- *
- * Formats a date or number according to the given options string and the default/instance locale.
- */
- Globalize.formatDate =
- Globalize.prototype.formatDate = function( value, options ) {
- validateParameterPresence( value, "value" );
- validateParameterTypeDate( value, "value" );
- return this.dateFormatter( options )( value );
- };
- /**
- * .parseDate( value, options )
- *
- * @value [String]
- *
- * @options [Object] see date/expand_pattern for more info.
- *
- * Return a Date instance or null.
- */
- Globalize.parseDate =
- Globalize.prototype.parseDate = function( value, options ) {
- validateParameterPresence( value, "value" );
- validateParameterTypeString( value, "value" );
- return this.dateParser( options )( value );
- };
- return Globalize;
- }));
|