]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/javascript/yui/build/datemath/datemath.js
Release 6.5.0
[Github/sugarcrm.git] / include / javascript / yui / build / datemath / datemath.js
1 /*
2 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
5 version: 2.9.0
6 */
7 /**
8 * The datemath module provides utility methods for basic JavaScript Date object manipulation and 
9 * comparison. 
10
11 * @module datemath
12 */
13
14 /**
15 * YAHOO.widget.DateMath is used for simple date manipulation. The class is a static utility
16 * used for adding, subtracting, and comparing dates.
17 * @namespace YAHOO.widget
18 * @class DateMath
19 */
20 YAHOO.widget.DateMath = {
21     /**
22     * Constant field representing Day
23     * @property DAY
24     * @static
25     * @final
26     * @type String
27     */
28     DAY : "D",
29
30     /**
31     * Constant field representing Week
32     * @property WEEK
33     * @static
34     * @final
35     * @type String
36     */
37     WEEK : "W",
38
39     /**
40     * Constant field representing Year
41     * @property YEAR
42     * @static
43     * @final
44     * @type String
45     */
46     YEAR : "Y",
47
48     /**
49     * Constant field representing Month
50     * @property MONTH
51     * @static
52     * @final
53     * @type String
54     */
55     MONTH : "M",
56
57     /**
58     * Constant field representing one day, in milliseconds
59     * @property ONE_DAY_MS
60     * @static
61     * @final
62     * @type Number
63     */
64     ONE_DAY_MS : 1000*60*60*24,
65     
66     /**
67      * Constant field representing the date in first week of January
68      * which identifies the first week of the year.
69      * <p>
70      * In the U.S, Jan 1st is normally used based on a Sunday start of week.
71      * ISO 8601, used widely throughout Europe, uses Jan 4th, based on a Monday start of week.
72      * </p>
73      * @property WEEK_ONE_JAN_DATE
74      * @static
75      * @type Number
76      */
77     WEEK_ONE_JAN_DATE : 1,
78
79     /**
80     * Adds the specified amount of time to the this instance.
81     * @method add
82     * @param {Date} date The JavaScript Date object to perform addition on
83     * @param {String} field The field constant to be used for performing addition.
84     * @param {Number} amount The number of units (measured in the field constant) to add to the date.
85     * @return {Date} The resulting Date object
86     */
87     add : function(date, field, amount) {
88         var d = new Date(date.getTime());
89         switch (field) {
90             case this.MONTH:
91                 var newMonth = date.getMonth() + amount;
92                 var years = 0;
93
94                 if (newMonth < 0) {
95                     while (newMonth < 0) {
96                         newMonth += 12;
97                         years -= 1;
98                     }
99                 } else if (newMonth > 11) {
100                     while (newMonth > 11) {
101                         newMonth -= 12;
102                         years += 1;
103                     }
104                 }
105
106                 d.setMonth(newMonth);
107                 d.setFullYear(date.getFullYear() + years);
108                 break;
109             case this.DAY:
110                 this._addDays(d, amount);
111                 // d.setDate(date.getDate() + amount);
112                 break;
113             case this.YEAR:
114                 d.setFullYear(date.getFullYear() + amount);
115                 break;
116             case this.WEEK:
117                 this._addDays(d, (amount * 7));
118                 // d.setDate(date.getDate() + (amount * 7));
119                 break;
120         }
121         return d;
122     },
123
124     /**
125      * Private helper method to account for bug in Safari 2 (webkit < 420)
126      * when Date.setDate(n) is called with n less than -128 or greater than 127.
127      * <p>
128      * Fix approach and original findings are available here:
129      * http://brianary.blogspot.com/2006/03/safari-date-bug.html
130      * </p>
131      * @method _addDays
132      * @param {Date} d JavaScript date object
133      * @param {Number} nDays The number of days to add to the date object (can be negative)
134      * @private
135      */
136     _addDays : function(d, nDays) {
137         if (YAHOO.env.ua.webkit && YAHOO.env.ua.webkit < 420) {
138             if (nDays < 0) {
139                 // Ensure we don't go below -128 (getDate() is always 1 to 31, so we won't go above 127)
140                 for(var min = -128; nDays < min; nDays -= min) {
141                     d.setDate(d.getDate() + min);
142                 }
143             } else {
144                 // Ensure we don't go above 96 + 31 = 127
145                 for(var max = 96; nDays > max; nDays -= max) {
146                     d.setDate(d.getDate() + max);
147                 }
148             }
149             // nDays should be remainder between -128 and 96
150         }
151         d.setDate(d.getDate() + nDays);
152     },
153
154     /**
155     * Subtracts the specified amount of time from the this instance.
156     * @method subtract
157     * @param {Date} date The JavaScript Date object to perform subtraction on
158     * @param {Number} field The this field constant to be used for performing subtraction.
159     * @param {Number} amount The number of units (measured in the field constant) to subtract from the date.
160     * @return {Date} The resulting Date object
161     */
162     subtract : function(date, field, amount) {
163         return this.add(date, field, (amount*-1));
164     },
165
166     /**
167     * Determines whether a given date is before another date on the calendar.
168     * @method before
169     * @param {Date} date  The Date object to compare with the compare argument
170     * @param {Date} compareTo The Date object to use for the comparison
171     * @return {Boolean} true if the date occurs before the compared date; false if not.
172     */
173     before : function(date, compareTo) {
174         var ms = compareTo.getTime();
175         if (date.getTime() < ms) {
176             return true;
177         } else {
178             return false;
179         }
180     },
181
182     /**
183     * Determines whether a given date is after another date on the calendar.
184     * @method after
185     * @param {Date} date  The Date object to compare with the compare argument
186     * @param {Date} compareTo The Date object to use for the comparison
187     * @return {Boolean} true if the date occurs after the compared date; false if not.
188     */
189     after : function(date, compareTo) {
190         var ms = compareTo.getTime();
191         if (date.getTime() > ms) {
192             return true;
193         } else {
194             return false;
195         }
196     },
197
198     /**
199     * Determines whether a given date is between two other dates on the calendar.
200     * @method between
201     * @param {Date} date  The date to check for
202     * @param {Date} dateBegin The start of the range
203     * @param {Date} dateEnd  The end of the range
204     * @return {Boolean} true if the date occurs between the compared dates; false if not.
205     */
206     between : function(date, dateBegin, dateEnd) {
207         if (this.after(date, dateBegin) && this.before(date, dateEnd)) {
208             return true;
209         } else {
210             return false;
211         }
212     },
213     
214     /**
215     * Retrieves a JavaScript Date object representing January 1 of any given year.
216     * @method getJan1
217     * @param {Number} calendarYear  The calendar year for which to retrieve January 1
218     * @return {Date} January 1 of the calendar year specified.
219     */
220     getJan1 : function(calendarYear) {
221         return this.getDate(calendarYear,0,1);
222     },
223
224     /**
225     * Calculates the number of days the specified date is from January 1 of the specified calendar year.
226     * Passing January 1 to this function would return an offset value of zero.
227     * @method getDayOffset
228     * @param {Date} date The JavaScript date for which to find the offset
229     * @param {Number} calendarYear The calendar year to use for determining the offset
230     * @return {Number} The number of days since January 1 of the given year
231     */
232     getDayOffset : function(date, calendarYear) {
233         var beginYear = this.getJan1(calendarYear); // Find the start of the year. This will be in week 1.
234         
235         // Find the number of days the passed in date is away from the calendar year start
236         var dayOffset = Math.ceil((date.getTime()-beginYear.getTime()) / this.ONE_DAY_MS);
237         return dayOffset;
238     },
239
240     /**
241     * Calculates the week number for the given date. Can currently support standard
242     * U.S. week numbers, based on Jan 1st defining the 1st week of the year, and 
243     * ISO8601 week numbers, based on Jan 4th defining the 1st week of the year.
244     * 
245     * @method getWeekNumber
246     * @param {Date} date The JavaScript date for which to find the week number
247     * @param {Number} firstDayOfWeek The index of the first day of the week (0 = Sun, 1 = Mon ... 6 = Sat).
248     * Defaults to 0
249     * @param {Number} janDate The date in the first week of January which defines week one for the year
250     * Defaults to the value of YAHOO.widget.DateMath.WEEK_ONE_JAN_DATE, which is 1 (Jan 1st). 
251     * For the U.S, this is normally Jan 1st. ISO8601 uses Jan 4th to define the first week of the year.
252     * 
253     * @return {Number} The number of the week containing the given date.
254     */
255     getWeekNumber : function(date, firstDayOfWeek, janDate) {
256
257         // Setup Defaults
258         firstDayOfWeek = firstDayOfWeek || 0;
259         janDate = janDate || this.WEEK_ONE_JAN_DATE;
260
261         var targetDate = this.clearTime(date),
262             startOfWeek,
263             endOfWeek;
264
265         if (targetDate.getDay() === firstDayOfWeek) { 
266             startOfWeek = targetDate;
267         } else {
268             startOfWeek = this.getFirstDayOfWeek(targetDate, firstDayOfWeek);
269         }
270
271         var startYear = startOfWeek.getFullYear();
272
273         // DST shouldn't be a problem here, math is quicker than setDate();
274         endOfWeek = new Date(startOfWeek.getTime() + 6*this.ONE_DAY_MS);
275
276         var weekNum;
277         if (startYear !== endOfWeek.getFullYear() && endOfWeek.getDate() >= janDate) {
278             // If years don't match, endOfWeek is in Jan. and if the 
279             // week has WEEK_ONE_JAN_DATE in it, it's week one by definition.
280             weekNum = 1;
281         } else {
282             // Get the 1st day of the 1st week, and 
283             // find how many days away we are from it.
284             var weekOne = this.clearTime(this.getDate(startYear, 0, janDate)),
285                 weekOneDayOne = this.getFirstDayOfWeek(weekOne, firstDayOfWeek);
286
287             // Round days to smoothen out 1 hr DST diff
288             var daysDiff  = Math.round((targetDate.getTime() - weekOneDayOne.getTime())/this.ONE_DAY_MS);
289
290             // Calc. Full Weeks
291             var rem = daysDiff % 7;
292             var weeksDiff = (daysDiff - rem)/7;
293             weekNum = weeksDiff + 1;
294         }
295         return weekNum;
296     },
297
298     /**
299      * Get the first day of the week, for the give date. 
300      * @param {Date} dt The date in the week for which the first day is required.
301      * @param {Number} startOfWeek The index for the first day of the week, 0 = Sun, 1 = Mon ... 6 = Sat (defaults to 0)
302      * @return {Date} The first day of the week
303      */
304     getFirstDayOfWeek : function (dt, startOfWeek) {
305         startOfWeek = startOfWeek || 0;
306         var dayOfWeekIndex = dt.getDay(),
307             dayOfWeek = (dayOfWeekIndex - startOfWeek + 7) % 7;
308
309         return this.subtract(dt, this.DAY, dayOfWeek);
310     },
311
312     /**
313     * Determines if a given week overlaps two different years.
314     * @method isYearOverlapWeek
315     * @param {Date} weekBeginDate The JavaScript Date representing the first day of the week.
316     * @return {Boolean} true if the date overlaps two different years.
317     */
318     isYearOverlapWeek : function(weekBeginDate) {
319         var overlaps = false;
320         var nextWeek = this.add(weekBeginDate, this.DAY, 6);
321         if (nextWeek.getFullYear() != weekBeginDate.getFullYear()) {
322             overlaps = true;
323         }
324         return overlaps;
325     },
326
327     /**
328     * Determines if a given week overlaps two different months.
329     * @method isMonthOverlapWeek
330     * @param {Date} weekBeginDate The JavaScript Date representing the first day of the week.
331     * @return {Boolean} true if the date overlaps two different months.
332     */
333     isMonthOverlapWeek : function(weekBeginDate) {
334         var overlaps = false;
335         var nextWeek = this.add(weekBeginDate, this.DAY, 6);
336         if (nextWeek.getMonth() != weekBeginDate.getMonth()) {
337             overlaps = true;
338         }
339         return overlaps;
340     },
341
342     /**
343     * Gets the first day of a month containing a given date.
344     * @method findMonthStart
345     * @param {Date} date The JavaScript Date used to calculate the month start
346     * @return {Date}  The JavaScript Date representing the first day of the month
347     */
348     findMonthStart : function(date) {
349         var start = this.getDate(date.getFullYear(), date.getMonth(), 1);
350         return start;
351     },
352
353     /**
354     * Gets the last day of a month containing a given date.
355     * @method findMonthEnd
356     * @param {Date} date The JavaScript Date used to calculate the month end
357     * @return {Date}  The JavaScript Date representing the last day of the month
358     */
359     findMonthEnd : function(date) {
360         var start = this.findMonthStart(date);
361         var nextMonth = this.add(start, this.MONTH, 1);
362         var end = this.subtract(nextMonth, this.DAY, 1);
363         return end;
364     },
365
366     /**
367     * Clears the time fields from a given date, effectively setting the time to 12 noon.
368     * @method clearTime
369     * @param {Date} date The JavaScript Date for which the time fields will be cleared
370     * @return {Date}  The JavaScript Date cleared of all time fields
371     */
372     clearTime : function(date) {
373         date.setHours(12,0,0,0);
374         return date;
375     },
376
377     /**
378      * Returns a new JavaScript Date object, representing the given year, month and date. Time fields (hr, min, sec, ms) on the new Date object
379      * are set to 0. The method allows Date instances to be created with the a year less than 100. "new Date(year, month, date)" implementations 
380      * set the year to 19xx if a year (xx) which is less than 100 is provided.
381      * <p>
382      * <em>NOTE:</em>Validation on argument values is not performed. It is the caller's responsibility to ensure
383      * arguments are valid as per the ECMAScript-262 Date object specification for the new Date(year, month[, date]) constructor.
384      * </p>
385      * @method getDate
386      * @param {Number} y Year.
387      * @param {Number} m Month index from 0 (Jan) to 11 (Dec).
388      * @param {Number} d (optional) Date from 1 to 31. If not provided, defaults to 1.
389      * @return {Date} The JavaScript date object with year, month, date set as provided.
390      */
391     getDate : function(y, m, d) {
392         var dt = null;
393         if (YAHOO.lang.isUndefined(d)) {
394             d = 1;
395         }
396         if (y >= 100) {
397             dt = new Date(y, m, d);
398         } else {
399             dt = new Date();
400             dt.setFullYear(y);
401             dt.setMonth(m);
402             dt.setDate(d);
403             dt.setHours(0,0,0,0);
404         }
405         return dt;
406     }
407 };
408 YAHOO.register("datemath", YAHOO.widget.DateMath, {version: "2.9.0", build: "2800"});