polyfill_Intl_DateTimeFormat.js.html 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>JSDoc: Source: polyfill/Intl/DateTimeFormat.js</title>
  6. <script src="scripts/prettify/prettify.js"> </script>
  7. <script src="scripts/prettify/lang-css.js"> </script>
  8. <!--[if lt IE 9]>
  9. <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
  10. <![endif]-->
  11. <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
  12. <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
  13. </head>
  14. <body>
  15. <div id="main">
  16. <h1 class="page-title">Source: polyfill/Intl/DateTimeFormat.js</h1>
  17. <section>
  18. <article>
  19. <pre class="prettyprint source linenums"><code>// Licensed Materials - Property of IBM
  20. //
  21. // IBM Watson Analytics
  22. //
  23. // (C) Copyright IBM Corp. 2018
  24. //
  25. // US Government Users Restricted Rights - Use, duplication or
  26. // disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  27. module.exports = ( function( ObjectPolyfill, Format )
  28. {
  29. "use strict";
  30. /**
  31. * These classes are NOT a polyfill, and are not meant to be!
  32. * They provide a poor man's fallback for the Intl formatters, for non-compliant environments.
  33. */
  34. var NAME = [ "short", "long" ];
  35. var DATE_NUMBER = [ "numeric", "2-digit" ];
  36. var DATE_TEXT = [ "narrow" ].concat( NAME );
  37. var DATE_BOTH = DATE_NUMBER.concat( DATE_TEXT );
  38. var BOOLEAN = [ true, false ];
  39. var padStart = Function.prototype.call.bind( String.prototype.padStart );
  40. // This regex will match a sequence of possible formatter items
  41. var reReplace = /A+|a+|D+|d+|E+|e+|F+|G+|g+|H+|h+|K+|k+|M+|m+|S+|s+|u+|W+|w+|Y+|y+|Z+|z+/g;
  42. // This date is re-used for processing
  43. var d1 = new Date();
  44. /**
  45. * Object that parses an Options object and normalizes it to options.
  46. * @class module:barejs/polyfill/Intl.DateTimeFormat~DateTimeFormatOptions
  47. */
  48. function DateTimeFormatOptions( _options )
  49. {
  50. // Date
  51. this._conditionalSet( _options, "year", DATE_NUMBER );
  52. this._conditionalSet( _options, "month", DATE_BOTH );
  53. this._conditionalSet( _options, "day", DATE_NUMBER );
  54. this._conditionalSet( _options, "weekday", DATE_TEXT );
  55. // Time
  56. this._conditionalSet( _options, "hour", DATE_NUMBER );
  57. this._conditionalSet( _options, "minute", DATE_NUMBER );
  58. this._conditionalSet( _options, "second", DATE_NUMBER );
  59. this._conditionalSet( _options, "weekday", DATE_TEXT );
  60. this._conditionalSet( _options, "hour12", BOOLEAN );
  61. this._conditionalSet( _options, "timeZoneName", NAME );
  62. }
  63. ObjectPolyfill.defineProperties( DateTimeFormatOptions.prototype,
  64. /** @lends module:barejs/polyfill/Intl.DateTimeFormat~DateTimeFormatOptions# */
  65. {
  66. localeMatcher: { writable: true, value: null },
  67. timeZone: { writable: true, value: null },
  68. hour12: { writable: true, value: null },
  69. formatMatcher: { writable: true, value: null },
  70. weekday: { writable: true, value: null },
  71. era: { writable: true, value: null },
  72. year: { writable: true, value: null },
  73. month: { writable: true, value: null },
  74. day: { writable: true, value: null },
  75. hour: { writable: true, value: null },
  76. minute: { writable: true, value: null },
  77. second: { writable: true, value: null },
  78. timeZoneName: { writable: true, value: null },
  79. /**
  80. * Helper function. If _property is present on _options, will assign the value to this (with the
  81. * same _property name), and validate the value against _validValues while doing so.
  82. * @param _options {Object} The options to validate
  83. * @param _property {String} The name of the property
  84. * @param _validValues {Array} The list of valid values
  85. */
  86. _conditionalSet:
  87. {
  88. value: function( _options, _property, _validValues )
  89. {
  90. if ( typeof _options[ _property ] !== "undefined" )
  91. {
  92. if ( !_validValues.includes( this[ _property ] = _options[ _property ] ) )
  93. throw new RangeError( "Invalid value for " + _property + ": " + _options[ _property ] );
  94. }
  95. }
  96. }
  97. } );
  98. /**
  99. * Supports NUMERICAL formatting of dates, according to the formatting patterns described on
  100. * http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns
  101. * Warning: does NOT support formats like MMMM which should be localized. This method should only
  102. * be used to produce a fixed date format. It also doesn't support identifiers that require
  103. * knowledge of a specific calendar system, like "day of the week" or "era".
  104. * @param _date {Date} The date to format
  105. * @param _formatString {String} The formatString to use.
  106. * @param _utc {Boolean} Optional: set to true to use the UTC time zone instead of local.
  107. * @returns {String} _date formatted as String using _pattern.
  108. * @memberof module:barejs/polyfill/Intl.DateTimeFormat~
  109. */
  110. function formatDateTime( _date, _formatString, _utc )
  111. {
  112. // Always assign to d1 so we convert a number to a date, and can safely modify the
  113. // date object to adjust for the time zone
  114. d1.setTime( _date || Date.now() );
  115. _utc = _utc === true; // ensure boolean
  116. return String( _formatString ).replace( reReplace, function( _match )
  117. {
  118. var v; // value; used by most format specifiers
  119. var c = _match.charAt( 0 ); // The first (and every) character of the matched pattern
  120. var l = _match.length; // short alias for _match.length.
  121. // First, grab values. Some values early out by returning immediately or throwing an error.
  122. switch ( c )
  123. {
  124. //
  125. // Values
  126. //
  127. case "y": // Year
  128. v = _utc ? d1.getUTCFullYear() : d1.getFullYear();
  129. // So two-digit years are a stupid idea (where's the cut-off point?!).
  130. // As a formatter, we just take the last two digits and don't care about a cut-off.
  131. // This does mean that 1894 and 1994 will both produce 94, which can't be distinguished.
  132. // The alternative would be a configurable cut-off year, but the best alternative
  133. // would be for people to stop chopping away significant digits.
  134. if ( l === 2 )
  135. v %= 100;
  136. break;
  137. case "M": // Month
  138. v = ( _utc ? d1.getUTCMonth() : d1.getMonth() ) + 1; // compensate for 0 based
  139. break;
  140. case "d": // Day in month
  141. v = _utc ? d1.getUTCDate() : d1.getDate();
  142. break;
  143. case "D": // Day of year
  144. // Start by making v a new UTC date on January 1st of the same year.
  145. // Using UTC will avoid DST differences.
  146. v = new Date( Date.UTC( d1.getUTCFullYear(), 0, 1, d1.getUTCHours(), d1.getUTCMinutes(), d1.getUTCSeconds(), d1.getUTCMilliseconds() ) );
  147. // Calculate the number of days and make the value 1 based.
  148. // Although we expect an integer result (due to the usage of UTC), round the result
  149. // in case the browser included leap seconds, or some other unforeseen difference.
  150. v = Math.round( ( d1.getTime() - v.getTime() ) / 86400000 ) + 1;
  151. break;
  152. case "E": // Day of week - Sunday is always day 1
  153. v = ( _utc ? d1.getUTCDay() : d1.getDay() ) + 1;
  154. break;
  155. case "H": // Hour [0-23]
  156. case "h": // Hour [1-12]
  157. case "K": // Hour [0-11]
  158. case "k": // Hour [1-24]
  159. v = _utc ? d1.getUTCHours() : d1.getHours();
  160. // v is now [0-23]
  161. switch ( c )
  162. {
  163. case 'h':
  164. v = ( v % 12 ) || 12; // translate to [1-12]
  165. break;
  166. case 'K':
  167. v = ( v % 12 ); // translate to [0-11]
  168. break;
  169. case 'k':
  170. v = v || 24; // translate to [1-24]
  171. break;
  172. }
  173. break;
  174. case "m": // Minute
  175. v = _utc ? d1.getUTCMinutes() : d1.getMinutes();
  176. break;
  177. case "s": // Second
  178. v = _utc ? d1.getUTCSeconds() : d1.getSeconds();
  179. break;
  180. case "S": // Fractional Second - rounds to the count of letters
  181. v = Math.round( ( _utc ? d1.getUTCMilliseconds() : d1.getMilliseconds() ) * Math.pow( 10, l - 3 ) );
  182. break;
  183. //
  184. // Instant return
  185. //
  186. case "a": // AM or PM
  187. if ( l > 1 )
  188. throw new RangeError( "Invalid pattern: " + _match + ", a maximum of 1 character is allowed" );
  189. // Note: am/pm this should actually be localised. However, we're allowing this
  190. // since the 12 hour format would be useless otherwise.
  191. v = _utc ? d1.getUTCHours() : d1.getHours();
  192. return v &lt; 12 ? "am" : "pm";
  193. case "Z": // Time zone. 1: GMT format, 2: RFC 822
  194. if ( l > 2 )
  195. throw new RangeError( "Invalid pattern: " + _match + ", a maximum of 2 characters is allowed" );
  196. if ( _utc &amp;&amp; ( l === 2 ) )
  197. return "Z";
  198. v = _utc ? 0 : -d1.getTimezoneOffset();
  199. // Translate v to +-00:00 syntax
  200. v = ( v &lt; 0 ? "-" : "+" ) +
  201. padStart( Math.floor( v / 60 ), 2, "0" ) +
  202. ":" + padStart( v % 60, 2, "0" );
  203. // And immediately return
  204. return ( l === 1 ? "GMT" + v : v );
  205. //
  206. // Unsupported
  207. //
  208. /*
  209. case "A": // Milliseconds in day
  210. case "e": // Day of week - Local (calendar based)
  211. case "F": // Day of Week in Month.
  212. case "G": // Era
  213. case "g": // Modified Julian day.
  214. case "u": // Extended year
  215. case "W": // Week of month
  216. case "w": // Week of year
  217. case "Y": // Year (of "Week of Year"), used in ISO year-week calendar. May differ from calendar year.
  218. case "z": // Timezone. 1: short wall (generic), 2: long wall, 3: short time zone (i.e. PST) 4: full name (Pacific Standard Time).
  219. */
  220. default:
  221. throw new Error( "format identifier " + _match.charAt( 0 ) + "is not supported by this method" );
  222. }
  223. // Process values
  224. switch ( c )
  225. {
  226. // Two digit maximum, more is invalid
  227. case "H": // Hour [0-23]
  228. case "h": // Hour [1-12]
  229. case "K": // Hour [0-11]
  230. case "k": // Hour [1-24]
  231. case "m": // Minute
  232. case "s": // Second
  233. if ( l > 2 )
  234. throw new RangeError( "Invalid pattern: " + _match + ", a maximum of 2 characters is allowed" );
  235. break;
  236. // Three digit maximum, more is invalid
  237. case "D": // Day of year
  238. if ( l > 3 )
  239. throw new RangeError( "Invalid pattern: " + _match + ", a maximum of 3 characters is allowed" );
  240. break;
  241. // Five digit maximum, but only two digits are not localised.
  242. case "M": // Month
  243. case "d": // Day in month
  244. case "E": // Day of week - Sunday is always day 1
  245. if ( l > 5 )
  246. throw new RangeError( "Invalid pattern: " + _match + ", a maximum of 5 characters is allowed" );
  247. if ( l > 2 )
  248. throw new RangeError( "Pattern: " + _match + ", requires localisation, which is not supported by format" );
  249. break;
  250. // Unlimited repeat allowed (no validation needed)
  251. /*
  252. case "y": // Year
  253. case "S": // Fractional Second
  254. break;
  255. */
  256. }
  257. /*
  258. if ( ( maxLen > 0 ) &amp;&amp; ( l > maxLen ) )
  259. throw new RangeError( "Invalid pattern: " + _match + ", a maximum of " + maxLen + " characters is allowed" );
  260. */
  261. // If we get here, we can just return value (possibly padding it to length).
  262. return l > 1 ? padStart( v, l, "0" ) : v;
  263. } );
  264. }
  265. /**
  266. * Provides Date/Time formatting
  267. * @class module:barejs/polyfill/Intl.DateTimeFormat
  268. * @extends module:barejs/polyfill/Intl~Format
  269. */
  270. function DateTimeFormat( _locales, _options )
  271. {
  272. Format.call( this, _locales, new DateTimeFormatOptions( Object( _options ) ) );
  273. }
  274. DateTimeFormat.prototype = Object.create( Format.prototype,
  275. /** @lends module:barejs/polyfill/Intl.DateTimeFormat# */
  276. {
  277. format:
  278. {
  279. enumerable: true,
  280. value: function format( _value )
  281. {
  282. var parts = []; // used to build the date and/or time part
  283. var fmt = []; // used to build the end format
  284. switch ( this._options.year )
  285. {
  286. case "2-digit":
  287. parts.push( "yy" );
  288. break;
  289. case "numeric":
  290. parts.push( "yyyy" );
  291. break;
  292. }
  293. switch ( this._options.month )
  294. {
  295. case "narrow":
  296. case "short":
  297. case "long":
  298. // No actual implementation, default to 2-digit
  299. case "2-digit":
  300. parts.push( "MM" );
  301. break;
  302. case "numeric":
  303. parts.push( "M" );
  304. break;
  305. }
  306. switch ( this._options.day )
  307. {
  308. case "2-digit":
  309. parts.push( "dd" );
  310. break;
  311. case "numeric":
  312. parts.push( "d" );
  313. break;
  314. }
  315. if ( parts.length > 0 )
  316. {
  317. fmt.push( parts.join( "-" ) );
  318. parts.length = 0; // reset for time part
  319. }
  320. switch ( this._options.hour )
  321. {
  322. case "2-digit":
  323. parts.push( "HH" );
  324. break;
  325. case "numeric":
  326. parts.push( "H" );
  327. break;
  328. }
  329. switch ( this._options.minute )
  330. {
  331. case "2-digit":
  332. parts.push( "mm" );
  333. break;
  334. case "numeric":
  335. parts.push( "m" );
  336. break;
  337. }
  338. switch ( this._options.second )
  339. {
  340. case "2-digit":
  341. parts.push( "ss" );
  342. break;
  343. case "numeric":
  344. parts.push( "s" );
  345. break;
  346. }
  347. if ( parts.length > 0 )
  348. fmt.push( parts.join( ":" ) );
  349. // DateTimeFormat defaults to formatting year/month/day if no options where specified.
  350. if ( fmt.length &lt; 1 )
  351. fmt.push( "yyyy-MM-dd" );
  352. return formatDateTime( _value, fmt.join( " " ) );
  353. }
  354. }
  355. } );
  356. return DateTimeFormat;
  357. }( require( "../Object" ), require( "./Format" ) ) );
  358. </code></pre>
  359. </article>
  360. </section>
  361. </div>
  362. <nav>
  363. <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-barejs.html">barejs</a></li><li><a href="module-barejs_polyfill.html">barejs/polyfill</a></li><li><a href="module-barejs_polyfill_Intl.html">barejs/polyfill/Intl</a></li></ul><h3>Classes</h3><ul><li><a href="module-barejs.decl.html">decl</a></li><li><a href="module-barejs.decl-Enum.html">Enum</a></li><li><a href="module-barejs.decl-Interface.html">Interface</a></li><li><a href="module-barejs.decl-SpecialType.html">SpecialType</a></li><li><a href="module-barejs.Destroyable.html">Destroyable</a></li><li><a href="module-barejs.EventArgs.html">EventArgs</a></li><li><a href="module-barejs.Evented.html">Evented</a></li><li><a href="module-barejs.Evented-EventedHandle.html">EventedHandle</a></li><li><a href="module-barejs.Exception.html">Exception</a></li><li><a href="module-barejs_polyfill.Array.html">Array</a></li><li><a href="module-barejs_polyfill.Date.html">Date</a></li><li><a href="module-barejs_polyfill.EntryStore.html">EntryStore</a></li><li><a href="module-barejs_polyfill.EntryStore.Iterator.html">Iterator</a></li><li><a href="module-barejs_polyfill.Function.html">Function</a></li><li><a href="module-barejs_polyfill.Map.html">Map</a></li><li><a href="module-barejs_polyfill.Map-MapIterator.html">MapIterator</a></li><li><a href="module-barejs_polyfill.Math.html">Math</a></li><li><a href="module-barejs_polyfill.Number.html">Number</a></li><li><a href="module-barejs_polyfill.Object.html">Object</a></li><li><a href="module-barejs_polyfill.Promise.html">Promise</a></li><li><a href="module-barejs_polyfill.Set.html">Set</a></li><li><a href="module-barejs_polyfill.Set-SetIterator.html">SetIterator</a></li><li><a href="module-barejs_polyfill.String.html">String</a></li><li><a href="module-barejs_polyfill.Symbol.html">Symbol</a></li><li><a href="module-barejs_polyfill.WeakMap.html">WeakMap</a></li><li><a href="module-barejs_polyfill.WeakSet.html">WeakSet</a></li><li><a href="module-barejs_polyfill_Intl.DateTimeFormat.html">DateTimeFormat</a></li><li><a href="module-barejs_polyfill_Intl.DateTimeFormat-DateTimeFormatOptions.html">DateTimeFormatOptions</a></li><li><a href="module-barejs_polyfill_Intl.NumberFormat.html">NumberFormat</a></li><li><a href="module-barejs_polyfill_Intl.NumberFormat-NumberFormatOptions.html">NumberFormatOptions</a></li><li><a href="module-barejs_polyfill_Intl-Format.html">Format</a></li></ul>
  364. </nav>
  365. <br class="clear">
  366. <footer>
  367. Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Wed Oct 03 2018 15:59:34 GMT+0200 (W. Europe Daylight Time)
  368. </footer>
  369. <script> prettyPrint(); </script>
  370. <script src="scripts/linenumber.js"> </script>
  371. </body>
  372. </html>