Date_wev8.js
33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
/*
* Ext JS Library 2.0.2
* Copyright(c) 2006-2008, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
/**
* @class Date
*
* The date parsing and format syntax is a subset of
* <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
* supported will provide results equivalent to their PHP versions.
*
* The following is a list of all currently supported formats:
*<pre>
Format Description Example returned values
------ ----------------------------------------------------------------------- -----------------------
d Day of the month, 2 digits with leading zeros 01 to 31
D A short textual representation of the day of the week Mon to Sun
j Day of the month without leading zeros 1 to 31
l A full textual representation of the day of the week Sunday to Saturday
N ISO-8601 numeric representation of the day of the week 1 (for Monday) through 7 (for Sunday)
S English ordinal suffix for the day of the month, 2 characters st, nd, rd or th. Works well with j
w Numeric representation of the day of the week 0 (for Sunday) to 6 (for Saturday)
z The day of the year (starting from 0) 0 to 364 (365 in leap years)
W ISO-8601 week number of year, weeks starting on Monday 01 to 53
F A full textual representation of a month, such as January or March January to December
m Numeric representation of a month, with leading zeros 01 to 12
M A short textual representation of a month Jan to Dec
n Numeric representation of a month, without leading zeros 1 to 12
t Number of days in the given month 28 to 31
L Whether it's a leap year 1 if it is a leap year, 0 otherwise.
o ISO-8601 year number (identical to (Y), but if the ISO week number (W) Examples: 1998 or 2004
belongs to the previous or next year, that year is used instead)
Y A full numeric representation of a year, 4 digits Examples: 1999 or 2003
y A two digit representation of a year Examples: 99 or 03
a Lowercase Ante meridiem and Post meridiem am or pm
A Uppercase Ante meridiem and Post meridiem AM or PM
g 12-hour format of an hour without leading zeros 1 to 12
G 24-hour format of an hour without leading zeros 0 to 23
h 12-hour format of an hour with leading zeros 01 to 12
H 24-hour format of an hour with leading zeros 00 to 23
i Minutes, with leading zeros 00 to 59
s Seconds, with leading zeros 00 to 59
u Milliseconds, with leading zeros 001 to 999
O Difference to Greenwich time (GMT) in hours and minutes Example: +1030
P Difference to Greenwich time (GMT) with colon between hours and minutes Example: -08:00
T Timezone abbreviation of the machine running the code Examples: EST, MDT, PDT ...
Z Timezone offset in seconds (negative if west of UTC, positive if east) -43200 to 50400
c ISO 8601 date 2007-04-17T15:19:21+08:00
U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) 1193432466 or -2138434463
</pre>
*
* Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
* <pre><code>
// Sample date:
// 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
document.write(dt.format('Y-m-d')); // 2007-01-10
document.write(dt.format('F j, Y, g:i a')); // January 10, 2007, 3:05 pm
document.write(dt.format('l, \\t\\he jS of F Y h:i:s A')); // Wednesday, the 10th of January 2007 03:05:01 PM
</code></pre>
*
* Here are some standard date/time patterns that you might find helpful. They
* are not part of the source of Date.js, but to use them you can simply copy this
* block of code into any script that is included after Date_wev8.js and they will also become
* globally available on the Date object. Feel free to add or remove patterns as needed in your code.
* <pre><code>
Date.patterns = {
ISO8601Long:"Y-m-d H:i:s",
ISO8601Short:"Y-m-d",
ShortDate: "n/j/Y",
LongDate: "l, F d, Y",
FullDateTime: "l, F d, Y g:i:s A",
MonthDay: "F d",
ShortTime: "g:i A",
LongTime: "g:i:s A",
SortableDateTime: "Y-m-d\\TH:i:s",
UniversalSortableDateTime: "Y-m-d H:i:sO",
YearMonth: "F, Y"
};
</code></pre>
*
* Example usage:
* <pre><code>
var dt = new Date();
document.write(dt.format(Date.patterns.ShortDate));
</code></pre>
*/
/*
* Most of the date-formatting functions below are the excellent work of Baron Schwartz.
* They generate precompiled functions from date formats instead of parsing and
* processing the pattern every time you format a date. These functions are available
* on every Date object (any javascript function).
*
* The original article and download are here:
* http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
*
*/
// private
Date.parseFunctions = {count:0};
// private
Date.parseRegexes = [];
// private
Date.formatFunctions = {count:0};
// private
Date.prototype.dateFormat = function(format) {
if (Date.formatFunctions[format] == null) {
Date.createNewFormat(format);
}
var func = Date.formatFunctions[format];
return this[func]();
};
/**
* Formats a date given the supplied format string.
* @param {String} format The format string.
* @return {String} The formatted date.
* @method
*/
Date.prototype.format = Date.prototype.dateFormat;
// private
Date.createNewFormat = function(format) {
var funcName = "format" + Date.formatFunctions.count++;
Date.formatFunctions[format] = funcName;
var code = "Date.prototype." + funcName + " = function(){return ";
var special = false;
var ch = '';
for (var i = 0; i < format.length; ++i) {
ch = format.charAt(i);
if (!special && ch == "\\") {
special = true;
}
else if (special) {
special = false;
code += "'" + String.escape(ch) + "' + ";
}
else {
code += Date.getFormatCode(ch);
}
}
eval(code.substring(0, code.length - 3) + ";}");
};
// private
Date.getFormatCode = function(character) {
switch (character) {
case "d":
return "String.leftPad(this.getDate(), 2, '0') + ";
case "D":
return "Date.getShortDayName(this.getDay()) + "; // get L10n short day name
case "j":
return "this.getDate() + ";
case "l":
return "Date.dayNames[this.getDay()] + ";
case "N":
return "(this.getDay() ? this.getDay() : 7) + ";
case "S":
return "this.getSuffix() + ";
case "w":
return "this.getDay() + ";
case "z":
return "this.getDayOfYear() + ";
case "W":
return "String.leftPad(this.getWeekOfYear(), 2, '0') + ";
case "F":
return "Date.monthNames[this.getMonth()] + ";
case "m":
return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
case "M":
return "Date.getShortMonthName(this.getMonth()) + "; // get L10n short month name
case "n":
return "(this.getMonth() + 1) + ";
case "t":
return "this.getDaysInMonth() + ";
case "L":
return "(this.isLeapYear() ? 1 : 0) + ";
case "o":
return "(this.getFullYear() + (this.getWeekOfYear() == 1 && this.getMonth() > 0 ? +1 : (this.getWeekOfYear() >= 52 && this.getMonth() < 11 ? -1 : 0))) + ";
case "Y":
return "this.getFullYear() + ";
case "y":
return "('' + this.getFullYear()).substring(2, 4) + ";
case "a":
return "(this.getHours() < 12 ? 'am' : 'pm') + ";
case "A":
return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
case "g":
return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
case "G":
return "this.getHours() + ";
case "h":
return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
case "H":
return "String.leftPad(this.getHours(), 2, '0') + ";
case "i":
return "String.leftPad(this.getMinutes(), 2, '0') + ";
case "s":
return "String.leftPad(this.getSeconds(), 2, '0') + ";
case "u":
return "String.leftPad(this.getMilliseconds(), 3, '0') + ";
case "O":
return "this.getGMTOffset() + ";
case "P":
return "this.getGMTOffset(true) + ";
case "T":
return "this.getTimezone() + ";
case "Z":
return "(this.getTimezoneOffset() * -60) + ";
case "c":
for (var df = Date.getFormatCode, c = "Y-m-dTH:i:sP", code = "", i = 0, l = c.length; i < l; ++i) {
var e = c.charAt(i);
code += e == "T" ? "'T' + " : df(e); // treat T as a literal
}
return code;
case "U":
return "Math.round(this.getTime() / 1000) + ";
default:
return "'" + String.escape(character) + "' + ";
}
};
/**
* Parses the passed string using the specified format. Note that this function expects dates in normal calendar
* format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
* the date format that is not specified will default to the current date value for that part. Time parts can also
* be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
* string or the parse operation will fail.
* Example Usage:
<pre><code>
//dt = Fri May 25 2007 (current date)
var dt = new Date();
//dt = Thu May 25 2006 (today's month/day in 2006)
dt = Date.parseDate("2006", "Y");
//dt = Sun Jan 15 2006 (all date parts specified)
dt = Date.parseDate("2006-01-15", "Y-m-d");
//dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
dt = Date.parseDate("2006-01-15 3:20:01 PM", "Y-m-d h:i:s A" );
</code></pre>
* @param {String} input The unparsed date as a string.
* @param {String} format The format the date is in.
* @return {Date} The parsed date.
* @static
*/
Date.parseDate = function(input, format) {
if (Date.parseFunctions[format] == null) {
Date.createParser(format);
}
var func = Date.parseFunctions[format];
return Date[func](input);
};
// private
Date.createParser = function(format) {
var funcName = "parse" + Date.parseFunctions.count++;
var regexNum = Date.parseRegexes.length;
var currentGroup = 1;
Date.parseFunctions[format] = funcName;
var code = "Date." + funcName + " = function(input){\n"
+ "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, ms = -1, o, z, u, v;\n"
+ "input = String(input);var d = new Date();\n"
+ "y = d.getFullYear();\n"
+ "m = d.getMonth();\n"
+ "d = d.getDate();\n"
+ "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
+ "if (results && results.length > 0) {";
var regex = "";
var special = false;
var ch = '';
for (var i = 0; i < format.length; ++i) {
ch = format.charAt(i);
if (!special && ch == "\\") {
special = true;
}
else if (special) {
special = false;
regex += String.escape(ch);
}
else {
var obj = Date.formatCodeToRegex(ch, currentGroup);
currentGroup += obj.g;
regex += obj.s;
if (obj.g && obj.c) {
code += obj.c;
}
}
}
code += "if (u)\n"
+ "{v = new Date(u * 1000);}" // give top priority to UNIX time
+ "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0 && ms >= 0)\n"
+ "{v = new Date(y, m, d, h, i, s, ms);}\n"
+ "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
+ "{v = new Date(y, m, d, h, i, s);}\n"
+ "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
+ "{v = new Date(y, m, d, h, i);}\n"
+ "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
+ "{v = new Date(y, m, d, h);}\n"
+ "else if (y >= 0 && m >= 0 && d > 0)\n"
+ "{v = new Date(y, m, d);}\n"
+ "else if (y >= 0 && m >= 0)\n"
+ "{v = new Date(y, m);}\n"
+ "else if (y >= 0)\n"
+ "{v = new Date(y);}\n"
+ "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
+ " (z ? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
+ " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
+ ";}";
Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$", "i");
eval(code);
};
// private
Date.formatCodeToRegex = function(character, currentGroup) {
/*
* currentGroup = position in regex result array
* g = calculation group (0 or 1. only group 1 contributes to date calculations.)
* c = calculation method (required for group 1. null for group 0.)
* s = regex string
*/
switch (character) {
case "d":
return {g:1,
c:"d = parseInt(results[" + currentGroup + "], 10);\n",
s:"(\\d{2})"}; // day of month with leading zeroes (01 - 31)
case "D":
for (var a = [], i = 0; i < 7; a.push(Date.getShortDayName(i)), ++i); // get L10n short day names
return {g:0,
c:null,
s:"(?:" + a.join("|") +")"};
case "j":
return {g:1,
c:"d = parseInt(results[" + currentGroup + "], 10);\n",
s:"(\\d{1,2})"}; // day of month without leading zeroes (1 - 31)
case "l":
return {g:0,
c:null,
s:"(?:" + Date.dayNames.join("|") + ")"};
case "N":
return {g:0,
c:null,
s:"[1-7]"}; // ISO-8601 day number (1 (monday) - 7 (sunday))
case "S":
return {g:0,
c:null,
s:"(?:st|nd|rd|th)"};
case "w":
return {g:0,
c:null,
s:"[0-6]"}; // javascript day number (0 (sunday) - 6 (saturday))
case "z":
return {g:0,
c:null,
s:"(?:\\d{1,3}"}; // day of the year (0 - 364 (365 in leap years))
case "W":
return {g:0,
c:null,
s:"(?:\\d{2})"}; // ISO-8601 week number (with leading zero)
case "F":
return {g:1,
c:"m = parseInt(Date.getMonthNumber(results[" + currentGroup + "]), 10);\n", // get L10n month number
s:"(" + Date.monthNames.join("|") + ")"};
case "m":
return {g:1,
c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
s:"(\\d{2})"}; // month number with leading zeros (01 - 12)
case "M":
for (var a = [], i = 0; i < 12; a.push(Date.getShortMonthName(i)), ++i); // get L10n short month names
return {g:1,
c:"m = parseInt(Date.getMonthNumber(results[" + currentGroup + "]), 10);\n", // get L10n month number
s:"(" + a.join("|") + ")"};
case "n":
return {g:1,
c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
s:"(\\d{1,2})"}; // month number without leading zeros (1 - 12)
case "t":
return {g:0,
c:null,
s:"(?:\\d{2})"}; // no. of days in the month (28 - 31)
case "L":
return {g:0,
c:null,
s:"(?:1|0)"};
case "o":
case "Y":
return {g:1,
c:"y = parseInt(results[" + currentGroup + "], 10);\n",
s:"(\\d{4})"}; // 4-digit year
case "y":
return {g:1,
c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
+ "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
s:"(\\d{1,2})"}; // 2-digit year
case "a":
return {g:1,
c:"if (results[" + currentGroup + "] == 'am') {\n"
+ "if (h == 12) { h = 0; }\n"
+ "} else { if (h < 12) { h += 12; }}",
s:"(am|pm)"};
case "A":
return {g:1,
c:"if (results[" + currentGroup + "] == 'AM') {\n"
+ "if (h == 12) { h = 0; }\n"
+ "} else { if (h < 12) { h += 12; }}",
s:"(AM|PM)"};
case "g":
case "G":
return {g:1,
c:"h = parseInt(results[" + currentGroup + "], 10);\n",
s:"(\\d{1,2})"}; // 24-hr format of an hour without leading zeroes (0 - 23)
case "h":
case "H":
return {g:1,
c:"h = parseInt(results[" + currentGroup + "], 10);\n",
s:"(\\d{2})"}; // 24-hr format of an hour with leading zeroes (00 - 23)
case "i":
return {g:1,
c:"i = parseInt(results[" + currentGroup + "], 10);\n",
s:"(\\d{2})"}; // minutes with leading zeros (00 - 59)
case "s":
return {g:1,
c:"s = parseInt(results[" + currentGroup + "], 10);\n",
s:"(\\d{2})"}; // seconds with leading zeros (00 - 59)
case "u":
return {g:1,
c:"ms = parseInt(results[" + currentGroup + "], 10);\n",
s:"(\\d{3})"}; // milliseconds with leading zeros (000 - 999)
case "O":
return {g:1,
c:[
"o = results[", currentGroup, "];\n",
"var sn = o.substring(0,1);\n", // get + / - sign
"var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also, just in case)
"var mn = o.substring(3,5) % 60;\n", // get minutes
"o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
" (sn + String.leftPad(hr, 2, '0') + String.leftPad(mn, 2, '0')) : null;\n"
].join(""),
s: "([+\-]\\d{4})"}; // GMT offset in hrs and mins
case "P":
return {g:1,
c:[
"o = results[", currentGroup, "];\n",
"var sn = o.substring(0,1);\n", // get + / - sign
"var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n", // get hours (performs minutes-to-hour conversion also, just in case)
"var mn = o.substring(4,6) % 60;\n", // get minutes
"o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
" (sn + String.leftPad(hr, 2, '0') + String.leftPad(mn, 2, '0')) : null;\n"
].join(""),
s: "([+\-]\\d{2}:\\d{2})"}; // GMT offset in hrs and mins (with colon separator)
case "T":
return {g:0,
c:null,
s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
case "Z":
return {g:1,
c:"z = results[" + currentGroup + "] * 1;\n" // -43200 <= UTC offset <= 50400
+ "z = (-43200 <= z && z <= 50400)? z : null;\n",
s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
case "c":
var df = Date.formatCodeToRegex, calc = [];
var arr = [df("Y", 1), df("m", 2), df("d", 3), df("h", 4), df("i", 5), df("s", 6), df("P", 7)];
for (var i = 0, l = arr.length; i < l; ++i) {
calc.push(arr[i].c);
}
return {g:1,
c:calc.join(""),
s:arr[0].s + "-" + arr[1].s + "-" + arr[2].s + "T" + arr[3].s + ":" + arr[4].s + ":" + arr[5].s + arr[6].s};
case "U":
return {g:1,
c:"u = parseInt(results[" + currentGroup + "], 10);\n",
s:"(-?\\d+)"}; // leading minus sign indicates seconds before UNIX epoch
default:
return {g:0,
c:null,
s:Ext.escapeRe(character)};
}
};
/**
* Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
*
* Note: The date string returned by the javascript Date object's toString() method varies
* between browsers (e.g. FF vs IE) and system region settings (e.g. IE in Asia vs IE in America).
* For a given date string e.g. "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)",
* getTimezone() first tries to get the timezone abbreviation from between a pair of parentheses
* (which may or may not be present), failing which it proceeds to get the timezone abbreviation
* from the GMT offset portion of the date string.
* @return {String} The abbreviated timezone name (e.g. 'CST', 'PDT', 'EDT', 'MPST' ...).
*/
Date.prototype.getTimezone = function() {
// the following list shows the differences between date strings from different browsers on a WinXP SP2 machine from an Asian locale:
//
// Opera : "Thu, 25 Oct 2007 22:53:45 GMT+0800" -- shortest (weirdest) date string of the lot
// Safari : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone (same as FF)
// FF : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone
// IE : "Thu Oct 25 22:54:35 UTC+0800 2007" -- (Asian system setting) look for 3-4 letter timezone abbrev
// IE : "Thu Oct 25 17:06:37 PDT 2007" -- (American system setting) look for 3-4 letter timezone abbrev
//
// this crazy regex attempts to guess the correct timezone abbreviation despite these differences.
// step 1: (?:\((.*)\) -- find timezone in parentheses
// step 2: ([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?) -- if nothing was found in step 1, find timezone from timezone offset portion of date string
// step 3: remove all non uppercase characters found in step 1 and 2
return this.toString().replace(/^.* (?:\((.*)\)|([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?)$/, "$1$2").replace(/[^A-Z]/g, "");
};
/**
* Get the offset from GMT of the current date (equivalent to the format specifier 'O').
* @param {Boolean} colon true to separate the hours and minutes with a colon (defaults to false).
* @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600').
*/
Date.prototype.getGMTOffset = function(colon) {
return (this.getTimezoneOffset() > 0 ? "-" : "+")
+ String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
+ (colon ? ":" : "")
+ String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
};
/**
* Get the numeric day number of the year, adjusted for leap year.
* @return {Number} 0 to 364 (365 in leap years).
*/
Date.prototype.getDayOfYear = function() {
var num = 0;
Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
for (var i = 0; i < this.getMonth(); ++i) {
num += Date.daysInMonth[i];
}
return num + this.getDate() - 1;
};
/**
* Get the numeric ISO-8601 week number of the year.
* (equivalent to the format specifier 'W', but without a leading zero).
* @return {Number} 1 to 53
*/
Date.prototype.getWeekOfYear = function() {
// adapted from http://www.merlyn.demon.co.uk/weekcalc.htm
var ms1d = 864e5; // milliseconds in a day
var ms7d = 7 * ms1d; // milliseconds in a week
var DC3 = Date.UTC(this.getFullYear(), this.getMonth(), this.getDate() + 3) / ms1d; // an Absolute Day Number
var AWN = Math.floor(DC3 / 7); // an Absolute Week Number
var Wyr = new Date(AWN * ms7d).getUTCFullYear();
return AWN - Math.floor(Date.UTC(Wyr, 0, 7) / ms7d) + 1;
};
/**
* Whether or not the current date is in a leap year.
* @return {Boolean} True if the current date is in a leap year, else false.
*/
Date.prototype.isLeapYear = function() {
var year = this.getFullYear();
return !!((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
};
/**
* Get the first day of the current month, adjusted for leap year. The returned value
* is the numeric day index within the week (0-6) which can be used in conjunction with
* the {@link #monthNames} array to retrieve the textual day name.
* Example:
*<pre><code>
var dt = new Date('1/10/2007');
document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
</code></pre>
* @return {Number} The day number (0-6).
*/
Date.prototype.getFirstDayOfMonth = function() {
var day = (this.getDay() - (this.getDate() - 1)) % 7;
return (day < 0) ? (day + 7) : day;
};
/**
* Get the last day of the current month, adjusted for leap year. The returned value
* is the numeric day index within the week (0-6) which can be used in conjunction with
* the {@link #monthNames} array to retrieve the textual day name.
* Example:
*<pre><code>
var dt = new Date('1/10/2007');
document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
</code></pre>
* @return {Number} The day number (0-6).
*/
Date.prototype.getLastDayOfMonth = function() {
var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
return (day < 0) ? (day + 7) : day;
};
/**
* Get the date of the first day of the month in which this date resides.
* @return {Date}
*/
Date.prototype.getFirstDateOfMonth = function() {
return new Date(this.getFullYear(), this.getMonth(), 1);
};
/**
* Get the date of the last day of the month in which this date resides.
* @return {Date}
*/
Date.prototype.getLastDateOfMonth = function() {
return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
};
/**
* Get the number of days in the current month, adjusted for leap year.
* @return {Number} The number of days in the month.
*/
Date.prototype.getDaysInMonth = function() {
Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
return Date.daysInMonth[this.getMonth()];
};
/**
* Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
* @return {String} 'st, 'nd', 'rd' or 'th'.
*/
Date.prototype.getSuffix = function() {
switch (this.getDate()) {
case 1:
case 21:
case 31:
return "st";
case 2:
case 22:
return "nd";
case 3:
case 23:
return "rd";
default:
return "th";
}
};
// private
Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
/**
* An array of textual month names.
* Override these values for international dates, for example...
* Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
* @type Array
* @static
*/
Date.monthNames =
["January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"];
/**
* Get the short month name for the given month number.
* Override this function for international dates.
* @param {Number} month A zero-based javascript month number.
* @return {String} The short month name.
* @static
*/
Date.getShortMonthName = function(month) {
return Date.monthNames[month].substring(0, 3);
}
/**
* An array of textual day names.
* Override these values for international dates, for example...
* Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
* @type Array
* @static
*/
Date.dayNames =
["Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"];
/**
* Get the short day name for the given day number.
* Override this function for international dates.
* @param {Number} day A zero-based javascript day number.
* @return {String} The short day name.
* @static
*/
Date.getShortDayName = function(day) {
return Date.dayNames[day].substring(0, 3);
}
// private
Date.y2kYear = 50;
/**
* An object hash of zero-based javascript month numbers (with short month names as keys. note: keys are case-sensitive).
* Override these values for international dates, for example...
* Date.monthNumbers = {'ShortJanNameInYourLang':0, 'ShortFebNameInYourLang':1, ...};
* @type Object
* @static
*/
Date.monthNumbers = {
Jan:0,
Feb:1,
Mar:2,
Apr:3,
May:4,
Jun:5,
Jul:6,
Aug:7,
Sep:8,
Oct:9,
Nov:10,
Dec:11};
/**
* Get the zero-based javascript month number for the given short/full month name.
* Override this function for international dates.
* @param {String} name The short/full month name.
* @return {Number} The zero-based javascript month number.
* @static
*/
Date.getMonthNumber = function(name) {
// handle camel casing for english month names (since the keys for the Date.monthNumbers hash are case sensitive)
return Date.monthNumbers[name.substring(0, 1).toUpperCase() + name.substring(1, 3).toLowerCase()];
}
/**
* Creates and returns a new Date instance with the exact same date value as the called instance.
* Dates are copied and passed by reference, so if a copied date variable is modified later, the original
* variable will also be changed. When the intention is to create a new variable that will not
* modify the original instance, you should create a clone.
*
* Example of correctly cloning a date:
* <pre><code>
//wrong way:
var orig = new Date('10/1/2006');
var copy = orig;
copy.setDate(5);
document.write(orig); //returns 'Thu Oct 05 2006'!
//correct way:
var orig = new Date('10/1/2006');
var copy = orig.clone();
copy.setDate(5);
document.write(orig); //returns 'Thu Oct 01 2006'
</code></pre>
* @return {Date} The new Date instance.
*/
Date.prototype.clone = function() {
return new Date(this.getTime());
};
/**
* Clears any time information from this date.
@param {Boolean} clone true to create a clone of this date, clear the time and return it (defaults to false).
@return {Date} this or the clone.
*/
Date.prototype.clearTime = function(clone){
if(clone){
return this.clone().clearTime();
}
this.setHours(0);
this.setMinutes(0);
this.setSeconds(0);
this.setMilliseconds(0);
return this;
};
// private
// safari setMonth is broken
if(Ext.isSafari){
Date.brokenSetMonth = Date.prototype.setMonth;
Date.prototype.setMonth = function(num){
if(num <= -1){
var n = Math.ceil(-num);
var back_year = Math.ceil(n/12);
var month = (n % 12) ? 12 - n % 12 : 0 ;
this.setFullYear(this.getFullYear() - back_year);
return Date.brokenSetMonth.call(this, month);
} else {
return Date.brokenSetMonth.apply(this, arguments);
}
};
}
/** Date interval constant @static @type String */
Date.MILLI = "ms";
/** Date interval constant @static @type String */
Date.SECOND = "s";
/** Date interval constant @static @type String */
Date.MINUTE = "mi";
/** Date interval constant @static @type String */
Date.HOUR = "h";
/** Date interval constant @static @type String */
Date.DAY = "d";
/** Date interval constant @static @type String */
Date.MONTH = "mo";
/** Date interval constant @static @type String */
Date.YEAR = "y";
/**
* Provides a convenient method of performing basic date arithmetic. This method
* does not modify the Date instance being called - it creates and returns
* a new Date instance containing the resulting date value.
*
* Examples:
* <pre><code>
//Basic usage:
var dt = new Date('10/29/2006').add(Date.DAY, 5);
document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
//Negative values will subtract correctly:
var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
//You can even chain several calls together in one line!
var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
</code></pre>
*
* @param {String} interval A valid date interval enum value.
* @param {Number} value The amount to add to the current date.
* @return {Date} The new Date instance.
*/
Date.prototype.add = function(interval, value){
var d = this.clone();
if (!interval || value === 0) return d;
switch(interval.toLowerCase()){
case Date.MILLI:
d.setMilliseconds(this.getMilliseconds() + value);
break;
case Date.SECOND:
d.setSeconds(this.getSeconds() + value);
break;
case Date.MINUTE:
d.setMinutes(this.getMinutes() + value);
break;
case Date.HOUR:
d.setHours(this.getHours() + value);
break;
case Date.DAY:
d.setDate(this.getDate() + value);
break;
case Date.MONTH:
var day = this.getDate();
if(day > 28){
day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
}
d.setDate(day);
d.setMonth(this.getMonth() + value);
break;
case Date.YEAR:
d.setFullYear(this.getFullYear() + value);
break;
}
return d;
};
/**
* Checks if this date falls on or between the given start and end dates.
* @param {Date} start Start date
* @param {Date} end End date
* @return {Boolean} true if this date falls on or between the given start and end dates.
*/
Date.prototype.between = function(start, end){
var t = this.getTime();
return start.getTime() <= t && t <= end.getTime();
}