~clinton-collins/familyproject/trunk

« back to all changes in this revision

Viewing changes to ZendFramework/externals/dojo/dojo/date/locale.js

  • Committer: Clinton Collins
  • Date: 2009-06-26 19:54:58 UTC
  • Revision ID: clinton.collins@gmail.com-20090626195458-5ebba0qcvo15xlpy
Initial Import

Show diffs side-by-side

added added

removed removed

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