aboutsummaryrefslogtreecommitdiff
path: root/contexts/data/lib/closure-library/closure/goog/date/daterange.js
blob: ac14c8e557b6ee794d57cc91df5205ec518ccd23 (plain)
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
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Date range data structure. Based loosely on
 * com.google.common.util.DateRange.
 *
 */

goog.provide('goog.date.DateRange');
goog.provide('goog.date.DateRange.Iterator');
goog.provide('goog.date.DateRange.StandardDateRangeKeys');

goog.require('goog.date.Date');
goog.require('goog.date.Interval');
goog.require('goog.iter.Iterator');
goog.require('goog.iter.StopIteration');



/**
 * Constructs a date range.
 * @constructor
 * @param {goog.date.Date} startDate The first date in the range.
 * @param {goog.date.Date} endDate The last date in the range.
 */
goog.date.DateRange = function(startDate, endDate) {
  /**
   * The first date in the range.
   * @type {goog.date.Date}
   * @private
   */
  this.startDate_ = startDate;

  /**
   * The last date in the range.
   * @type {goog.date.Date}
   * @private
   */
  this.endDate_ = endDate;
};


/**
 * The first possible day, as far as this class is concerned.
 * @type {goog.date.Date}
 */
goog.date.DateRange.MINIMUM_DATE = new goog.date.Date(0000, 0, 1);


/**
 * The last possible day, as far as this class is concerned.
 * @type {goog.date.Date}
 */
goog.date.DateRange.MAXIMUM_DATE = new goog.date.Date(9999, 11, 31);


/**
 * @return {goog.date.Date} The first date in the range.
 */
goog.date.DateRange.prototype.getStartDate = function() {
  return this.startDate_;
};


/**
 * @return {goog.date.Date} The last date in the range.
 */
goog.date.DateRange.prototype.getEndDate = function() {
  return this.endDate_;
};


/**
 * @return {goog.iter.Iterator} An iterator over the date range.
 */
goog.date.DateRange.prototype.iterator = function() {
  return new goog.date.DateRange.Iterator(this);
};


/**
 * Tests two {@link goog.date.DateRange} objects for equality.
 * @param {goog.date.DateRange} a A date range.
 * @param {goog.date.DateRange} b A date range.
 * @return {boolean} Whether |a| is the same range as |b|.
 */
goog.date.DateRange.equals = function(a, b) {
  // Test for same object reference; type conversion is irrelevant.
  if (a === b) {
    return true;
  }

  if (a == null || b == null) {
    return false;
  }

  return a.startDate_.equals(b.startDate_) && a.endDate_.equals(b.endDate_);
};


/**
 * Calculates a date that is a number of days after a date. Does not modify its
 * input.
 * @param {goog.date.Date} date The input date.
 * @param {number} offset Number of days.
 * @return {goog.date.Date} The date that is |offset| days after |date|.
 * @private
 */
goog.date.DateRange.offsetInDays_ = function(date, offset) {
  var newDate = date.clone();
  newDate.add(new goog.date.Interval(goog.date.Interval.DAYS, offset));
  return newDate;
};


/**
 * Calculates the Monday before a date. If the input is a Monday, returns the
 * input. Does not modify its input.
 * @param {goog.date.Date} date The input date.
 * @return {goog.date.Date} If |date| is a Monday, return |date|; otherwise
 *     return the Monday before |date|.
 * @private
 */
goog.date.DateRange.currentOrLastMonday_ = function(date) {
  var newDate = date.clone();
  newDate.add(new goog.date.Interval(goog.date.Interval.DAYS,
      -newDate.getIsoWeekday()));
  return newDate;
};


/**
 * Calculates a date that is a number of months after the first day in the
 * month that contains its input. Does not modify its input.
 * @param {goog.date.Date} date The input date.
 * @param {number} offset Number of months.
 * @return {goog.date.Date} The date that is |offset| months after the first
 *     day in the month that contains |date|.
 * @private
 */
goog.date.DateRange.offsetInMonths_ = function(date, offset) {
  var newDate = date.clone();
  newDate.setDate(1);
  newDate.add(new goog.date.Interval(goog.date.Interval.MONTHS, offset));
  return newDate;
};


/**
 * Returns the range from yesterday to yesterday.
 * @param {goog.date.Date=} opt_today The date to consider today.
 *     Defaults to today.
 * @return {goog.date.DateRange} The range that includes only yesterday.
 */
goog.date.DateRange.yesterday = function(opt_today) {
  var today = goog.date.DateRange.cloneOrCreate_(opt_today);
  var yesterday = goog.date.DateRange.offsetInDays_(today, -1);
  return new goog.date.DateRange(yesterday, yesterday);
};


