1/*
2*  $Id: dateextensions.js 43 2006-08-17 19:11:44Z wingedfox $
3*  $HeadURL: https://svn.debugger.ru/repos/jslibs/BrowserExtensions/tags/BrowserExtensions.003/dateextensions.js $
4*
5*  Extension implements additional methods to operate with Date object
6*  @author Ilya Lebedev <ilya@lebedev.net>
7*  @modified $Date: 2006-08-17 23:11:44 +0400 (Чтв, 17 Авг 2006) $
8*  @version $Rev: 43 $
9*  @license LGPL 2.1 or later
10*/
11var MONTH_NAMES=new Array('January','February','March','April','May','June','July','August','September','October','November','December','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
12var DAY_NAMES=new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat');
13
14/*
15*  leap year check
16*
17*  @return bool check result
18*  @access public
19*/
20Date.prototype.isLeapYear = function () {
21  var y = this.getFullYear();
22  return (y % 4 == 0  &&  y % 100 != 0) || y % 400 == 0;
23}
24/*
25*  the day of year number
26*
27*  @return int day of year
28*  @access public
29*/
30Date.prototype.getDayOfYear = function () {
31   var md = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334],
32       m = this.getMonth(),
33       d = this.getDate()+md[m];
34   return this.isLeapYear()&&m>2?d+1:d;
35}
36/*
37*  return year according to Iso notation
38*
39*  @return int year number
40*  @access public
41*/
42Date.prototype.getIsoYear = function () {
43  var d = this.getDayOfYear(),
44      j1 = (new Date(this.getFullYear(),0,1)).getIsoDay(),
45      y = this.getFullYear();
46  if (d <= (8 - j1) && j1 > 4) {
47    return y-1;
48  } else if (((this.isLeapYear()?366:365) - d) < (4 - this.getIsoDay())) {
49    return y+1;
50  } else {
51    return y;
52  }
53}
54/*
55*  find day number in ISO notation (Mon = 1, Sun=7)
56*
57*  @return day number
58*  @access public
59*/
60Date.prototype.getIsoDay = function () {
61   var y = this.getFullYear(),
62       yy = (y-1) % 100,
63       c = (y-1) - yy,
64       g = yy + Math.floor(yy/4),
65       j1 = 1 + ((((Math.floor(c / 100) % 4) * 5) + g) % 7);
66   return (1 + ((this.getDayOfYear() + (j1 - 1) - 1) % 7));
67}
68/*
69*  return week number in ISO notation
70*
71*  @return int week number
72*  @access public
73*/
74Date.prototype.getIsoWeek = function () {
75  var y = this.getFullYear(),
76      yi = this.getIsoYear(),
77      j1 = (new Date(y,0,1)).getIsoDay();
78  if ( yi < y ) {
79    if (j1 == 5 || (j1 == 6 && (new Date(yi,0,1)).isLeapYear())) {
80      w = 53;
81    } else {
82      w = 52;
83    }
84  } else if (yi > y) {
85    w = 1;
86  } else {
87    var w = Math.floor((this.getDayOfYear() + (7-this.getIsoDay()) + (j1 - 1)) / 7);
88    if (j1 > 4) w -= 1;
89  }
90  return w;
91}
92/*
93*  Converts Date object to formatted string
94*
95*  @description
96*  Possible formatting options
97*    %a - abbreviated weekday name according to the current locale
98*    %A - full weekday name according to the current locale
99*    %b - abbreviated month name according to the current locale
100*    %B - full month name according to the current locale
101*    %c - preferred date and time representation for the current locale
102*    %C - century number (the year divided by 100 and truncated to an integer, range 00 to 99)
103*    %d - day of the month as a decimal number (range 01 to 31)
104*    %D - same as %m/%d/%y
105*    %e - day of the month as a decimal number, a single digit is preceded by a space (range ' 1' to '31')
106*    %g - like %G, but without the century.
107*    %G - The 4-digit year corresponding to the ISO week number (see %V).
108*         self has the same format and value as %Y, except that if the ISO week number belongs
109*         to the previous or next year, that year is used instead.
110*    %h - same as %b
111*    %H - hour as a decimal number using a 24-hour clock (range 00 to 23)
112*    %I - hour as a decimal number using a 12-hour clock (range 01 to 12)
113*    %j - day of the year as a decimal number (range 001 to 366)
114*    %m - month as a decimal number (range 01 to 12)
115*    %M - minute as a decimal number
116*    %n - newline character
117*    %p - either `am' or `pm' according to the given time value, or the corresponding strings for the current locale
118*    %r - time in a.m. and p.m. notation
119*    %R - time in 24 hour notation
120*    %S - second as a decimal number
121*    %t - tab character
122*    %T - current time, equal to %H:%M:%S
123*    %V - The ISO 8601:1988 week number of the current year as a decimal number, range 01 to 53,
124*         where week 1 is the first week that has at least 4 days in the current year,
125*         and with Monday as the first day of the week.
126*         (Use %G or %g for the year component that corresponds to the week number for the specified timestamp.)
127*    %u - weekday as a decimal number [1,7], with 1 representing Monday
128*    %U - week number of the current year as a decimal number, starting with the first Sunday as the first day of the first week
129*    %w - day of the week as a decimal, Sunday being 0
130*    %W - week number of the current year as a decimal number, starting with the first Monday as the first day of the first week
131*    %x - preferred date representation for the current locale without the time
132*    %X - preferred time representation for the current locale without the date
133*    %y - year as a decimal number without a century (range 00 to 99)
134*    %Y - year as a decimal number including the century
135*    %Z or %z - time zone or name or abbreviation
136*
137*  @link http://php.net/strftime
138*
139*  @param string optional date format
140*  @param string optional single char spacer, used to pad short values
141*  @return string formatted Date
142*  @access public
143*/
144Date.prototype.toFormatString = function (fmt, spacer) {
145  var self = this;
146  if (!fmt) return this.toString();
147  if (typeof spacer != 'string') spacer = "0";
148  if (spacer.length > 1) spacer.length = 1;
149
150  return fmt.replace(/%\w+/g,function(a) {
151      a = a.replace(/[%\s]/,"");
152      switch (a) {
153        case "a" : return DAY_NAMES[self.getDay()];
154        case "A" : return DAY_NAMES[self.getDay()+7];
155        case "b" :
156        case "h" : return MONTH_NAMES[self.getMonth()];
157        case "B" : return MONTH_NAMES[self.getMonth()+12];
158        case "c" : return; //???
159        case "C" : return Math.round(self.getFullYear()/100);
160        case "d" : return String(self.getDate()).padLeft(2,spacer);
161        case "D" : return self.toFormatString("%m/%d/%y", spacer);//String(self.getMonth()+1).padLeft(2,"0")+"/"+String(self.getDate()+1).padLeft(2,"0")+"/"+String(self.getFullYear()).slice(-2);
162        case "e" : return String(self.getDate()+1).padLeft(2);
163        case "g" : return self.getIsoYear().slice(-2);
164        case "G" : return self.getIsoYear();
165        case "H" : return String(self.getHours()).padLeft(2,spacer);
166        case "I" : return (self.getHours()>12?self.getHours()-12:self.getHours()).padLeft(2,spacer);
167        case "j" : return String(self.getDayOfYear()).padLeft(3,spacer);
168        case "m" : return String(self.getMonth()+1).padLeft(2,spacer);
169        case "M" : return String(self.getMinutes()).padLeft(2,spacer);
170        case "n" : return "\n";
171        case "p" : return (self.getHours()>12?"PM":"AM");
172        case "r" : return self.toFormatString("%I", spacer)+":"+self.toFormatString("%M", spacer)+":"+self.toFormatString("%S", spacer)+" "+self.toFormatString("%p", spacer);
173        case "R" : return self.toFormatString("%H", spacer)+":"+self.toFormatString("%M", spacer);
174        case "S" : return String(self.getSeconds()).padLeft(2,spacer);
175        case "t" : return "\t";
176        case "T" : return self.toFormatString("%H", spacer)+":"+self.toFormatString("%M", spacer)+":"+self.toFormatString("%S", spacer);
177        case "u" : return self.getIsoDay();
178        case "U" : return String(parseInt((self.getDayOfYear() - 1 - self.getIsoDay() + 13) / 7 - 1)).padLeft(2,"0");
179        case "V" : return String(self.getIsoWeek()).padLeft(2,spacer);
180        case "w" : return self.getDay();
181        case "W" : return String(parseInt((self.getDayOfYear() - 1 - self.getDay() + 13) / 7 - 1)).padLeft(2,"0");
182        case "x" : return; // ???
183        case "X" : return; // ???
184        case "y" : return String(self.getFullYear()).slice(-2);
185        case "Y" : return self.getFullYear();
186        case "z" : return; // ???
187        case "Z" : return self.getTimezoneOffset() / 60;
188      }
189      return a;
190    }
191  )
192}
193