BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlt_dateutil.h
Go to the documentation of this file.
1/// @file bdlt_dateutil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlt_dateutil.h -*-C++-*-
8#ifndef INCLUDED_BDLT_DATEUTIL
9#define INCLUDED_BDLT_DATEUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlt_dateutil bdlt_dateutil
15/// @brief Provide common non-primitive operations on date objects.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlt
19/// @{
20/// @addtogroup bdlt_dateutil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlt_dateutil-purpose"> Purpose</a>
25/// * <a href="#bdlt_dateutil-classes"> Classes </a>
26/// * <a href="#bdlt_dateutil-description"> Description </a>
27/// * <a href="#bdlt_dateutil-yyyymmdd-format"> "YYYYMMDD" Format </a>
28/// * <a href="#bdlt_dateutil-end-of-month-adjustment-conventions"> End-of-Month Adjustment Conventions </a>
29/// * <a href="#bdlt_dateutil-usage"> Usage </a>
30/// * <a href="#bdlt_dateutil-example-1-schedule-generation"> Example 1: Schedule Generation </a>
31///
32/// # Purpose {#bdlt_dateutil-purpose}
33/// Provide common non-primitive operations on date objects.
34///
35/// # Classes {#bdlt_dateutil-classes}
36///
37/// - bdlt::DateUtil: namespace for non-primitive operations on date objects
38///
39/// @see bdlt_date
40///
41/// # Description {#bdlt_dateutil-description}
42/// This component provides a `struct`, `bdlt::DateUtil`, that
43/// serves as a namespace for utility functions that operate on `bdlt::Date`
44/// objects.
45///
46/// The following list of methods are provided by `bdlt::DateUtil`:
47/// @code
48/// 'isValidYYYYMMDD' o Validate or convert to and from the
49/// 'convertFromYYYYMMDDRaw' "YYYYMMDD" format
50/// 'convertFromYYYYMMDD' (see {"YYYYMMDD" Format}).
51/// 'convertToYYYYMMDD'
52///
53/// 'nextDayOfWeek' o Move a date to the next or the previous
54/// 'nextDayOfWeekInclusive' specified day of week.
55/// 'previousDayOfWeek'
56/// 'previousDayOfWeekInclusive'
57///
58/// 'earliestDayOfWeekInMonth' o Find a specified day of the week in a
59/// 'nthDayOfWeekInMonth' specified year and month.
60/// 'lastDayOfWeekInMonth'
61/// 'lastDayInMonth'
62///
63/// 'addMonthsEom' o Add a specified number of months to a date
64/// 'addMonthsNoEom' using either the end-of-month or the
65/// 'addMonths' non-end-of-month convention (see
66/// {End-of-Month Adjustment Conventions}).
67///
68/// 'addYearsEom' o Add a specified number of years to a date
69/// 'addYearsNoEom' using either the end-of-month or the
70/// 'addYears' non-end-of-month convention (see
71/// {End-of-Month Adjustment Conventions}).
72/// @endcode
73///
74/// ## "YYYYMMDD" Format {#bdlt_dateutil-yyyymmdd-format}
75///
76///
77/// The "YYYYMMDD" format is a common integral representation of a date that is
78/// human readable and maintains appropriate ordering when sorted using integer
79/// comparisons. The notation uses eight digits (from left to right): four
80/// digits for the year, two digits for the month, and two digits for the day of
81/// the month. For example, February 1, 2014, is represented by the number
82/// 20140201.
83///
84/// Note that the year is not restricted to values on or after 1000, so, for
85/// example, 10102 (or 00010102) represents the date January 2, 0001.
86///
87/// ## End-of-Month Adjustment Conventions {#bdlt_dateutil-end-of-month-adjustment-conventions}
88///
89///
90/// Two adjustment conventions are used to determine the behavior of the
91/// functions (`addMonths` and `addYears`) that adjust a date by a particular
92/// number of months or years: the end-of-month convention and the
93/// non-end-of-month convention. The difference between the two conventions is
94/// that the end-of-month convention adjusts the resulting date to the end of
95/// the month if the original date is the last day of the month, while the
96/// non-end-of-month convention does not perform this adjustment.
97///
98/// For example, if we add 3 months to February 28, 2013 using the
99/// non-end-of-month convention, then the resulting date will be May 28, 2013.
100/// If we do the same operation except using the end-of-month convention, then
101/// the resulting date will be May 31, 2013.
102///
103/// More formal definitions of the two conventions are provided below:
104///
105/// The End-of-Month Convention:
106/// If the original date to be adjusted is the last day of a month, or if
107/// the day of the month of the original date does not exist in the
108/// resulting date, then adjust the resulting date to be the last day of
109/// the month.
110///
111/// The Non-End-of-Month Convention:
112/// If the day of the month of the original date does not exist in the
113/// resulting date, then adjust the resulting date to be the last day of
114/// the month.
115///
116/// ## Usage {#bdlt_dateutil-usage}
117///
118///
119/// This section illustrates intended use of this component.
120///
121/// ### Example 1: Schedule Generation {#bdlt_dateutil-example-1-schedule-generation}
122///
123///
124/// Suppose that given a starting date in the "YYYYMMDD" format, we want to
125/// generate a schedule for an event that occurs on the same day of the month
126/// for 12 months.
127///
128/// First, we use the `bdlt::DateUtil::convertFromYYYYMMDD` function to convert
129/// the integer into a `bdlt::Date`:
130/// @code
131/// const int startingDateYYYYMMDD = 20130430;
132///
133/// bdlt::Date date;
134/// int rc = bdlt::DateUtil::convertFromYYYYMMDD(&date, startingDateYYYYMMDD);
135/// assert(0 == rc);
136/// @endcode
137/// Now, we use the `addMonthsEom` function to generate the schedule. Note that
138/// `addMonthsEom` adjusts the resulting date to be the last day of the month if
139/// the original date is the last day of the month, while `addMonthsNoEom` does
140/// not make this adjustment.
141/// @code
142/// bsl::vector<bdlt::Date> schedule;
143/// schedule.push_back(date);
144///
145/// for (int i = 1; i < 12; ++i) {
146/// schedule.push_back(bdlt::DateUtil::addMonthsEom(date, i));
147/// }
148/// @endcode
149/// Finally, we print the generated schedule to the console and observe the
150/// output:
151/// @code
152/// bsl::copy(schedule.begin(),
153/// schedule.end(),
154/// bsl::ostream_iterator<bdlt::Date>(bsl::cout, "\n"));
155///
156/// // Expected output on the console:
157/// //
158/// // 30APR2013
159/// // 31MAY2013
160/// // 30JUN2013
161/// // 31JUL2013
162/// // 31AUG2013
163/// // 30SEP2013
164/// // 31OCT2013
165/// // 30NOV2013
166/// // 31DEC2013
167/// // 31JAN2014
168/// // 28FEB2014
169/// // 31MAR2014
170/// @endcode
171/// Notice that the dates have been adjusted to the end of the month. If we had
172/// used `addMonthsNoEom` instead of `addMonthsEom`, this adjustment would not
173/// have occurred.
174/// @}
175/** @} */
176/** @} */
177
178/** @addtogroup bdl
179 * @{
180 */
181/** @addtogroup bdlt
182 * @{
183 */
184/** @addtogroup bdlt_dateutil
185 * @{
186 */
187
188#include <bdlscm_version.h>
189
190#include <bdlt_date.h>
191#include <bdlt_dayofweek.h>
193
194#include <bsls_assert.h>
195#include <bsls_review.h>
196
197
198namespace bdlt {
199
200 // ===============
201 // struct DateUtil
202 // ===============
203
204/// This `struct` provides a namespace for utility functions that provide
205/// non-primitive operations on dates.
206struct DateUtil {
207
208 private:
209 // PRIVATE CLASS METHODS
210
211 /// Return the date that is the specified `numYears` from the specified
212 /// `original` date (which must be either the 28th or 29th of February),
213 /// adjusted as necessary according to the following (end-of-month)
214 /// rules: (1) if `original` is the last day of a month, adjust the
215 /// result to be the last day of the month, and (2) if the day of the
216 /// month in `original` does not exist in the month of the result (e.g.,
217 /// February 29, 2001), move the resulting date to the last day of the
218 /// month. The behavior is undefined unless `original` is either the
219 /// 28th or 29th of February, and the resulting date results in a valid
220 /// `Date` value. Note that `numYears` may be negative.
221 static Date addYearsEomEndOfFebruary(const Date& original, int numYears);
222
223 public:
224 // CLASS METHODS
225
226 /// Return the date that is the specified `numMonths` from the specified
227 /// `original` date, adjusted as necessary according to the specified
228 /// `eomFlag` (end-of-month flag). If `eomFlag` is `true` and
229 /// `original` is the last day of the month, then adjust the result to
230 /// be the last day of the month; if `eomFlag` is `false`, then no such
231 /// adjustment is performed. In any case, if the day of the month in
232 /// `original` does not exist in the month of the result (e.g., February
233 /// 29, 2001), move the resulting date to the last day of the month.
234 /// The behavior is undefined unless the operation results in a valid
235 /// `Date` value. Note that `numMonths` may be negative.
236 static Date addMonths(const Date& original, int numMonths, bool eomFlag);
237
238 /// Return the date that is the specified `numMonths` from the specified
239 /// `original` date, adjusted as necessary according to the following
240 /// (end-of-month) rules: (1) if `original` is the last day of a month,
241 /// adjust the result to be the last day of the month, and (2) if the
242 /// day of the month in `original` does not exist in the month of the
243 /// result (e.g., February 30), move the resulting date to the last day
244 /// of the month. The behavior is undefined unless the operation
245 /// results in a valid `Date` value. Note that `numMonths` may be
246 /// negative.
247 static Date addMonthsEom(const Date& original, int numMonths);
248
249 /// Return the date that is the specified `numMonths` from the specified
250 /// `original` date, adjusted as necessary according to the following
251 /// (non-end-of-month) rule: if the day of the month in `original` does
252 /// not exist in the month of the result (e.g., February 29, 2001), move
253 /// the resulting date to the last day of the month. The behavior is
254 /// undefined unless the operation results in a valid `Date` value.
255 /// Note that `numMonths` may be negative.
256 static Date addMonthsNoEom(const Date& original, int numMonths);
257
258 /// Return the date that is the specified `numYears` from the specified
259 /// `original` date, adjusted as necessary according to the specified
260 /// `eomFlag` (end-of-month flag). If `eomFlag` is `true` and
261 /// `original` is the last day of the month, then adjust the result to
262 /// be the last day of the month; if `eomFlag` is `false`, then no such
263 /// adjustment is performed. In any case, if the day of the month in
264 /// `original` does not exist in the month of the result (e.g., February
265 /// 29, 2001), move the resulting date to the last day of the month.
266 /// The behavior is undefined unless the operation results in a valid
267 /// `Date` value. Note that `numYears` may be negative.
268 static Date addYears(const Date& original, int numYears, bool eomFlag);
269
270 /// Return the date that is the specified `numYears` from the specified
271 /// `original` date, adjusted as necessary according to the following
272 /// (end-of-month) rules: (1) if `original` is the last day of a month,
273 /// adjust the result to be the last day of the month, and (2) if the
274 /// day of the month in `original` does not exist in the month of the
275 /// result (e.g., February 29, 2001), move the resulting date to the
276 /// last day of the month. The behavior is undefined unless the
277 /// operation results in a valid `Date` value. Note that `numYears` may
278 /// be negative.
279 static Date addYearsEom(const Date& original, int numYears);
280
281 /// Return the date that is the specified `numYears` from the specified
282 /// `original` date, adjusted as necessary according to the following
283 /// (non-end-of-month) rule: if the day of the month in `original` does
284 /// not exist in the month of the result (e.g., February 30), move the
285 /// resulting date to the last day of the month. The behavior is
286 /// undefined unless the operation results in a valid `Date` value.
287 /// Note that `numYears` may be negative.
288 static Date addYearsNoEom(const Date& original, int numYears);
289
290 /// Load, into the specified `result`, the `Date` value represented by
291 /// the specified `yyyymmddValue` in the "YYYYMMDD" format. Return 0 on
292 /// success, and a non-zero value, with no effect on `result`, if
293 /// `yyyymmddValue` does not represent a valid `Date`.
294 static int convertFromYYYYMMDD(Date *result, int yyyymmddValue);
295
296 /// Return the `Date` value represented by the specified `yyyymmddValue`
297 /// in the "YYYYMMDD" format. The behavior is undefined unless
298 /// `yyyymmddValue` represents a valid `Date`.
299 static Date convertFromYYYYMMDDRaw(int yyyymmddValue);
300
301 /// Return the integer value in the "YYYYMMDD" format that represents
302 /// the specified `date`.
303 static int convertToYYYYMMDD(const Date& date);
304
305 /// Return the earliest date in the specified `month` of the specified
306 /// `year` that falls on the specified `dayOfWeek`. The behavior is
307 /// undefined unless `1 <= year <= 9999` and `1 <= month <= 12`.
308 static Date earliestDayOfWeekInMonth(int year,
309 int month,
310 DayOfWeek::Enum dayOfWeek);
311
312 /// Return `true` if the specified `yyyymmddValue` represents a valid
313 /// `Date` value in the "YYYYMMDD" format, and `false` otherwise.
314 static bool isValidYYYYMMDD(int yyyymmddValue);
315
316 /// Return the latest date in the specified `month` of the specified
317 /// `year`. The behavior is undefined unless `1 <= year <= 9999` and
318 /// `1 <= month <= 12`.
319 static Date lastDayInMonth(int year, int month);
320
321 /// Return the latest date in the specified `month` of the specified
322 /// `year` that falls on the specified `dayOfWeek`. The behavior is
323 /// undefined unless `1 <= year <= 9999` and `1 <= month <= 12`.
324 static Date lastDayOfWeekInMonth(int year,
325 int month,
326 DayOfWeek::Enum dayOfWeek);
327
328 /// Return the first date *after* the specified `date` that falls on the
329 /// specified `dayOfWeek`. The behavior is undefined unless the
330 /// resulting date is no later than 9999/12/31.
331 static Date nextDayOfWeek(DayOfWeek::Enum dayOfWeek, const Date& date);
332
333 /// Return the first date *on* or *after* the specified `date` that
334 /// falls on the specified `dayOfWeek`. The behavior is undefined
335 /// unless the resulting date is no later than 9999/12/31.
337 const Date& date);
338
339 /// Return the date in the specified `month` of the specified `year`
340 /// corresponding to the specified `n`th occurrence of the specified
341 /// `dayOfWeek`. If `n < 0`, return the date corresponding to the
342 /// `-n`th occurrence of the `dayOfWeek` counting from the end of the
343 /// `month` towards the first of the `month`. If `5 == n` and a result
344 /// cannot be found in `month`, then return the date of the first
345 /// `dayOfWeek` in the following month. If `-5 == n` and a result
346 /// cannot be found in `month`, then return the date of the last
347 /// `dayOfWeek` in the previous month. The behavior is undefined unless
348 /// `1 <= year <= 9999`, `1 <= month <= 12`, `n != 0`, `-5 <= n <= 5`,
349 /// and the resulting date is neither earlier than 0001/01/01 nor later
350 /// than 9999/12/31.
351 ///
352 /// For example:
353 /// @code
354 /// nthDayOfWeekInMonth(2004, 11, DayOfWeek::e_THURSDAY, 4);
355 /// @endcode
356 /// returns November 25, 2004, the fourth Thursday in November, 2004.
357 static Date nthDayOfWeekInMonth(int year,
358 int month,
359 DayOfWeek::Enum dayOfWeek,
360 int n);
361
362 /// Return the last date *before* the specified `date` that falls on the
363 /// specified `dayOfWeek`. The behavior is undefined unless the
364 /// resulting date is no earlier than 1/1/1.
365 static Date previousDayOfWeek(DayOfWeek::Enum dayOfWeek, const Date& date);
366
367 /// Return the last date *on* or *before* the specified `date` that
368 /// falls on the specified `dayOfWeek`. The behavior is undefined
369 /// unless the resulting date is no earlier than 1/1/1.
371 const Date& date);
372};
373
374// ============================================================================
375// INLINE DEFINITIONS
376// ============================================================================
377
378 // ---------------
379 // struct DateUtil
380 // ---------------
381
382// CLASS METHODS
383inline
384Date DateUtil::addMonths(const Date& original, int numMonths, bool eomFlag)
385{
386
387 return eomFlag ? addMonthsEom(original, numMonths)
388 : addMonthsNoEom(original, numMonths);
389}
390
391inline
392Date DateUtil::addYears(const Date& original, int numYears, bool eomFlag)
393{
394
395 return eomFlag ? addYearsEom(original, numYears)
396 : addYearsNoEom(original, numYears);
397}
398
399inline
400Date DateUtil::addYearsEom(const Date& original, int numYears)
401{
402 BSLS_REVIEW( 1 <= original.year() + numYears);
403 BSLS_REVIEW(9999 >= original.year() + numYears);
404
405 if (2 == original.month() && 28 <= original.day()) {
406 return addYearsEomEndOfFebruary(original, numYears); // RETURN
407 }
408 return Date(original.year() + numYears, original.month(), original.day());
409}
410
411inline
412Date DateUtil::addYearsNoEom(const Date& original, int numYears)
413{
414 BSLS_REVIEW( 1 <= original.year() + numYears);
415 BSLS_REVIEW(9999 >= original.year() + numYears);
416
417 const int newYear = original.year() + numYears;
418
419 if (2 == original.month() && 29 == original.day()) {
420 return Date(newYear,
421 original.month(),
422 SerialDateImpUtil::isLeapYear(newYear) ? 29 : 28);
423 // RETURN
424
425 }
426 return Date(newYear, original.month(), original.day());
427}
428
429inline
430int DateUtil::convertFromYYYYMMDD(Date *result, int yyyymmddValue)
431{
432 BSLS_REVIEW(result);
433
434 if (!isValidYYYYMMDD(yyyymmddValue)) {
435 return 1; // RETURN
436 }
437 *result = convertFromYYYYMMDDRaw(yyyymmddValue);
438
439 return 0;
440}
441
442inline
444{
445 BSLS_ASSERT_SAFE(isValidYYYYMMDD(yyyymmddValue));
446
447 return Date(yyyymmddValue / 10000,
448 (yyyymmddValue / 100) % 100,
449 yyyymmddValue % 100);
450}
451
452inline
454{
455 return date.year() * 10000 + date.month() * 100 + date.day();
456}
457
458inline
460 int month,
461 DayOfWeek::Enum dayOfWeek)
462{
463 BSLS_ASSERT_SAFE(1 <= year); BSLS_ASSERT_SAFE(year <= 9999);
464 BSLS_ASSERT_SAFE(1 <= month); BSLS_ASSERT_SAFE(month <= 12);
465
466 return nextDayOfWeekInclusive(dayOfWeek, Date(year, month, 1));
467}
468
469inline
470bool DateUtil::isValidYYYYMMDD(int yyyymmddValue)
471{
472 const int day = yyyymmddValue % 100;
473 yyyymmddValue /= 100;
474 const int month = yyyymmddValue % 100;
475
476 return SerialDateImpUtil::isValidYearMonthDay(yyyymmddValue / 100,
477 month,
478 day);
479}
480
481inline
482Date DateUtil::lastDayInMonth(int year, int month)
483{
484 BSLS_REVIEW(1 <= year); BSLS_REVIEW(year <= 9999);
485 BSLS_REVIEW(1 <= month); BSLS_REVIEW(month <= 12);
486
487 return Date(year,
488 month,
490}
491
492} // close package namespace
493
494
495#endif
496
497// ----------------------------------------------------------------------------
498// Copyright 2016 Bloomberg Finance L.P.
499//
500// Licensed under the Apache License, Version 2.0 (the "License");
501// you may not use this file except in compliance with the License.
502// You may obtain a copy of the License at
503//
504// http://www.apache.org/licenses/LICENSE-2.0
505//
506// Unless required by applicable law or agreed to in writing, software
507// distributed under the License is distributed on an "AS IS" BASIS,
508// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
509// See the License for the specific language governing permissions and
510// limitations under the License.
511// ----------------------------- END-OF-FILE ----------------------------------
512
513/** @} */
514/** @} */
515/** @} */
Definition bdlt_date.h:294
int day() const
Return the day of the month in the range [1 .. 31] of this date.
Definition bdlt_date.h:927
int year() const
Return the year in the range [1 .. 9999] of this date.
Definition bdlt_date.h:977
int month() const
Return the month of the year in the range [1 .. 12] of this date.
Definition bdlt_date.h:965
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1762
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_REVIEW(X)
Definition bsls_review.h:949
Definition bbldc_basicisma30360.h:112
Definition bdlt_dateutil.h:206
static Date addYears(const Date &original, int numYears, bool eomFlag)
Definition bdlt_dateutil.h:392
static int convertToYYYYMMDD(const Date &date)
Definition bdlt_dateutil.h:453
static Date nthDayOfWeekInMonth(int year, int month, DayOfWeek::Enum dayOfWeek, int n)
static Date addMonthsEom(const Date &original, int numMonths)
static Date convertFromYYYYMMDDRaw(int yyyymmddValue)
Definition bdlt_dateutil.h:443
static int convertFromYYYYMMDD(Date *result, int yyyymmddValue)
Definition bdlt_dateutil.h:430
static Date lastDayInMonth(int year, int month)
Definition bdlt_dateutil.h:482
static Date addYearsEom(const Date &original, int numYears)
Definition bdlt_dateutil.h:400
static Date addMonths(const Date &original, int numMonths, bool eomFlag)
Definition bdlt_dateutil.h:384
static Date lastDayOfWeekInMonth(int year, int month, DayOfWeek::Enum dayOfWeek)
static Date previousDayOfWeek(DayOfWeek::Enum dayOfWeek, const Date &date)
static Date addYearsNoEom(const Date &original, int numYears)
Definition bdlt_dateutil.h:412
static Date previousDayOfWeekInclusive(DayOfWeek::Enum dayOfWeek, const Date &date)
static Date nextDayOfWeek(DayOfWeek::Enum dayOfWeek, const Date &date)
static bool isValidYYYYMMDD(int yyyymmddValue)
Definition bdlt_dateutil.h:470
static Date addMonthsNoEom(const Date &original, int numMonths)
static Date earliestDayOfWeekInMonth(int year, int month, DayOfWeek::Enum dayOfWeek)
Definition bdlt_dateutil.h:459
static Date nextDayOfWeekInclusive(DayOfWeek::Enum dayOfWeek, const Date &date)
Enum
Enumerated day-of-week values.
Definition bdlt_dayofweek.h:123
static bool isValidYearMonthDay(int year, int month, int day)
Definition bdlt_posixdateimputil.h:742
static bool isLeapYear(int year)
Definition bdlt_posixdateimputil.h:726
static int lastDayOfMonth(int year, int month)