/**
 * Returns the range from today to today.
 * @param {goog.date.Date=} opt_today The date to consider today.
 *     Defaults to today.
 * @return {goog.date.DateRange} The range that includes only today.
 */
goog.date.DateRange.today = function(opt_today) {
  var today = goog.date.DateRange.cloneOrCreate_(opt_today);
  return new goog.date.DateRange(today, today);
};


/**
 * Returns the range that includes the seven days that end yesterday.
 * @param {goog.date.Date=} opt_today The date to consider today.
 *     Defaults to today.
 * @return {goog.date.DateRange} The range that includes the seven days that
 *     end yesterday.
 */
goog.date.DateRange.last7Days = function(opt_today) {
  var today = goog.date.DateRange.cloneOrCreate_(opt_today);
  var yesterday = goog.date.DateRange.offsetInDays_(today, -1);
  return new goog.date.DateRange(goog.date.DateRange.offsetInDays_(today, -7),
      yesterday);
};


/**
 * Returns the range that starts the first of this month and ends the last day
 * of this month.
 * @param {goog.date.Date=} opt_today The date to consider today.
 *     Defaults to today.
 * @return {goog.date.DateRange} The range that starts the first of this month
 *     and ends the last day of this month.
 */
goog.date.DateRange.thisMonth = function(opt_today) {
  var today = goog.date.DateRange.cloneOrCreate_(opt_today);
  return new goog.date.DateRange(
      goog.date.DateRange.offsetInMonths_(today, 0),
      goog.date.DateRange.offsetInDays_(
          goog.date.DateRange.offsetInMonths_(today, 1),
          -1));
};


/**
 * Returns the range that starts the first of last month and ends the last day
 * of last month.
 * @param {goog.date.Date=} opt_today The date to consider today.
 *     Defaults to today.
 * @return {goog.date.DateRange} The range that starts the first of last month
 *     and ends the last day of last month.
 */
goog.date.DateRange.lastMonth = function(opt_today) {
  var today = goog.date.DateRange.cloneOrCreate_(opt_today);
  return new goog.date.DateRange(
      goog.date.DateRange.offsetInMonths_(today, -1),
      goog.date.DateRange.offsetInDays_(
          goog.date.DateRange.offsetInMonths_(today, 0),
          -1));
};


/**
 * Returns the seven-day range that starts on the first day of the week
 * (see {@link goog.i18n.DateTimeSymbols.FIRSTDAYOFWEEK}) on or before today.
 * @param {goog.date.Date=} opt_today The date to consider today.
 *     Defaults to today.
 * @return {goog.date.DateRange} The range that starts the Monday on or before
 *     today and ends the Sunday on or after today.
 */
goog.date.DateRange.thisWeek = function(opt_today) {
  var today = goog.date.DateRange.cloneOrCreate_(opt_today);
  var iso = today.getIsoWeekday();
  var firstDay = today.getFirstDayOfWeek();
  var i18nFirstDay = (iso >= firstDay) ? iso - firstDay : iso + (7 - firstDay);
  var start = goog.date.DateRange.offsetInDays_(today, -i18nFirstDay);
  var end = goog.date.DateRange.offsetInDays_(start, 6);
  return new goog.date.DateRange(start, end);
};


/**
 * Returns the seven-day range that ends the day before the first day of
 * the week (see {@link goog.i18n.DateTimeSymbols.FIRSTDAYOFWEEK}) that
 * contains today.
 * @param {goog.date.Date=} opt_today The date to consider today.
 *     Defaults to today.
 * @return {goog.date.DateRange} The range that starts seven days before the
 *     Monday on or before today and ends the Sunday on or before yesterday.
 */
goog.date.DateRange.lastWeek = function(opt_today) {
  var thisWeek = goog.date.DateRange.thisWeek(opt_today);
  var start = goog.date.DateRange.offsetInDays_(thisWeek.getStartDate(), -7);
  var end = goog.date.DateRange.offsetInDays_(thisWeek.getEndDate(), -7);
  return new goog.date.DateRange(start, end);
};


/**
 * Returns the range that starts seven days before the Monday on or before
 * today and ends the Friday before today.
 * @param {goog.date.Date=} opt_today The date to consider today.
 *     Defaults to today.
 * @return {goog.date.DateRange} The range that starts seven days before the
 *     Monday on or before today and ends the Friday before today.
 */
