]>
Commit | Line | Data |
---|---|---|
2f01fe57 | 1 | /* |
81bea17a | 2 | Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. |
2f01fe57 AD |
3 | Available via Academic Free License >= 2.1 OR the modified BSD license. |
4 | see: http://dojotoolkit.org/license for details | |
5 | */ | |
6 | ||
7 | ||
a089699c AD |
8 | if(!dojo._hasResource["dojo.date"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
9 | dojo._hasResource["dojo.date"] = true; | |
2f01fe57 | 10 | dojo.provide("dojo.date"); |
a089699c | 11 | |
81bea17a AD |
12 | dojo.getObject("date", true, dojo); |
13 | ||
a089699c AD |
14 | /*===== |
15 | dojo.date = { | |
16 | // summary: Date manipulation utilities | |
2f01fe57 | 17 | } |
a089699c AD |
18 | =====*/ |
19 | ||
20 | dojo.date.getDaysInMonth = function(/*Date*/dateObject){ | |
21 | // summary: | |
22 | // Returns the number of days in the month used by dateObject | |
23 | var month = dateObject.getMonth(); | |
24 | var days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; | |
25 | if(month == 1 && dojo.date.isLeapYear(dateObject)){ return 29; } // Number | |
26 | return days[month]; // Number | |
81bea17a | 27 | }; |
a089699c AD |
28 | |
29 | dojo.date.isLeapYear = function(/*Date*/dateObject){ | |
30 | // summary: | |
31 | // Determines if the year of the dateObject is a leap year | |
32 | // description: | |
33 | // Leap years are years with an additional day YYYY-02-29, where the | |
34 | // year number is a multiple of four with the following exception: If | |
35 | // a year is a multiple of 100, then it is only a leap year if it is | |
36 | // also a multiple of 400. For example, 1900 was not a leap year, but | |
37 | // 2000 is one. | |
38 | ||
39 | var year = dateObject.getFullYear(); | |
40 | return !(year%400) || (!(year%4) && !!(year%100)); // Boolean | |
81bea17a | 41 | }; |
a089699c AD |
42 | |
43 | // FIXME: This is not localized | |
44 | dojo.date.getTimezoneName = function(/*Date*/dateObject){ | |
45 | // summary: | |
46 | // Get the user's time zone as provided by the browser | |
47 | // dateObject: | |
48 | // Needed because the timezone may vary with time (daylight savings) | |
49 | // description: | |
50 | // Try to get time zone info from toString or toLocaleString method of | |
51 | // the Date object -- UTC offset is not a time zone. See | |
52 | // http://www.twinsun.com/tz/tz-link.htm Note: results may be | |
53 | // inconsistent across browsers. | |
54 | ||
55 | var str = dateObject.toString(); // Start looking in toString | |
56 | var tz = ''; // The result -- return empty string if nothing found | |
57 | var match; | |
58 | ||
59 | // First look for something in parentheses -- fast lookup, no regex | |
60 | var pos = str.indexOf('('); | |
61 | if(pos > -1){ | |
62 | tz = str.substring(++pos, str.indexOf(')')); | |
63 | }else{ | |
64 | // If at first you don't succeed ... | |
65 | // If IE knows about the TZ, it appears before the year | |
81bea17a | 66 | // Capital letters or slash before a 4-digit year |
a089699c AD |
67 | // at the end of string |
68 | var pat = /([A-Z\/]+) \d{4}$/; | |
69 | if((match = str.match(pat))){ | |
70 | tz = match[1]; | |
71 | }else{ | |
72 | // Some browsers (e.g. Safari) glue the TZ on the end | |
73 | // of toLocaleString instead of putting it in toString | |
74 | str = dateObject.toLocaleString(); | |
81bea17a | 75 | // Capital letters or slash -- end of string, |
a089699c AD |
76 | // after space |
77 | pat = / ([A-Z\/]+)$/; | |
78 | if((match = str.match(pat))){ | |
79 | tz = match[1]; | |
80 | } | |
81 | } | |
82 | } | |
83 | ||
84 | // Make sure it doesn't somehow end up return AM or PM | |
85 | return (tz == 'AM' || tz == 'PM') ? '' : tz; // String | |
81bea17a | 86 | }; |
a089699c AD |
87 | |
88 | // Utility methods to do arithmetic calculations with Dates | |
89 | ||
90 | dojo.date.compare = function(/*Date*/date1, /*Date?*/date2, /*String?*/portion){ | |
91 | // summary: | |
92 | // Compare two date objects by date, time, or both. | |
93 | // description: | |
94 | // Returns 0 if equal, positive if a > b, else negative. | |
95 | // date1: | |
96 | // Date object | |
97 | // date2: | |
98 | // Date object. If not specified, the current Date is used. | |
99 | // portion: | |
100 | // A string indicating the "date" or "time" portion of a Date object. | |
101 | // Compares both "date" and "time" by default. One of the following: | |
102 | // "date", "time", "datetime" | |
103 | ||
104 | // Extra step required in copy for IE - see #3112 | |
105 | date1 = new Date(+date1); | |
106 | date2 = new Date(+(date2 || new Date())); | |
107 | ||
108 | if(portion == "date"){ | |
109 | // Ignore times and compare dates. | |
110 | date1.setHours(0, 0, 0, 0); | |
111 | date2.setHours(0, 0, 0, 0); | |
112 | }else if(portion == "time"){ | |
113 | // Ignore dates and compare times. | |
114 | date1.setFullYear(0, 0, 0); | |
115 | date2.setFullYear(0, 0, 0); | |
116 | } | |
117 | ||
118 | if(date1 > date2){ return 1; } // int | |
119 | if(date1 < date2){ return -1; } // int | |
120 | return 0; // int | |
2f01fe57 | 121 | }; |
a089699c AD |
122 | |
123 | dojo.date.add = function(/*Date*/date, /*String*/interval, /*int*/amount){ | |
124 | // summary: | |
125 | // Add to a Date in intervals of different size, from milliseconds to years | |
126 | // date: Date | |
127 | // Date object to start with | |
128 | // interval: | |
129 | // A string representing the interval. One of the following: | |
130 | // "year", "month", "day", "hour", "minute", "second", | |
131 | // "millisecond", "quarter", "week", "weekday" | |
132 | // amount: | |
133 | // How much to add to the date. | |
134 | ||
135 | var sum = new Date(+date); // convert to Number before copying to accomodate IE (#3112) | |
136 | var fixOvershoot = false; | |
137 | var property = "Date"; | |
138 | ||
139 | switch(interval){ | |
140 | case "day": | |
141 | break; | |
142 | case "weekday": | |
143 | //i18n FIXME: assumes Saturday/Sunday weekend, but this is not always true. see dojo.cldr.supplemental | |
144 | ||
145 | // Divide the increment time span into weekspans plus leftover days | |
146 | // e.g., 8 days is one 5-day weekspan / and two leftover days | |
147 | // Can't have zero leftover days, so numbers divisible by 5 get | |
148 | // a days value of 5, and the remaining days make up the number of weeks | |
149 | var days, weeks; | |
150 | var mod = amount % 5; | |
151 | if(!mod){ | |
152 | days = (amount > 0) ? 5 : -5; | |
153 | weeks = (amount > 0) ? ((amount-5)/5) : ((amount+5)/5); | |
154 | }else{ | |
155 | days = mod; | |
156 | weeks = parseInt(amount/5); | |
157 | } | |
158 | // Get weekday value for orig date param | |
159 | var strt = date.getDay(); | |
160 | // Orig date is Sat / positive incrementer | |
161 | // Jump over Sun | |
162 | var adj = 0; | |
163 | if(strt == 6 && amount > 0){ | |
164 | adj = 1; | |
165 | }else if(strt == 0 && amount < 0){ | |
166 | // Orig date is Sun / negative incrementer | |
167 | // Jump back over Sat | |
168 | adj = -1; | |
169 | } | |
170 | // Get weekday val for the new date | |
171 | var trgt = strt + days; | |
172 | // New date is on Sat or Sun | |
173 | if(trgt == 0 || trgt == 6){ | |
174 | adj = (amount > 0) ? 2 : -2; | |
175 | } | |
176 | // Increment by number of weeks plus leftover days plus | |
177 | // weekend adjustments | |
178 | amount = (7 * weeks) + days + adj; | |
179 | break; | |
180 | case "year": | |
181 | property = "FullYear"; | |
182 | // Keep increment/decrement from 2/29 out of March | |
183 | fixOvershoot = true; | |
184 | break; | |
185 | case "week": | |
186 | amount *= 7; | |
187 | break; | |
188 | case "quarter": | |
189 | // Naive quarter is just three months | |
190 | amount *= 3; | |
191 | // fallthrough... | |
192 | case "month": | |
193 | // Reset to last day of month if you overshoot | |
194 | fixOvershoot = true; | |
195 | property = "Month"; | |
196 | break; | |
197 | // case "hour": | |
198 | // case "minute": | |
199 | // case "second": | |
200 | // case "millisecond": | |
201 | default: | |
202 | property = "UTC"+interval.charAt(0).toUpperCase() + interval.substring(1) + "s"; | |
203 | } | |
204 | ||
205 | if(property){ | |
206 | sum["set"+property](sum["get"+property]()+amount); | |
207 | } | |
208 | ||
209 | if(fixOvershoot && (sum.getDate() < date.getDate())){ | |
210 | sum.setDate(0); | |
211 | } | |
212 | ||
213 | return sum; // Date | |
2f01fe57 | 214 | }; |
a089699c AD |
215 | |
216 | dojo.date.difference = function(/*Date*/date1, /*Date?*/date2, /*String?*/interval){ | |
217 | // summary: | |
218 | // Get the difference in a specific unit of time (e.g., number of | |
219 | // months, weeks, days, etc.) between two dates, rounded to the | |
220 | // nearest integer. | |
221 | // date1: | |
222 | // Date object | |
223 | // date2: | |
224 | // Date object. If not specified, the current Date is used. | |
225 | // interval: | |
226 | // A string representing the interval. One of the following: | |
227 | // "year", "month", "day", "hour", "minute", "second", | |
228 | // "millisecond", "quarter", "week", "weekday" | |
229 | // Defaults to "day". | |
230 | ||
231 | date2 = date2 || new Date(); | |
232 | interval = interval || "day"; | |
233 | var yearDiff = date2.getFullYear() - date1.getFullYear(); | |
234 | var delta = 1; // Integer return value | |
235 | ||
236 | switch(interval){ | |
237 | case "quarter": | |
238 | var m1 = date1.getMonth(); | |
239 | var m2 = date2.getMonth(); | |
240 | // Figure out which quarter the months are in | |
241 | var q1 = Math.floor(m1/3) + 1; | |
242 | var q2 = Math.floor(m2/3) + 1; | |
243 | // Add quarters for any year difference between the dates | |
244 | q2 += (yearDiff * 4); | |
245 | delta = q2 - q1; | |
246 | break; | |
247 | case "weekday": | |
248 | var days = Math.round(dojo.date.difference(date1, date2, "day")); | |
249 | var weeks = parseInt(dojo.date.difference(date1, date2, "week")); | |
250 | var mod = days % 7; | |
251 | ||
252 | // Even number of weeks | |
253 | if(mod == 0){ | |
254 | days = weeks*5; | |
255 | }else{ | |
256 | // Weeks plus spare change (< 7 days) | |
257 | var adj = 0; | |
258 | var aDay = date1.getDay(); | |
259 | var bDay = date2.getDay(); | |
260 | ||
261 | weeks = parseInt(days/7); | |
262 | mod = days % 7; | |
263 | // Mark the date advanced by the number of | |
264 | // round weeks (may be zero) | |
265 | var dtMark = new Date(date1); | |
266 | dtMark.setDate(dtMark.getDate()+(weeks*7)); | |
267 | var dayMark = dtMark.getDay(); | |
268 | ||
269 | // Spare change days -- 6 or less | |
270 | if(days > 0){ | |
271 | switch(true){ | |
272 | // Range starts on Sat | |
273 | case aDay == 6: | |
274 | adj = -1; | |
275 | break; | |
276 | // Range starts on Sun | |
277 | case aDay == 0: | |
278 | adj = 0; | |
279 | break; | |
280 | // Range ends on Sat | |
281 | case bDay == 6: | |
282 | adj = -1; | |
283 | break; | |
284 | // Range ends on Sun | |
285 | case bDay == 0: | |
286 | adj = -2; | |
287 | break; | |
288 | // Range contains weekend | |
289 | case (dayMark + mod) > 5: | |
290 | adj = -2; | |
291 | } | |
292 | }else if(days < 0){ | |
293 | switch(true){ | |
294 | // Range starts on Sat | |
295 | case aDay == 6: | |
296 | adj = 0; | |
297 | break; | |
298 | // Range starts on Sun | |
299 | case aDay == 0: | |
300 | adj = 1; | |
301 | break; | |
302 | // Range ends on Sat | |
303 | case bDay == 6: | |
304 | adj = 2; | |
305 | break; | |
306 | // Range ends on Sun | |
307 | case bDay == 0: | |
308 | adj = 1; | |
309 | break; | |
310 | // Range contains weekend | |
311 | case (dayMark + mod) < 0: | |
312 | adj = 2; | |
313 | } | |
314 | } | |
315 | days += adj; | |
316 | days -= (weeks*2); | |
317 | } | |
318 | delta = days; | |
319 | break; | |
320 | case "year": | |
321 | delta = yearDiff; | |
322 | break; | |
323 | case "month": | |
324 | delta = (date2.getMonth() - date1.getMonth()) + (yearDiff * 12); | |
325 | break; | |
326 | case "week": | |
327 | // Truncate instead of rounding | |
328 | // Don't use Math.floor -- value may be negative | |
329 | delta = parseInt(dojo.date.difference(date1, date2, "day")/7); | |
330 | break; | |
331 | case "day": | |
332 | delta /= 24; | |
333 | // fallthrough | |
334 | case "hour": | |
335 | delta /= 60; | |
336 | // fallthrough | |
337 | case "minute": | |
338 | delta /= 60; | |
339 | // fallthrough | |
340 | case "second": | |
341 | delta /= 1000; | |
342 | // fallthrough | |
343 | case "millisecond": | |
344 | delta *= date2.getTime() - date1.getTime(); | |
345 | } | |
346 | ||
347 | // Round for fractional values and DST leaps | |
348 | return Math.round(delta); // Number (integer) | |
2f01fe57 | 349 | }; |
a089699c | 350 | |
2f01fe57 | 351 | } |