This repository has been archived by the owner on Sep 5, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
/
dateUtil.js
325 lines (298 loc) · 11.1 KB
/
dateUtil.js
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
(function() {
'use strict';
/**
* Utility for performing date calculations to facilitate operation of the calendar and
* datepicker.
*/
angular.module('material.components.datepicker').factory('$$mdDateUtil', function($mdDateLocale) {
return {
getFirstDateOfMonth: getFirstDateOfMonth,
getNumberOfDaysInMonth: getNumberOfDaysInMonth,
getDateInNextMonth: getDateInNextMonth,
getDateInPreviousMonth: getDateInPreviousMonth,
isInNextMonth: isInNextMonth,
isInPreviousMonth: isInPreviousMonth,
getDateMidpoint: getDateMidpoint,
isSameMonthAndYear: isSameMonthAndYear,
getWeekOfMonth: getWeekOfMonth,
incrementDays: incrementDays,
incrementMonths: incrementMonths,
getLastDateOfMonth: getLastDateOfMonth,
isSameDay: isSameDay,
getMonthDistance: getMonthDistance,
isValidDate: isValidDate,
setDateTimeToMidnight: setDateTimeToMidnight,
createDateAtMidnight: createDateAtMidnight,
isDateWithinRange: isDateWithinRange,
incrementYears: incrementYears,
getYearDistance: getYearDistance,
clampDate: clampDate,
getTimestampFromNode: getTimestampFromNode,
isMonthWithinRange: isMonthWithinRange,
removeLocalTzAndReparseDate: removeLocalTzAndReparseDate
};
/**
* Gets the first day of the month for the given date's month.
* @param {Date} date
* @returns {Date}
*/
function getFirstDateOfMonth(date) {
return new Date(date.getFullYear(), date.getMonth(), 1);
}
/**
* Gets the number of days in the month for the given date's month.
* @param date
* @returns {number}
*/
function getNumberOfDaysInMonth(date) {
return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
}
/**
* Get an arbitrary date in the month after the given date's month.
* @param date
* @returns {Date}
*/
function getDateInNextMonth(date) {
return new Date(date.getFullYear(), date.getMonth() + 1, 1);
}
/**
* Get an arbitrary date in the month before the given date's month.
* @param date
* @returns {Date}
*/
function getDateInPreviousMonth(date) {
return new Date(date.getFullYear(), date.getMonth() - 1, 1);
}
/**
* Gets whether two dates have the same month and year.
* @param {Date} d1
* @param {Date} d2
* @returns {boolean}
*/
function isSameMonthAndYear(d1, d2) {
return d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth();
}
/**
* Gets whether two dates are the same day (not not necessarily the same time).
* @param {Date} d1
* @param {Date} d2
* @returns {boolean}
*/
function isSameDay(d1, d2) {
return d1.getDate() == d2.getDate() && isSameMonthAndYear(d1, d2);
}
/**
* Gets whether a date is in the month immediately after some date.
* @param {Date} startDate The date from which to compare.
* @param {Date} endDate The date to check.
* @returns {boolean}
*/
function isInNextMonth(startDate, endDate) {
var nextMonth = getDateInNextMonth(startDate);
return isSameMonthAndYear(nextMonth, endDate);
}
/**
* Gets whether a date is in the month immediately before some date.
* @param {Date} startDate The date from which to compare.
* @param {Date} endDate The date to check.
* @returns {boolean}
*/
function isInPreviousMonth(startDate, endDate) {
var previousMonth = getDateInPreviousMonth(startDate);
return isSameMonthAndYear(endDate, previousMonth);
}
/**
* Gets the midpoint between two dates.
* @param {Date} d1
* @param {Date} d2
* @returns {Date}
*/
function getDateMidpoint(d1, d2) {
return createDateAtMidnight((d1.getTime() + d2.getTime()) / 2);
}
/**
* Gets the week of the month that a given date occurs in.
* @param {Date} date
* @returns {number} Index of the week of the month (zero-based).
*/
function getWeekOfMonth(date) {
var firstDayOfMonth = getFirstDateOfMonth(date);
return Math.floor((firstDayOfMonth.getDay() + date.getDate() - 1) / 7);
}
/**
* Gets a new date incremented by the given number of days. Number of days can be negative.
* @param {Date} date
* @param {number} numberOfDays
* @returns {Date}
*/
function incrementDays(date, numberOfDays) {
return new Date(date.getFullYear(), date.getMonth(), date.getDate() + numberOfDays);
}
/**
* Gets a new date incremented by the given number of months. Number of months can be negative.
* If the date of the given month does not match the target month, the date will be set to the
* last day of the month.
* @param {Date} date
* @param {number} numberOfMonths
* @returns {Date}
*/
function incrementMonths(date, numberOfMonths) {
// If the same date in the target month does not actually exist, the Date object will
// automatically advance *another* month by the number of missing days.
// For example, if you try to go from Jan. 30 to Feb. 30, you'll end up on March 2.
// So, we check if the month overflowed and go to the last day of the target month instead.
var dateInTargetMonth = new Date(date.getFullYear(), date.getMonth() + numberOfMonths, 1);
var numberOfDaysInMonth = getNumberOfDaysInMonth(dateInTargetMonth);
if (numberOfDaysInMonth < date.getDate()) {
dateInTargetMonth.setDate(numberOfDaysInMonth);
} else {
dateInTargetMonth.setDate(date.getDate());
}
return dateInTargetMonth;
}
/**
* Get the integer distance between two months. This *only* considers the month and year
* portion of the Date instances.
*
* @param {Date} start
* @param {Date} end
* @returns {number} Number of months between `start` and `end`. If `end` is before `start`
* chronologically, this number will be negative.
*/
function getMonthDistance(start, end) {
return (12 * (end.getFullYear() - start.getFullYear())) + (end.getMonth() - start.getMonth());
}
/**
* Gets the last day of the month for the given date.
* @param {Date} date
* @returns {Date}
*/
function getLastDateOfMonth(date) {
return new Date(date.getFullYear(), date.getMonth(), getNumberOfDaysInMonth(date));
}
/**
* Checks whether a date is valid.
* @param {Date} date
* @return {boolean} Whether the date is a valid Date.
*/
function isValidDate(date) {
return date && date.getTime && !isNaN(date.getTime());
}
/**
* Sets a date's time to midnight.
* @param {Date} date
*/
function setDateTimeToMidnight(date) {
if (isValidDate(date)) {
date.setHours(0, 0, 0, 0);
}
}
/**
* Creates a date with the time set to midnight.
* Drop-in replacement for two forms of the Date constructor via opt_value.
* @param {number|Date=} opt_value Leave undefined for a Date representing now. Or use a
* single value representing the number of seconds since the Unix Epoch or a Date object.
* @return {Date} New date with time set to midnight.
*/
function createDateAtMidnight(opt_value) {
var date;
if (angular.isDate(opt_value)) {
date = opt_value;
} else if (angular.isNumber(opt_value)) {
date = new Date(opt_value);
} else {
date = new Date();
}
setDateTimeToMidnight(date);
return date;
}
/**
* Checks if a date is within a min and max range, ignoring the time component.
* If minDate or maxDate are not dates, they are ignored.
* @param {Date} date
* @param {Date} minDate
* @param {Date} maxDate
*/
function isDateWithinRange(date, minDate, maxDate) {
var dateAtMidnight = createDateAtMidnight(date);
var minDateAtMidnight = isValidDate(minDate) ? createDateAtMidnight(minDate) : null;
var maxDateAtMidnight = isValidDate(maxDate) ? createDateAtMidnight(maxDate) : null;
return (!minDateAtMidnight || minDateAtMidnight <= dateAtMidnight) &&
(!maxDateAtMidnight || maxDateAtMidnight >= dateAtMidnight);
}
/**
* Gets a new date incremented by the given number of years. Number of years can be negative.
* See `incrementMonths` for notes on overflow for specific dates.
* @param {Date} date
* @param {number} numberOfYears
* @returns {Date}
*/
function incrementYears(date, numberOfYears) {
return incrementMonths(date, numberOfYears * 12);
}
/**
* Get the integer distance between two years. This *only* considers the year portion of the
* Date instances.
*
* @param {Date} start
* @param {Date} end
* @returns {number} Number of months between `start` and `end`. If `end` is before `start`
* chronologically, this number will be negative.
*/
function getYearDistance(start, end) {
return end.getFullYear() - start.getFullYear();
}
/**
* Clamps a date between a minimum and a maximum date.
* @param {Date} date Date to be clamped
* @param {Date=} minDate Minimum date
* @param {Date=} maxDate Maximum date
* @return {Date}
*/
function clampDate(date, minDate, maxDate) {
var boundDate = date;
if (minDate && date < minDate) {
boundDate = new Date(minDate.getTime());
}
if (maxDate && date > maxDate) {
boundDate = new Date(maxDate.getTime());
}
return boundDate;
}
/**
* Extracts and parses the timestamp from a DOM node.
* @param {HTMLElement} node Node from which the timestamp will be extracted.
* @return {number} Time since epoch.
*/
function getTimestampFromNode(node) {
if (node && node.hasAttribute('data-timestamp')) {
return Number(node.getAttribute('data-timestamp'));
}
}
/**
* Checks if a month is within a min and max range, ignoring the date and time components.
* If minDate or maxDate are not dates, they are ignored.
* @param {Date} date
* @param {Date} minDate
* @param {Date} maxDate
*/
function isMonthWithinRange(date, minDate, maxDate) {
var month = date.getMonth();
var year = date.getFullYear();
return (!minDate || minDate.getFullYear() < year || minDate.getMonth() <= month) &&
(!maxDate || maxDate.getFullYear() > year || maxDate.getMonth() >= month);
}
/**
* @param {Date} value date in local timezone
* @return {Date} date with local timezone offset removed
*/
function removeLocalTzAndReparseDate(value) {
var dateValue, formattedDate;
// Remove the local timezone offset before calling formatDate.
dateValue = new Date(value.getTime() + 60000 * value.getTimezoneOffset());
formattedDate = $mdDateLocale.formatDate(dateValue);
// parseDate only works with a date formatted by formatDate when using Moment validation.
return $mdDateLocale.parseDate(formattedDate);
}
});
})();