3
Copyright 2012 Yahoo! Inc. All rights reserved.
4
Licensed under the BSD License.
5
http://yuilibrary.com/license/
7
YUI.add('datatype-date-format', function(Y) {
10
* The DataType Utility provides type-conversion and string-formatting
11
* convenience methods for various JavaScript object types.
21
* @submodule datatype-date
25
* Format date submodule implements strftime formatters for javascript based on the
26
* Open Group specification defined at
27
* http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html
28
* This implementation does not include modified conversion specifiers (i.e., Ex and Ox)
31
* @submodule datatype-date-format
35
* DataType.Date provides a set of utility functions to operate against Date objects.
37
* @class DataType.Date
42
* Pad a number with leading spaces, zeroes or something else
44
* @param x {Number} The number to be padded
45
* @param pad {String} The character to pad the number with
46
* @param r {Number} (optional) The base of the pad, eg, 10 implies to two digits, 100 implies to 3 digits.
49
var xPad=function (x, pad, r)
51
if(typeof r === "undefined")
56
for( ; parseInt(x, 10)<r && r>1; r/=10) {
64
a: function (d, l) { return l.a[d.getDay()]; },
65
A: function (d, l) { return l.A[d.getDay()]; },
66
b: function (d, l) { return l.b[d.getMonth()]; },
67
B: function (d, l) { return l.B[d.getMonth()]; },
68
C: function (d) { return xPad(parseInt(d.getFullYear()/100, 10), 0); },
71
g: function (d) { return xPad(parseInt(Dt.formats.G(d)%100, 10), 0); },
73
var y = d.getFullYear();
74
var V = parseInt(Dt.formats.V(d), 10);
75
var W = parseInt(Dt.formats.W(d), 10);
79
} else if(W===0 && V>=52) {
86
I: function (d) { var I=d.getHours()%12; return xPad(I===0?12:I, 0); },
88
var gmd_1 = new Date("" + d.getFullYear() + "/1/1 GMT");
89
var gmdate = new Date("" + d.getFullYear() + "/" + (d.getMonth()+1) + "/" + d.getDate() + " GMT");
90
var ms = gmdate - gmd_1;
91
var doy = parseInt(ms/60000/60/24, 10)+1;
92
return xPad(doy, 0, 100);
95
l: function (d) { var I=d.getHours()%12; return xPad(I===0?12:I, " "); },
96
m: function (d) { return xPad(d.getMonth()+1, 0); },
97
M: ["getMinutes", "0"],
98
p: function (d, l) { return l.p[d.getHours() >= 12 ? 1 : 0 ]; },
99
P: function (d, l) { return l.P[d.getHours() >= 12 ? 1 : 0 ]; },
100
s: function (d, l) { return parseInt(d.getTime()/1000, 10); },
101
S: ["getSeconds", "0"],
102
u: function (d) { var dow = d.getDay(); return dow===0?7:dow; },
104
var doy = parseInt(Dt.formats.j(d), 10);
105
var rdow = 6-d.getDay();
106
var woy = parseInt((doy+rdow)/7, 10);
110
var woy = parseInt(Dt.formats.W(d), 10);
111
var dow1_1 = (new Date("" + d.getFullYear() + "/1/1")).getDay();
112
// First week is 01 and not 00 as in the case of %U and %W,
113
// so we add 1 to the final result except if day 1 of the year
114
// is a Monday (then %W returns 01).
115
// We also need to subtract 1 if the day 1 of the year is
116
// Friday-Sunday, so the resulting equation becomes:
117
var idow = woy + (dow1_1 > 4 || dow1_1 <= 1 ? 0 : 1);
118
if(idow === 53 && (new Date("" + d.getFullYear() + "/12/31")).getDay() < 4)
124
idow = Dt.formats.V(new Date("" + (d.getFullYear()-1) + "/12/31"));
127
return xPad(idow, 0);
131
var doy = parseInt(Dt.formats.j(d), 10);
132
var rdow = 7-Dt.formats.u(d);
133
var woy = parseInt((doy+rdow)/7, 10);
134
return xPad(woy, 0, 10);
136
y: function (d) { return xPad(d.getFullYear()%100, 0); },
139
var o = d.getTimezoneOffset();
140
var H = xPad(parseInt(Math.abs(o/60), 10), 0);
141
var M = xPad(Math.abs(o%60), 0);
142
return (o>0?"-":"+") + H + M;
145
var tz = d.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/, "$2").replace(/[a-z ]/g, "");
147
tz = Dt.formats.z(d);
151
"%": function (d) { return "%"; }
166
//"+": "%a %b %e %T %Z %Y"
170
* Takes a native JavaScript Date and formats it as a string for display to user.
174
* @param oDate {Date} Date.
175
* @param oConfig {Object} (Optional) Object literal of configuration values:
177
* <dt>format {HTML} (Optional)</dt>
180
* Any strftime string is supported, such as "%I:%M:%S %p". strftime has several format specifiers defined by the Open group at
181
* <a href="http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html">http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html</a>
182
* PHP added a few of its own, defined at <a href="http://www.php.net/strftime">http://www.php.net/strftime</a>
185
* This javascript implementation supports all the PHP specifiers and a few more. The full list is below.
188
* If not specified, it defaults to the ISO 8601 standard date format: %Y-%m-%d.
189
* This may be overridden by the deprecated Y.config.dateFormat property.
192
* <dt>%a</dt> <dd>abbreviated weekday name according to the current locale</dd>
193
* <dt>%A</dt> <dd>full weekday name according to the current locale</dd>
194
* <dt>%b</dt> <dd>abbreviated month name according to the current locale</dd>
195
* <dt>%B</dt> <dd>full month name according to the current locale</dd>
196
* <dt>%c</dt> <dd>preferred date and time representation for the current locale</dd>
197
* <dt>%C</dt> <dd>century number (the year divided by 100 and truncated to an integer, range 00 to 99)</dd>
198
* <dt>%d</dt> <dd>day of the month as a decimal number (range 01 to 31)</dd>
199
* <dt>%D</dt> <dd>same as %m/%d/%y</dd>
200
* <dt>%e</dt> <dd>day of the month as a decimal number, a single digit is preceded by a space (range " 1" to "31")</dd>
201
* <dt>%F</dt> <dd>same as %Y-%m-%d (ISO 8601 date format)</dd>
202
* <dt>%g</dt> <dd>like %G, but without the century</dd>
203
* <dt>%G</dt> <dd>The 4-digit year corresponding to the ISO week number</dd>
204
* <dt>%h</dt> <dd>same as %b</dd>
205
* <dt>%H</dt> <dd>hour as a decimal number using a 24-hour clock (range 00 to 23)</dd>
206
* <dt>%I</dt> <dd>hour as a decimal number using a 12-hour clock (range 01 to 12)</dd>
207
* <dt>%j</dt> <dd>day of the year as a decimal number (range 001 to 366)</dd>
208
* <dt>%k</dt> <dd>hour as a decimal number using a 24-hour clock (range 0 to 23); single digits are preceded by a blank. (See also %H.)</dd>
209
* <dt>%l</dt> <dd>hour as a decimal number using a 12-hour clock (range 1 to 12); single digits are preceded by a blank. (See also %I.) </dd>
210
* <dt>%m</dt> <dd>month as a decimal number (range 01 to 12)</dd>
211
* <dt>%M</dt> <dd>minute as a decimal number</dd>
212
* <dt>%n</dt> <dd>newline character</dd>
213
* <dt>%p</dt> <dd>either "AM" or "PM" according to the given time value, or the corresponding strings for the current locale</dd>
214
* <dt>%P</dt> <dd>like %p, but lower case</dd>
215
* <dt>%r</dt> <dd>time in a.m. and p.m. notation equal to %I:%M:%S %p</dd>
216
* <dt>%R</dt> <dd>time in 24 hour notation equal to %H:%M</dd>
217
* <dt>%s</dt> <dd>number of seconds since the Epoch, ie, since 1970-01-01 00:00:00 UTC</dd>
218
* <dt>%S</dt> <dd>second as a decimal number</dd>
219
* <dt>%t</dt> <dd>tab character</dd>
220
* <dt>%T</dt> <dd>current time, equal to %H:%M:%S</dd>
221
* <dt>%u</dt> <dd>weekday as a decimal number [1,7], with 1 representing Monday</dd>
222
* <dt>%U</dt> <dd>week number of the current year as a decimal number, starting with the
223
* first Sunday as the first day of the first week</dd>
224
* <dt>%V</dt> <dd>The ISO 8601:1988 week number of the current year as a decimal number,
225
* range 01 to 53, where week 1 is the first week that has at least 4 days
226
* in the current year, and with Monday as the first day of the week.</dd>
227
* <dt>%w</dt> <dd>day of the week as a decimal, Sunday being 0</dd>
228
* <dt>%W</dt> <dd>week number of the current year as a decimal number, starting with the
229
* first Monday as the first day of the first week</dd>
230
* <dt>%x</dt> <dd>preferred date representation for the current locale without the time</dd>
231
* <dt>%X</dt> <dd>preferred time representation for the current locale without the date</dd>
232
* <dt>%y</dt> <dd>year as a decimal number without a century (range 00 to 99)</dd>
233
* <dt>%Y</dt> <dd>year as a decimal number including the century</dd>
234
* <dt>%z</dt> <dd>numerical time zone representation</dd>
235
* <dt>%Z</dt> <dd>time zone name or abbreviation</dd>
236
* <dt>%%</dt> <dd>a literal "%" character</dd>
239
* <dt>locale {String} (Deprecated, optional)</dt>
241
* <b>Deprecated - use Y.config.lang instead, which provides access to a much larger set of built-in languages.</b>
242
* The locale to use when displaying days of week, months of the year, and other locale specific
243
* strings. If not specified, this defaults to "en" (though this may be overridden by the deprecated Y.config.locale).
244
* The following locales are built in:
249
* <dd>US English</dd>
251
* <dd>British English</dd>
253
* <dd>Australian English (identical to British English)</dd>
255
* More locales may be added by subclassing of the deprecated Y.DataType.Date.Locale["en"].
256
* See Y.DataType.Date.Locale for more information.
259
* @return {HTML} Formatted date for display.
261
format : function (oDate, oConfig) {
262
oConfig = oConfig || {};
264
if(!Y.Lang.isDate(oDate)) {
265
Y.log("format called without a date", "WARN", "datatype-date");
266
return Y.Lang.isValue(oDate) ? oDate : "";
269
var format, resources, compatMode, sLocale, LOCALE;
271
// Y.config.dateFormat is deprecated - remove from YUI 3.2
272
format = oConfig.format || Y.config.dateFormat || "%Y-%m-%d";
273
// compatMode supports deprecated features - remove from YUI 3.2
274
compatMode = Y.Lang.isUndefined(Y.config.lang) && (Y.Lang.isValue(oConfig.locale) || Y.Lang.isValue(Y.config.locale));
276
sLocale = oConfig.locale || Y.config.locale;
277
LOCALE = Y.DataType.Date.Locale;
278
sLocale = sLocale.replace(/_/g, "-");
280
// Make sure we have a definition for the requested locale, or default to en.
281
if(!LOCALE[sLocale]) {
282
Y.log("selected locale " + sLocale + " not found, trying alternatives", "WARN", "datatype-date");
283
var tmpLocale = sLocale.replace(/-[a-zA-Z]+$/, "");
284
if(tmpLocale in LOCALE) {
286
} else if(Y.config.locale in LOCALE) {
287
sLocale = Y.config.locale;
291
Y.log("falling back to " + sLocale, "INFO", "datatype-date");
294
resources = LOCALE[sLocale];
296
resources = Y.Intl.get('datatype-date-format');
299
var replace_aggs = function (m0, m1) {
300
if (compatMode && m1 === "r") {
301
return resources[m1];
303
var f = Dt.aggregates[m1];
304
return (f === "locale" ? resources[m1] : f);
307
var replace_formats = function (m0, m1) {
308
var f = Dt.formats[m1];
309
switch(Y.Lang.type(f)) {
310
case "string": // string => built in date function
312
case "function": // function => our own function
313
return f.call(oDate, oDate, resources);
314
case "array": // built in function with padding
315
if(Y.Lang.type(f[0]) === "string") {
316
return xPad(oDate[f[0]](), f[1]);
317
} // no break; (fall through to default:)
319
// Y.config.dateFormat is deprecated - remove from YUI 3.2
320
Y.log("unrecognised replacement type, please file a bug (format: " + oConfig.format || Y.config.dateFormat + ")", "WARN", "datatype-date");
325
// First replace aggregates (run in a loop because an agg may be made up of other aggs)
326
while(format.match(/%[cDFhnrRtTxX]/)) {
327
format = format.replace(/%([cDFhnrRtTxX])/g, replace_aggs);
330
// Now replace formats (do not run in a loop otherwise %%a will be replace with the value of %a)
331
var str = format.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g, replace_formats);
333
replace_aggs = replace_formats = undefined;
339
Y.mix(Y.namespace("DataType.Date"), Dt);
345
* The Date.Locale class is a container for all localised date strings
346
* used by Y.DataType.Date. It is used internally, but may be extended
347
* to provide new date localisations.
349
* To create your own Locale, follow these steps:
351
* <li>Find an existing locale that matches closely with your needs</li>
352
* <li>Use this as your base class. Use Y.DataType.Date.Locale["en"] if nothing
354
* <li>Create your own class as an extension of the base class using
355
* Y.merge, and add your own localisations where needed.</li>
357
* See the Y.DataType.Date.Locale["en-US"] and Y.DataType.Date.Locale["en-GB"]
358
* classes which extend Y.DataType.Date.Locale["en"].
360
* For example, to implement locales for French french and Canadian french,
361
* we would do the following:
363
* <li>For French french, we have no existing similar locale, so use
364
* Y.DataType.Date.Locale["en"] as the base, and extend it:
366
* Y.DataType.Date.Locale["fr"] = Y.merge(Y.DataType.Date.Locale["en"], {
367
* a: ["dim", "lun", "mar", "mer", "jeu", "ven", "sam"],
368
* A: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"],
369
* b: ["jan", "fév", "mar", "avr", "mai", "jun", "jui", "aoû", "sep", "oct", "nov", "déc"],
370
* B: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"],
371
* c: "%a %d %b %Y %T %Z",
379
* <li>For Canadian french, we start with French french and change the meaning of \%x:
381
* Y.DataType.Date.Locale["fr-CA"] = Y.merge(Y.DataType.Date.Locale["fr"], {
388
* With that, you can use your new locales:
390
* var d = new Date("2008/04/22");
391
* Y.DataType.Date.format(d, { format: "%A, %d %B == %x", locale: "fr" });
395
* mardi, 22 avril == 22.04.2008
399
* Y.DataType.Date.format(d, {format: "%A, %d %B == %x", locale: "fr-CA" });
403
* mardi, 22 avril == 2008-04-22
406
* @class DataType.Date.Locale
408
* @deprecated - use Y.config.lang to request one of many built-in languages instead.
411
a: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
412
A: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
413
b: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
414
B: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
415
c: "%a %d %b %Y %T %Z",
423
Y.namespace("DataType.Date.Locale");
425
Y.DataType.Date.Locale["en"] = YDateEn;
427
Y.DataType.Date.Locale["en-US"] = Y.merge(YDateEn, {
428
c: "%a %d %b %Y %I:%M:%S %p %Z",
433
Y.DataType.Date.Locale["en-GB"] = Y.merge(YDateEn, {
436
Y.DataType.Date.Locale["en-AU"] = Y.merge(YDateEn);
441
}, '3.5.1' ,{lang:['ar','ar-JO','ca','ca-ES','da','da-DK','de','de-AT','de-DE','el','el-GR','en','en-AU','en-CA','en-GB','en-IE','en-IN','en-JO','en-MY','en-NZ','en-PH','en-SG','en-US','es','es-AR','es-BO','es-CL','es-CO','es-EC','es-ES','es-MX','es-PE','es-PY','es-US','es-UY','es-VE','fi','fi-FI','fr','fr-BE','fr-CA','fr-FR','hi','hi-IN','id','id-ID','it','it-IT','ja','ja-JP','ko','ko-KR','ms','ms-MY','nb','nb-NO','nl','nl-BE','nl-NL','pl','pl-PL','pt','pt-BR','ro','ro-RO','ru','ru-RU','sv','sv-SE','th','th-TH','tr','tr-TR','vi','vi-VN','zh-Hans','zh-Hans-CN','zh-Hant','zh-Hant-HK','zh-Hant-TW']});