goog.date.DateRange.lastBusinessWeek = function(opt_today) {
  // TODO(user): should be i18nized.
  var today = goog.date.DateRange.cloneOrCreate_(opt_today);
  var start = goog.date.DateRange.offsetInDays_(today,
      - 7 - today.getIsoWeekday());
  var end = goog.date.DateRange.offsetInDays_(start, 4);
  return new goog.date.DateRange(start, end);
};


/**
 * Returns the range that includes all days between January 1, 1900 and
 * December 31, 9999.
 * @param {goog.date.Date=} opt_today The date to consider today.
 *     Defaults to today.
 * @return {goog.date.DateRange} The range that includes all days between
 *     January 1, 1900 and December 31, 9999.
 */
goog.date.DateRange.allTime = function(opt_today) {
  return new goog.date.DateRange(
      goog.date.DateRange.MINIMUM_DATE,
      goog.date.DateRange.MAXIMUM_DATE);
};


/**
 * Standard date range keys. Equivalent to the enum IDs in
 * DateRange.java http://go/datarange.java
 *
 * @enum {string}
 */
goog.date.DateRange.StandardDateRangeKeys = {
  YESTERDAY: 'yesterday',
  TODAY: 'today',
  LAST_7_DAYS: 'last7days',
  THIS_MONTH: 'thismonth',
  LAST_MONTH: 'lastmonth',
  THIS_WEEK: 'thisweek',
  LAST_WEEK: 'lastweek',
  LAST_BUSINESS_WEEK: 'lastbusinessweek',
  ALL_TIME: 'alltime'
};


/**
 * @param {string} dateRangeKey A standard date range key.
 * @param {goog.date.Date=} opt_today The date to consider today.
 *     Defaults to today.
 * @return {goog.date.DateRange} The date range that corresponds to that key.
 * @throws {Error} If no standard date range with that key exists.
 */
goog.date.DateRange.standardDateRange = function(dateRangeKey, opt_today) {
  switch (dateRangeKey) {
    case goog.date.DateRange.StandardDateRangeKeys.YESTERDAY:
      return goog.date.DateRange.yesterday(opt_today);

    case goog.date.DateRange.StandardDateRangeKeys.TODAY:
      return goog.date.DateRange.today(opt_today);

    case goog.date.DateRange.StandardDateRangeKeys.LAST_7_DAYS:
      return goog.date.DateRange.last7Days(opt_today);

    case goog.date.DateRange.StandardDateRangeKeys.THIS_MONTH:
      return goog.date.DateRange.thisMonth(opt_today);

    case goog.date.DateRange.StandardDateRangeKeys.LAST_MONTH:
      return goog.date.DateRange.lastMonth(opt_today);

    case goog.date.DateRange.StandardDateRangeKeys.THIS_WEEK:
      return goog.date.DateRange.thisWeek(opt_today);

    case goog.date.DateRange.StandardDateRangeKeys.LAST_WEEK:
      return goog.date.DateRange.lastWeek(opt_today);

    case goog.date.DateRange.StandardDateRangeKeys.LAST_BUSINESS_WEEK:
      return goog.date.DateRange.lastBusinessWeek(opt_today);

    case goog.date.DateRange.StandardDateRangeKeys.ALL_TIME:
      return goog.date.DateRange.allTime(opt_today);

    default:
      throw Error('no such date range key: ' + dateRangeKey);
  }
};


/**
 * Clones or creates new.
 * @param {goog.date.Date=} opt_today The date to consider today.
 *     Defaults to today.
 * @return {!goog.date.Date} cloned or new.
 * @private
 */
goog.date.DateRange.cloneOrCreate_ = function(opt_today) {
  return opt_today ? opt_today.clone() : new goog.date.Date();
};



/**
 * Creates an iterator over the dates in a {@link goog.date.DateRange}.
 * @constructor
 * @extends {goog.iter.Iterator}
 * @param {goog.date.DateRange} dateRange The date range to iterate.
 */
goog.date.DateRange.Iterator = function(dateRange) {
  /**
   * The next date.
   * @type {goog.date.Date}
   * @private
   */
  this.nextDate_ = dateRange.getStartDate().clone();

  /**
   * The end date, expressed as an integer: YYYYMMDD.
   * @type {number}
   * @private
   */
  this.endDate_ = Number(dateRange.getEndDate().toIsoString());
};
goog.inherits(goog.date.DateRange.Iterator, goog.iter.Iterator);


/** @override */
goog.date.DateRange.Iterator.prototype.next = function() {
  if (Number(this.nextDate_.toIsoString()) > this.endDate_) {
    throw goog.iter.StopIteration;
  }

  var rv = this.nextDate_.clone();
  this.nextDate_.add(new goog.date.Interval(goog.date.Interval.DAYS, 1));
  return rv;
};