3214e2f622b93a2fd823591b8cc673316cf3b397.svn-base 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811
  1. if (!dojo._hasResource["dojo.date.locale"]) { // _hasResource checks added by
  2. // build. Do not use
  3. // _hasResource directly in your
  4. // code.
  5. dojo._hasResource["dojo.date.locale"] = true;
  6. dojo.provide("dojo.date.locale");
  7. // Localization methods for Date. Honor local customs using locale-dependent
  8. // dojo.cldr data.
  9. dojo.require("dojo.date");
  10. dojo.require("dojo.cldr.supplemental");
  11. dojo.require("dojo.regexp");
  12. dojo.require("dojo.string");
  13. dojo.require("dojo.i18n");
  14. // Load the bundles containing localization information for
  15. // names and formats
  16. dojo
  17. .requireLocalization(
  18. "dojo.cldr",
  19. "gregorian",
  20. null,
  21. "ko,zh-cn,zh,ja,en,it-it,en-ca,en-au,it,en-gb,es-es,fr,pt,ROOT,ko-kr,es,de,pt-br");
  22. // NOTE: Everything in this module assumes Gregorian calendars.
  23. // Other calendars will be implemented in separate modules.
  24. (function() {
  25. // Format a pattern without literals
  26. function formatPattern(dateObject, bundle, pattern) {
  27. return pattern.replace(/([a-z])\1*/ig, function(match) {
  28. var s;
  29. var c = match.charAt(0);
  30. var l = match.length;
  31. var pad;
  32. var widthList = ["abbr", "wide", "narrow"];
  33. switch (c) {
  34. case 'G' :
  35. s = bundle[(l < 4) ? "eraAbbr" : "eraNames"][dateObject
  36. .getFullYear() < 0 ? 0 : 1];
  37. break;
  38. case 'y' :
  39. s = dateObject.getFullYear();
  40. switch (l) {
  41. case 1 :
  42. break;
  43. case 2 :
  44. s = String(s);
  45. s = s.substr(s.length - 2);
  46. break;
  47. default :
  48. pad = true;
  49. }
  50. break;
  51. case 'Q' :
  52. case 'q' :
  53. s = Math.ceil((dateObject.getMonth() + 1) / 3);
  54. // switch(l){
  55. // case 1: case 2:
  56. pad = true;
  57. // break;
  58. // case 3: case 4: // unimplemented
  59. // }
  60. break;
  61. case 'M' :
  62. case 'L' :
  63. var m = dateObject.getMonth();
  64. var width;
  65. switch (l) {
  66. case 1 :
  67. case 2 :
  68. s = m + 1;
  69. pad = true;
  70. break;
  71. case 3 :
  72. case 4 :
  73. case 5 :
  74. width = widthList[l - 3];
  75. break;
  76. }
  77. if (width) {
  78. var type = (c == "L") ? "standalone" : "format";
  79. var prop = ["months", type, width].join("-");
  80. s = bundle[prop][m];
  81. }
  82. break;
  83. case 'w' :
  84. var firstDay = 0;
  85. s = dojo.date.locale._getWeekOfYear(dateObject,
  86. firstDay);
  87. pad = true;
  88. break;
  89. case 'd' :
  90. s = dateObject.getDate();
  91. pad = true;
  92. break;
  93. case 'D' :
  94. s = dojo.date.locale._getDayOfYear(dateObject);
  95. pad = true;
  96. break;
  97. case 'E' :
  98. case 'e' :
  99. case 'c' : // REVIEW: don't see this in the spec?
  100. var d = dateObject.getDay();
  101. var width;
  102. switch (l) {
  103. case 1 :
  104. case 2 :
  105. if (c == 'e') {
  106. var first = dojo.cldr.supplemental
  107. .getFirstDayOfWeek(options.locale);
  108. d = (d - first + 7) % 7;
  109. }
  110. if (c != 'c') {
  111. s = d + 1;
  112. pad = true;
  113. break;
  114. }
  115. // else fallthrough...
  116. case 3 :
  117. case 4 :
  118. case 5 :
  119. width = widthList[l - 3];
  120. break;
  121. }
  122. if (width) {
  123. var type = (c == "c") ? "standalone" : "format";
  124. var prop = ["days", type, width].join("-");
  125. s = bundle[prop][d];
  126. }
  127. break;
  128. case 'a' :
  129. var timePeriod = (dateObject.getHours() < 12)
  130. ? 'am'
  131. : 'pm';
  132. s = bundle[timePeriod];
  133. break;
  134. case 'h' :
  135. case 'H' :
  136. case 'K' :
  137. case 'k' :
  138. var h = dateObject.getHours();
  139. // strange choices in the date format make it impossible
  140. // to write this succinctly
  141. switch (c) {
  142. case 'h' : // 1-12
  143. s = (h % 12) || 12;
  144. break;
  145. case 'H' : // 0-23
  146. s = h;
  147. break;
  148. case 'K' : // 0-11
  149. s = (h % 12);
  150. break;
  151. case 'k' : // 1-24
  152. s = h || 24;
  153. break;
  154. }
  155. pad = true;
  156. break;
  157. case 'm' :
  158. s = dateObject.getMinutes();
  159. pad = true;
  160. break;
  161. case 's' :
  162. s = dateObject.getSeconds();
  163. pad = true;
  164. break;
  165. case 'S' :
  166. s = Math.round(dateObject.getMilliseconds()
  167. * Math.pow(10, l - 3));
  168. break;
  169. case 'v' : // FIXME: don't know what this is. seems to be
  170. // same as z?
  171. case 'z' :
  172. // We only have one timezone to offer; the one from the
  173. // browser
  174. s = dojo.date.getTimezoneName(dateObject);
  175. if (s) {
  176. break;
  177. }
  178. l = 4;
  179. // fallthrough... use GMT if tz not available
  180. case 'Z' :
  181. var offset = dateObject.getTimezoneOffset();
  182. var tz = [
  183. (offset <= 0 ? "+" : "-"),
  184. dojo.string.pad(Math.floor(Math.abs(offset)
  185. / 60), 2),
  186. dojo.string.pad(Math.abs(offset) % 60, 2)];
  187. if (l == 4) {
  188. tz.splice(0, 0, "GMT");
  189. tz.splice(3, 0, ":");
  190. }
  191. s = tz.join("");
  192. break;
  193. // case 'Y': case 'u': case 'W': case 'F': case 'g': case
  194. // 'A':
  195. // console.debug(match+" modifier unimplemented");
  196. default :
  197. throw new Error("dojo.date.locale.format: invalid pattern char: "
  198. + pattern);
  199. }
  200. if (pad) {
  201. s = dojo.string.pad(s, l);
  202. }
  203. return s;
  204. });
  205. }
  206. dojo.date.locale.format = function(/* Date */dateObject, /* Object? */
  207. options) {
  208. // summary:
  209. // Format a Date object as a String, using locale-specific settings.
  210. //
  211. // description:
  212. // Create a string from a Date object using a known localized
  213. // pattern.
  214. // By default, this method formats both date and time from
  215. // dateObject.
  216. // Formatting patterns are chosen appropriate to the locale.
  217. // Different
  218. // formatting lengths may be chosen, with "full" used by default.
  219. // Custom patterns may be used or registered with translations using
  220. // the addCustomFormats method.
  221. // Formatting patterns are implemented using the syntax described at
  222. // http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns
  223. //
  224. // dateObject:
  225. // the date and/or time to be formatted. If a time only is
  226. // formatted,
  227. // the values in the year, month, and day fields are irrelevant. The
  228. // opposite is true when formatting only dates.
  229. //
  230. // options: object {selector: string, formatLength: string,
  231. // datePattern: string, timePattern: string, locale: string}
  232. // selector- choice of 'time','date' (default: date and time)
  233. // formatLength- choice of long, short, medium or full (plus any
  234. // custom additions). Defaults to 'short'
  235. // datePattern,timePattern- override pattern with this string
  236. // am,pm- override strings for am/pm in times
  237. // locale- override the locale used to determine formatting rules
  238. options = options || {};
  239. var locale = dojo.i18n.normalizeLocale(options.locale);
  240. var formatLength = options.formatLength || 'short';
  241. var bundle = dojo.date.locale._getGregorianBundle(locale);
  242. var str = [];
  243. var sauce = dojo.hitch(this, formatPattern, dateObject, bundle);
  244. if (options.selector == "year") {
  245. // Special case as this is not yet driven by CLDR data
  246. var year = dateObject.getFullYear();
  247. if (locale.match(/^zh|^ja/)) {
  248. year += "\u5E74";
  249. }
  250. return year;
  251. }
  252. if (options.selector != "time") {
  253. var datePattern = options.datePattern
  254. || bundle["dateFormat-" + formatLength];
  255. if (datePattern) {
  256. str.push(_processPattern(datePattern, sauce));
  257. }
  258. }
  259. if (options.selector != "date") {
  260. var timePattern = options.timePattern
  261. || bundle["timeFormat-" + formatLength];
  262. if (timePattern) {
  263. str.push(_processPattern(timePattern, sauce));
  264. }
  265. }
  266. var result = str.join(" "); // TODO: use locale-specific pattern to
  267. // assemble date + time
  268. return result; // String
  269. };
  270. dojo.date.locale.regexp = function(/* Object? */options) {
  271. // summary:
  272. // Builds the regular needed to parse a localized date
  273. //
  274. // options: object {selector: string, formatLength: string,
  275. // datePattern: string, timePattern: string, locale: string, strict:
  276. // boolean}
  277. // selector- choice of 'time', 'date' (default: date and time)
  278. // formatLength- choice of long, short, medium or full (plus any
  279. // custom additions). Defaults to 'short'
  280. // datePattern,timePattern- override pattern with this string
  281. // locale- override the locale used to determine formatting rules
  282. return dojo.date.locale._parseInfo(options).regexp; // String
  283. };
  284. dojo.date.locale._parseInfo = function(/* Object? */options) {
  285. options = options || {};
  286. var locale = dojo.i18n.normalizeLocale(options.locale);
  287. var bundle = dojo.date.locale._getGregorianBundle(locale);
  288. var formatLength = options.formatLength || 'short';
  289. var datePattern = options.datePattern
  290. || bundle["dateFormat-" + formatLength];
  291. var timePattern = options.timePattern
  292. || bundle["timeFormat-" + formatLength];
  293. var pattern;
  294. if (options.selector == 'date') {
  295. pattern = datePattern;
  296. } else if (options.selector == 'time') {
  297. pattern = timePattern;
  298. } else {
  299. pattern = datePattern + ' ' + timePattern; // TODO: use
  300. // locale-specific
  301. // pattern to
  302. // assemble date +
  303. // time
  304. }
  305. var tokens = [];
  306. var re = _processPattern(pattern, dojo.hitch(this,
  307. _buildDateTimeRE, tokens, bundle, options));
  308. return {
  309. regexp : re,
  310. tokens : tokens,
  311. bundle : bundle
  312. };
  313. };
  314. dojo.date.locale.parse = function(/* String */value, /* Object? */options) {
  315. // summary:
  316. // Convert a properly formatted string to a primitive Date object,
  317. // using locale-specific settings.
  318. //
  319. // description:
  320. // Create a Date object from a string using a known localized
  321. // pattern.
  322. // By default, this method parses looking for both date and time in
  323. // the string.
  324. // Formatting patterns are chosen appropriate to the locale.
  325. // Different
  326. // formatting lengths may be chosen, with "full" used by default.
  327. // Custom patterns may be used or registered with translations using
  328. // the addCustomFormats method.
  329. // Formatting patterns are implemented using the syntax described at
  330. // http://www.unicode.org/reports/tr35/#Date_Format_Patterns
  331. //
  332. // value:
  333. // A string representation of a date
  334. //
  335. // options: object {selector: string, formatLength: string,
  336. // datePattern: string, timePattern: string, locale: string, strict:
  337. // boolean}
  338. // selector- choice of 'time', 'date' (default: date and time)
  339. // formatLength- choice of long, short, medium or full (plus any
  340. // custom additions). Defaults to 'short'
  341. // datePattern,timePattern- override pattern with this string
  342. // am,pm- override strings for am/pm in times
  343. // locale- override the locale used to determine formatting rules
  344. // strict- strict parsing, off by default
  345. var info = dojo.date.locale._parseInfo(options);
  346. var tokens = info.tokens, bundle = info.bundle;
  347. var re = new RegExp("^" + info.regexp + "$");
  348. var match = re.exec(value);
  349. if (!match) {
  350. return null;
  351. } // null
  352. var widthList = ['abbr', 'wide', 'narrow'];
  353. // 1972 is a leap year. We want to avoid Feb 29 rolling over into
  354. // Mar 1,
  355. // in the cases where the year is parsed after the month and day.
  356. var result = new Date(1972, 0);
  357. var expected = {};
  358. var amPm = "";
  359. dojo.forEach(match, function(v, i) {
  360. if (!i) {
  361. return;
  362. }
  363. var token = tokens[i - 1];
  364. var l = token.length;
  365. switch (token.charAt(0)) {
  366. case 'y' :
  367. if (l != 2) {
  368. // interpret year literally, so '5' would be
  369. // 5 A.D.
  370. result.setFullYear(v);
  371. expected.year = v;
  372. } else {
  373. if (v < 100) {
  374. v = Number(v);
  375. // choose century to apply, according to
  376. // a sliding window
  377. // of 80 years before and 20 years after
  378. // present year
  379. var year = ''
  380. + allGetServerTime().getFullYear();
  381. var century = year.substring(0, 2)
  382. * 100;
  383. var yearPart = Number(year.substring(2,
  384. 4));
  385. var cutoff = Math
  386. .min(yearPart + 20, 99);
  387. var num = (v < cutoff)
  388. ? century + v
  389. : century - 100 + v;
  390. result.setFullYear(num);
  391. expected.year = num;
  392. } else {
  393. // we expected 2 digits and got more...
  394. if (options.strict) {
  395. return null;
  396. }
  397. // interpret literally, so '150' would
  398. // be 150 A.D.
  399. // also tolerate '1950', if 'yyyy' input
  400. // passed to 'yy' format
  401. result.setFullYear(v);
  402. expected.year = v;
  403. }
  404. }
  405. break;
  406. case 'M' :
  407. if (l > 2) {
  408. var months = bundle['months-format-'
  409. + widthList[l - 3]].concat();
  410. if (!options.strict) {
  411. // Tolerate abbreviating period in month
  412. // part
  413. // Case-insensitive comparison
  414. v = v.replace(".", "").toLowerCase();
  415. months = dojo.map(months, function(s) {
  416. return s.replace(".", "")
  417. .toLowerCase();
  418. });
  419. }
  420. v = dojo.indexOf(months, v);
  421. if (v == -1) {
  422. // console.debug("dojo.date.locale.parse:
  423. // Could not parse month name: '" + v +
  424. // "'.");
  425. return null;
  426. }
  427. } else {
  428. v--;
  429. }
  430. result.setMonth(v);
  431. expected.month = v;
  432. break;
  433. case 'E' :
  434. case 'e' :
  435. var days = bundle['days-format-'
  436. + widthList[l - 3]].concat();
  437. if (!options.strict) {
  438. // Case-insensitive comparison
  439. v = v.toLowerCase();
  440. days = dojo.map(days, "".toLowerCase);
  441. }
  442. v = dojo.indexOf(days, v);
  443. if (v == -1) {
  444. // console.debug("dojo.date.locale.parse:
  445. // Could not parse weekday name: '" + v +
  446. // "'.");
  447. return null;
  448. }
  449. // TODO: not sure what to actually do with this
  450. // input,
  451. // in terms of setting something on the Date
  452. // obj...?
  453. // without more context, can't affect the actual
  454. // date
  455. // TODO: just validate?
  456. break;
  457. case 'd' :
  458. result.setDate(v);
  459. expected.date = v;
  460. break;
  461. case 'D' :
  462. // FIXME: need to defer this until after the
  463. // year is set for leap-year?
  464. result.setMonth(0);
  465. result.setDate(v);
  466. break;
  467. case 'a' : // am/pm
  468. var am = options.am || bundle.am;
  469. var pm = options.pm || bundle.pm;
  470. if (!options.strict) {
  471. var period = /\./g;
  472. v = v.replace(period, '').toLowerCase();
  473. am = am.replace(period, '').toLowerCase();
  474. pm = pm.replace(period, '').toLowerCase();
  475. }
  476. if (options.strict && v != am && v != pm) {
  477. // console.debug("dojo.date.locale.parse:
  478. // Could not parse am/pm part.");
  479. return null;
  480. }
  481. // we might not have seen the hours field yet,
  482. // so store the state and apply hour change
  483. // later
  484. amPm = (v == pm) ? 'p' : (v == am) ? 'a' : '';
  485. break;
  486. case 'K' : // hour (1-24)
  487. if (v == 24) {
  488. v = 0;
  489. }
  490. // fallthrough...
  491. case 'h' : // hour (1-12)
  492. case 'H' : // hour (0-23)
  493. case 'k' : // hour (0-11)
  494. // TODO: strict bounds checking, padding
  495. if (v > 23) {
  496. // console.debug("dojo.date.locale.parse:
  497. // Illegal hours value");
  498. return null;
  499. }
  500. // in the 12-hour case, adjusting for am/pm
  501. // requires the 'a' part
  502. // which could come before or after the hour, so
  503. // we will adjust later
  504. result.setHours(v);
  505. break;
  506. case 'm' : // minutes
  507. result.setMinutes(v);
  508. break;
  509. case 's' : // seconds
  510. result.setSeconds(v);
  511. break;
  512. case 'S' : // milliseconds
  513. result.setMilliseconds(v);
  514. // break;
  515. // case 'w':
  516. // TODO var firstDay = 0;
  517. // default:
  518. // TODO: throw?
  519. // console.debug("dojo.date.locale.parse:
  520. // unsupported pattern char=" +
  521. // token.charAt(0));
  522. }
  523. });
  524. var hours = result.getHours();
  525. if (amPm === 'p' && hours < 12) {
  526. result.setHours(hours + 12); // e.g., 3pm -> 15
  527. } else if (amPm === 'a' && hours == 12) {
  528. result.setHours(0); // 12am -> 0
  529. }
  530. // validate parse date fields versus input date fields
  531. if (expected.year && result.getFullYear() != expected.year) {
  532. // console.debug("dojo.date.locale.parse: Parsed year: '" +
  533. // result.getFullYear() + "' did not match input year: '" +
  534. // expected.year + "'.");
  535. return null;
  536. }
  537. if (expected.month && result.getMonth() != expected.month) {
  538. // console.debug("dojo.date.locale.parse: Parsed month: '" +
  539. // result.getMonth() + "' did not match input month: '" +
  540. // expected.month + "'.");
  541. return null;
  542. }
  543. if (expected.date && result.getDate() != expected.date) {
  544. // console.debug("dojo.date.locale.parse: Parsed day of month:
  545. // '" + result.getDate() + "' did not match input day of month:
  546. // '" + expected.date + "'.");
  547. return null;
  548. }
  549. // TODO: implement a getWeekday() method in order to test
  550. // validity of input strings containing 'EEE' or 'EEEE'...
  551. return result; // Date
  552. };
  553. function _processPattern(pattern, applyPattern, applyLiteral, applyAll) {
  554. // summary: Process a pattern with literals in it
  555. // Break up on single quotes, treat every other one as a literal,
  556. // except '' which becomes '
  557. var identity = function(x) {
  558. return x;
  559. };
  560. applyPattern = applyPattern || identity;
  561. applyLiteral = applyLiteral || identity;
  562. applyAll = applyAll || identity;
  563. // split on single quotes (which escape literals in date format
  564. // strings)
  565. // but preserve escaped single quotes (e.g., o''clock)
  566. var chunks = pattern.match(/(''|[^'])+/g);
  567. var literal = false;
  568. dojo.forEach(chunks, function(chunk, i) {
  569. if (!chunk) {
  570. chunks[i] = '';
  571. } else {
  572. chunks[i] = (literal ? applyLiteral : applyPattern)(chunk);
  573. literal = !literal;
  574. }
  575. });
  576. return applyAll(chunks.join(''));
  577. }
  578. function _buildDateTimeRE(tokens, bundle, options, pattern) {
  579. pattern = dojo.regexp.escapeString(pattern);
  580. if (!options.strict) {
  581. pattern = pattern.replace(" a", " ?a");
  582. } // kludge to tolerate no space before am/pm
  583. return pattern.replace(/([a-z])\1*/ig, function(match) {
  584. // Build a simple regexp. Avoid captures, which would ruin the
  585. // tokens list
  586. var s;
  587. var c = match.charAt(0);
  588. var l = match.length;
  589. var p2 = '', p3 = '';
  590. if (options.strict) {
  591. if (l > 1) {
  592. p2 = '0' + '{' + (l - 1) + '}';
  593. }
  594. if (l > 2) {
  595. p3 = '0' + '{' + (l - 2) + '}';
  596. }
  597. } else {
  598. p2 = '0?';
  599. p3 = '0{0,2}';
  600. }
  601. switch (c) {
  602. case 'y' :
  603. s = '\\d{2,4}';
  604. break;
  605. case 'M' :
  606. s = (l > 2) ? '\\S+' : p2 + '[1-9]|1[0-2]';
  607. break;
  608. case 'D' :
  609. s = p2
  610. + '[1-9]|'
  611. + p3
  612. + '[1-9][0-9]|[12][0-9][0-9]|3[0-5][0-9]|36[0-6]';
  613. break;
  614. case 'd' :
  615. s = p2 + '[1-9]|[12]\\d|3[01]';
  616. break;
  617. case 'w' :
  618. s = p2 + '[1-9]|[1-4][0-9]|5[0-3]';
  619. break;
  620. case 'E' :
  621. s = '\\S+';
  622. break;
  623. case 'h' : // hour (1-12)
  624. s = p2 + '[1-9]|1[0-2]';
  625. break;
  626. case 'k' : // hour (0-11)
  627. s = p2 + '\\d|1[01]';
  628. break;
  629. case 'H' : // hour (0-23)
  630. s = p2 + '\\d|1\\d|2[0-3]';
  631. break;
  632. case 'K' : // hour (1-24)
  633. s = p2 + '[1-9]|1\\d|2[0-4]';
  634. break;
  635. case 'm' :
  636. case 's' :
  637. s = '[0-5]\\d';
  638. break;
  639. case 'S' :
  640. s = '\\d{' + l + '}';
  641. break;
  642. case 'a' :
  643. var am = options.am || bundle.am || 'AM';
  644. var pm = options.pm || bundle.pm || 'PM';
  645. if (options.strict) {
  646. s = am + '|' + pm;
  647. } else {
  648. s = am + '|' + pm;
  649. if (am != am.toLowerCase()) {
  650. s += '|' + am.toLowerCase();
  651. }
  652. if (pm != pm.toLowerCase()) {
  653. s += '|' + pm.toLowerCase();
  654. }
  655. }
  656. break;
  657. default :
  658. // case 'v':
  659. // case 'z':
  660. // case 'Z':
  661. s = ".*";
  662. // console.debug("parse of date format, pattern=" +
  663. // pattern);
  664. }
  665. if (tokens) {
  666. tokens.push(match);
  667. }
  668. return "(" + s + ")"; // add capture
  669. }).replace(/[\xa0 ]/g, "[\\s\\xa0]"); // normalize whitespace.
  670. // Need explicit handling of
  671. // \xa0 for IE.
  672. }
  673. })();
  674. (function() {
  675. var _customFormats = [];
  676. dojo.date.locale.addCustomFormats = function(/* String */packageName, /* String */
  677. bundleName) {
  678. // summary:
  679. // Add a reference to a bundle containing localized custom formats
  680. // to be
  681. // used by date/time formatting and parsing routines.
  682. //
  683. // description:
  684. // The user may add custom localized formats where the bundle has
  685. // properties following the
  686. // same naming convention used by dojo for the CLDR data:
  687. // dateFormat-xxxx / timeFormat-xxxx
  688. // The pattern string should match the format used by the CLDR.
  689. // See dojo.date.format for details.
  690. // The resources must be loaded by dojo.requireLocalization() prior
  691. // to use
  692. _customFormats.push({
  693. pkg : packageName,
  694. name : bundleName
  695. });
  696. };
  697. dojo.date.locale._getGregorianBundle = function(/* String */locale) {
  698. var gregorian = {};
  699. dojo.forEach(_customFormats, function(desc) {
  700. var bundle = dojo.i18n.getLocalization(desc.pkg,
  701. desc.name, locale);
  702. gregorian = dojo.mixin(gregorian, bundle);
  703. }, this);
  704. return gregorian; /* Object */
  705. };
  706. })();
  707. dojo.date.locale.addCustomFormats("dojo.cldr", "gregorian");
  708. dojo.date.locale.getNames = function(/* String */item, /* String */type, /* String? */
  709. use, /* String? */locale) {
  710. // summary:
  711. // Used to get localized strings from dojo.cldr for day or month names.
  712. //
  713. // item: 'months' || 'days'
  714. // type: 'wide' || 'narrow' || 'abbr' (e.g. "Monday", "Mon", or "M"
  715. // respectively, in English)
  716. // use: 'standAlone' || 'format' (default)
  717. // locale: override locale used to find the names
  718. var label;
  719. var lookup = dojo.date.locale._getGregorianBundle(locale);
  720. var props = [item, use, type];
  721. if (use == 'standAlone') {
  722. label = lookup[props.join('-')];
  723. }
  724. props[1] = 'format';
  725. // return by copy so changes won't be made accidentally to the in-memory
  726. // model
  727. return (label || lookup[props.join('-')]).concat(); /* Array */
  728. };
  729. dojo.date.locale.isWeekend = function(/* Date? */dateObject, /* String? */
  730. locale) {
  731. // summary:
  732. // Determines if the date falls on a weekend, according to local custom.
  733. var weekend = dojo.cldr.supplemental.getWeekend(locale);
  734. var day = (dateObject || allGetServerTime()).getDay();
  735. if (weekend.end < weekend.start) {
  736. weekend.end += 7;
  737. if (day < weekend.start) {
  738. day += 7;
  739. }
  740. }
  741. return day >= weekend.start && day <= weekend.end; // Boolean
  742. };
  743. // These are used only by format and strftime. Do they need to be public?
  744. // Which module should they go in?
  745. dojo.date.locale._getDayOfYear = function(/* Date */dateObject) {
  746. // summary: gets the day of the year as represented by dateObject
  747. return dojo.date.difference(new Date(dateObject.getFullYear(), 0, 1),
  748. dateObject)
  749. + 1; // Number
  750. };
  751. dojo.date.locale._getWeekOfYear = function(/* Date */dateObject, /* Number */
  752. firstDayOfWeek) {
  753. if (arguments.length == 1) {
  754. firstDayOfWeek = 0;
  755. } // Sunday
  756. var firstDayOfYear = new Date(dateObject.getFullYear(), 0, 1).getDay();
  757. var adj = (firstDayOfYear - firstDayOfWeek + 7) % 7;
  758. var week = Math
  759. .floor((dojo.date.locale._getDayOfYear(dateObject) + adj - 1)
  760. / 7);
  761. // if year starts on the specified day, start counting weeks at 1
  762. if (firstDayOfYear == firstDayOfWeek) {
  763. week++;
  764. }
  765. return week; // Number
  766. };
  767. }