BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlt_prolepticdateimputil.h
Go to the documentation of this file.
1/// @file bdlt_prolepticdateimputil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlt_prolepticdateimputil.h -*-C++-*-
8#ifndef INCLUDED_BDLT_PROLEPTICDATEIMPUTIL
9#define INCLUDED_BDLT_PROLEPTICDATEIMPUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlt_prolepticdateimputil bdlt_prolepticdateimputil
15/// @brief Provide low-level support functions for date-value manipulation.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlt
19/// @{
20/// @addtogroup bdlt_prolepticdateimputil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlt_prolepticdateimputil-purpose"> Purpose</a>
25/// * <a href="#bdlt_prolepticdateimputil-classes"> Classes </a>
26/// * <a href="#bdlt_prolepticdateimputil-description"> Description </a>
27/// * <a href="#bdlt_prolepticdateimputil-representations-valid-dates-and-leap-years"> Representations, Valid Dates, and Leap Years </a>
28/// * <a href="#bdlt_prolepticdateimputil-caching"> Caching </a>
29/// * <a href="#bdlt_prolepticdateimputil-usage"> Usage </a>
30/// * <a href="#bdlt_prolepticdateimputil-example-1-use-as-a-general-purpose-utility"> Example 1: Use as a General Purpose Utility </a>
31/// * <a href="#bdlt_prolepticdateimputil-example-2-implement-a-value-semantic-date-type"> Example 2: Implement a Value-Semantic Date Type </a>
32///
33/// # Purpose {#bdlt_prolepticdateimputil-purpose}
34/// Provide low-level support functions for date-value manipulation.
35///
36/// # Classes {#bdlt_prolepticdateimputil-classes}
37///
38/// - bdlt::ProlepticDateImpUtil: low-level date-related stateless functions
39///
40/// @see bdlt_date
41///
42/// # Description {#bdlt_prolepticdateimputil-description}
43/// This component provides a utility `struct`,
44/// `bdlt::ProlepticDateImpUtil`, that defines a suite of low-level,
45/// date-related functions, which can be used to validate, manipulate, and
46/// convert among values in three different formats:
47/// @code
48/// YMD: year/month/day date
49/// YD: year/day-of-year date
50/// S: serial date
51/// @endcode
52/// The supplied functionality can also be used (e.g.) for determining leap
53/// years, finding the last day in a given month, and for determining the day of
54/// the week for a given date. Note that in this component a "date" is
55/// understood to represent a valid day in the (YMD) range `0001/01/01` to
56/// `9999/12/31` according to the *proleptic* *Gregorian* *calendar*:
57/// @code
58/// http://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar
59/// @endcode
60///
61/// ## Representations, Valid Dates, and Leap Years {#bdlt_prolepticdateimputil-representations-valid-dates-and-leap-years}
62///
63///
64/// The "Calendar Date", or "year-month-day (ymd)", is the canonical
65/// representation and is denoted as "YYYY/MM/DD", with valid years being in the
66/// range `[1 .. 9999]`. Within a valid year, valid months and valid days are
67/// confined to the respective ranges `[1 .. 12]` and `[1 .. 31]`. Valid dates
68/// in this representation range from `0001/01/01` to `9999/12/31`, governed by
69/// the proleptic Gregorian calendar. Specifically, within the 4th, 6th, 9th,
70/// and 11th months (respectively, April, June, September, and November) of any
71/// year, valid days are in the range `[1 .. 30]`. Valid days for all other
72/// months of any year, with exception of the 2nd month (February), are in the
73/// range `[1 .. 31]`.
74///
75/// In a *leap* *year*, February has 29 days instead of the usual 28. Thus, the
76/// range of valid days for February in a leap year is `[1 .. 29]`; otherwise,
77/// the range of valid days for February is `[1 .. 28]`. The proleptic
78/// Gregorian calendar retroactively applies the leap year rules instituted by
79/// the Gregorian Reformation to all years. In particular, a year in the range
80/// `[1 .. 9999]` is a leap year if it is divisible by 4, but *not* divisible by
81/// 100, *unless* it is *also* divisible by 400. (Expressed conversely, all
82/// years *not* divisible by 4 are non-leap years, as are all century years
83/// *not* divisible by 400 (e.g., 1900).
84///
85/// The "Day-Of-Year Date", or "year-day (yd)" representation, denoted by
86/// "YYYY/DDD", represents dates by their year (again, in the range
87/// `[1 .. 9999]`) and the day of year, in the range `[1 .. 366]`. Valid date
88/// values in this representation range from `0001/001` to `9999/365`, with a
89/// day-of-year value of 366 permitted for leap years only.
90///
91/// The "Serial Date" representation depicts dates as consecutive integers
92/// beginning with 1 (representing `0001/01/01`). In this representation, valid
93/// date values are in the range `[1 .. 3652059]`, with 3652059 representing
94/// `9999/12/31`.
95///
96/// ## Caching {#bdlt_prolepticdateimputil-caching}
97///
98///
99/// To achieve maximal runtime performance, several of the functions in this
100/// component reserve the right to be implemented using statically cached (i.e.,
101/// tabulated, pre-calculated) values (which is inherently thread-safe). For
102/// all functions where a cache may be used, `bdlt::ProlepticDateImpUtil` also
103/// explicitly provides a `NoCache` version (e.g., `ymdToSerialNoCache`) that is
104/// guaranteed NOT to use a cache. Although the "normal" (potentially cached)
105/// functions typically gain huge performance advantages, the `NoCache` versions
106/// may conceivably be preferred by the performance-minded user who is
107/// *reasonably* *certain* that the vast majority of date values of interest
108/// will miss the cache (thus incurring a small, but unnecessary overhead for
109/// the cache-hit tests). Note, however, that the `NoCache` function variants
110/// are provided primarily for testing and for generating the cache in the first
111/// place (see this component's test driver).
112///
113/// ## Usage {#bdlt_prolepticdateimputil-usage}
114///
115///
116/// This section illustrates intended use of this component.
117///
118/// ### Example 1: Use as a General Purpose Utility {#bdlt_prolepticdateimputil-example-1-use-as-a-general-purpose-utility}
119///
120///
121/// The primary purpose of this component is to support the implementation of a
122/// general-purpose, value-semantic (vocabulary) "Date" type. However, it also
123/// provides many low-level utility functions suitable for direct use by other
124/// clients. In this example we employ several of the functions from this
125/// component to ask questions about particular dates in one of the three
126/// supported formats.
127///
128/// First, what day of the week was January 3, 2010?
129/// @code
130/// assert(2 == bdlt::ProlepticDateImpUtil::ymdToDayOfWeek(2010, 3, 1));
131/// // 2 means Monday.
132/// @endcode
133/// Then, was the year 2000 a leap year?
134/// @code
135/// assert(true == bdlt::ProlepticDateImpUtil::isLeapYear(2000));
136/// // Yes, it was.
137/// @endcode
138/// Next, was February 29, 1900 a valid date in history?
139/// @code
140/// assert(false == bdlt::ProlepticDateImpUtil::isValidYearMonthDay(1900,
141/// 2,
142/// 29));
143/// // No, it was not.
144/// @endcode
145/// Then, what was the last day of February in 1600?
146/// @code
147/// assert(29 == bdlt::ProlepticDateImpUtil::lastDayOfMonth(1600, 2));
148/// // The 29th.
149/// @endcode
150/// Next, how many leap years occurred from 1959 to 2012, inclusive?
151/// @code
152/// assert(14 == bdlt::ProlepticDateImpUtil::numLeapYears(1959, 2012));
153/// // There were 14.
154/// @endcode
155/// Now, on what day of the year will February 29, 2020 fall?
156/// @code
157/// assert(60 == bdlt::ProlepticDateImpUtil::ymdToDayOfYear(2020, 2, 29));
158/// // The 60th one.
159/// @endcode
160/// Finally, in what month did the 120th day of 2011 fall?
161/// @code
162/// assert(4 == bdlt::ProlepticDateImpUtil::ydToMonth(2011, 120));
163/// // 4 means April.
164/// @endcode
165///
166/// ### Example 2: Implement a Value-Semantic Date Type {#bdlt_prolepticdateimputil-example-2-implement-a-value-semantic-date-type}
167///
168///
169/// Using the functions supplied in this component, we can easily implement a
170/// C++ class that represents abstract (*mathematical*) date values and performs
171/// common operations on them. The internal representation could be any of the
172/// three supported by this component. In this example, we choose to represent
173/// the date value internally as a "serial date".
174///
175/// First, we define a partial interface of our date class, `MyDate`, omitting
176/// many methods, free operators, and `friend` declarations that do not
177/// contribute substantively to illustrating use of this component:
178/// @code
179/// /// This class represents a valid date, in the proleptic Gregorian
180/// /// calendar, in the range `[0001/01/01 .. 9999/12/31]`.
181/// class MyDate {
182///
183/// // DATA
184/// int d_serialDate; // 1 = 0001/01/01, 2 = 0001/01/02, etc.
185///
186/// // FRIENDS
187/// friend bool operator==(const MyDate&, const MyDate&);
188/// // ...
189///
190/// private:
191/// // PRIVATE CREATORS
192///
193/// /// Create a `MyDate` object initialized with the value indicated by
194/// /// the specified `serialDate`. The behavior is undefined unless
195/// /// `serialDate` represents a valid `MyDate` value.
196/// explicit MyDate(int serialDate);
197///
198/// public:
199/// // CLASS METHODS
200///
201/// /// Return `true` if the specified `year`, `month`, and `day`
202/// /// represent a valid value for a `MyDate` object, and `false`
203/// /// otherwise.
204/// static bool isValid(int year, int month, int day);
205///
206/// // CREATORS
207///
208/// /// Create a `MyDate` object having the earliest supported valid
209/// /// date value, i.e., "0001/01/01".
210/// MyDate();
211///
212/// /// Create a `MyDate` object having the value represented by the
213/// /// specified `year`, `month`, and `day`. The behavior is undefined
214/// /// unless `isValid(year, month, day)` returns `true`.
215/// MyDate(int year, int month, int day);
216///
217/// // ...
218///
219/// // MANIPULATORS
220///
221/// // ...
222///
223/// /// Set this `MyDate` object to have the value represented by the
224/// /// specified `year`, `month`, and `day`. The behavior is undefined
225/// /// unless `isValid(year, month, day)` returns `true`.
226/// void setYearMonthDay(int year, int month, int day);
227///
228/// // ACCESSORS
229///
230/// /// Load, into the specified `year`, `month`, and `day`, the
231/// /// individual attribute values of this `MyDate` object.
232/// void getYearMonthDay(int *year, int *month, int *day) const;
233///
234/// /// Return the day of the month in the range `[1 .. 31]` of this
235/// /// `MyDate` object.
236/// int day() const;
237///
238/// /// Return the month of the year in the range `[1 .. 12]` of this
239/// /// `MyDate` object.
240/// int month() const;
241///
242/// /// Return the year in the range `[1 .. 9999]` of this `MyDate`
243/// /// object.
244/// int year() const;
245///
246/// // ...
247/// };
248///
249/// // FREE OPERATORS
250///
251/// /// Return `true` if the specified `lhs` and `rhs` `MyDate` objects have
252/// /// the same value, and `false` otherwise. Two dates have the same
253/// /// value if each of the corresponding `year`, `month`, and `day`
254/// /// attributes respectively have the same value.
255/// bool operator==(const MyDate& lhs, const MyDate& rhs);
256///
257/// // ...
258/// @endcode
259/// Then, we provide an implementation of the `MyDate` methods and associated
260/// free operators declared above, using @ref bsls_assert to identify preconditions
261/// and invariants where appropriate. Note the use of various
262/// `bdlt::ProlepticDateImpUtil` functions in the code:
263/// @code
264/// // PRIVATE CREATORS
265/// inline
266/// MyDate::MyDate(int serialDate)
267/// : d_serialDate(serialDate)
268/// {
269/// BSLS_ASSERT_SAFE(bdlt::ProlepticDateImpUtil::isValidSerial(
270/// d_serialDate));
271/// }
272///
273/// // CLASS METHODS
274/// inline
275/// bool MyDate::isValid(int year, int month, int day)
276/// {
277/// return bdlt::ProlepticDateImpUtil::isValidYearMonthDay(year,
278/// month,
279/// day);
280/// }
281///
282/// // CREATORS
283/// inline
284/// MyDate::MyDate()
285/// : d_serialDate(1)
286/// {
287/// }
288///
289/// inline
290/// MyDate::MyDate(int year, int month, int day)
291/// : d_serialDate(bdlt::ProlepticDateImpUtil::ymdToSerial(year, month, day))
292/// {
293/// BSLS_ASSERT_SAFE(isValid(year, month, day));
294/// }
295///
296/// // ...
297///
298/// // MANIPULATORS
299///
300/// // ...
301///
302/// inline
303/// void MyDate::setYearMonthDay(int year, int month, int day)
304/// {
305/// BSLS_ASSERT_SAFE(isValid(year, month, day));
306///
307/// d_serialDate = bdlt::ProlepticDateImpUtil::ymdToSerial(year,
308/// month,
309/// day);
310/// }
311///
312/// // ACCESSORS
313/// inline
314/// void MyDate::getYearMonthDay(int *year, int *month, int *day) const
315/// {
316/// BSLS_ASSERT_SAFE(year);
317/// BSLS_ASSERT_SAFE(month);
318/// BSLS_ASSERT_SAFE(day);
319///
320/// bdlt::ProlepticDateImpUtil::serialToYmd(year,
321/// month,
322/// day,
323/// d_serialDate);
324/// }
325///
326/// inline
327/// int MyDate::day() const
328/// {
329/// return bdlt::ProlepticDateImpUtil::serialToDay(d_serialDate);
330/// }
331///
332/// inline
333/// int MyDate::month() const
334/// {
335/// return bdlt::ProlepticDateImpUtil::serialToMonth(d_serialDate);
336/// }
337///
338/// inline
339/// int MyDate::year() const
340/// {
341/// return bdlt::ProlepticDateImpUtil::serialToYear(d_serialDate);
342/// }
343///
344/// // FREE OPERATORS
345/// inline
346/// bool operator==(const MyDate& lhs, const MyDate& rhs)
347/// {
348/// return lhs.d_serialDate == rhs.d_serialDate;
349/// }
350/// @endcode
351/// Next, we illustrate basic use of our `MyDate` class, starting with the
352/// creation of a default object, `d1`:
353/// @code
354/// MyDate d1; assert( 1 == d1.year());
355/// assert( 1 == d1.month());
356/// assert( 1 == d1.day());
357/// @endcode
358/// Now, we set `d1` to July 4, 1776 via the `setYearMonthDay` method, but we
359/// first verify that it is a valid date using `isValid`:
360/// @code
361/// assert(MyDate::isValid(1776, 7, 4));
362/// d1.setYearMonthDay(1776, 7, 4); assert(1776 == d1.year());
363/// assert( 7 == d1.month());
364/// assert( 4 == d1.day());
365/// @endcode
366/// Finally, using the value constructor, we create `d2` to have the same value
367/// as `d1`:
368/// @code
369/// MyDate d2(1776, 7, 4); assert(1776 == d2.year());
370/// assert( 7 == d2.month());
371/// assert( 4 == d2.day());
372/// assert( d1 == d2);
373/// @endcode
374/// Note that equality comparison of `MyDate` objects is very efficient, being
375/// comprised of a comparison of two `int` values. Similarly, the `MyDate`
376/// methods and free operators (not shown) that add a (signed) number of days to
377/// a date are also very efficient. However, one of the trade-offs of storing a
378/// date internally as a serial value is that operations involving conversion
379/// among the serial value and one or more of the `year`, `month`, and `day`
380/// attributes (e.g., `setYearMonthDay`, `getYearMonthDay`) entail considerably
381/// more computation.
382/// @}
383/** @} */
384/** @} */
385
386/** @addtogroup bdl
387 * @{
388 */
389/** @addtogroup bdlt
390 * @{
391 */
392/** @addtogroup bdlt_prolepticdateimputil
393 * @{
394 */
395
396#include <bdlscm_version.h>
397
398#include <bsls_assert.h>
399#include <bsls_review.h>
400
401
402namespace bdlt {
403
404 // ===========================
405 // struct ProlepticDateImpUtil
406 // ===========================
407
408/// This `struct` provides a namespace for a suite of pure functions that
409/// perform low-level operations on date values in a variety of formats:
410/// year/month/day, year/day-of-year, and serial date. Dates in the range
411/// `[0001/01/01 .. 9999/12/31]` that are valid per the proleptic Gregorian
412/// calendar are supported, with serial date 1 (3652059) corresponding to `0001/01/01` (`9999/12/31`).
413///
414/// \note Note that all of the functions, whether or
415/// not implemented in terms of a static cache, are stateless, and, as such,
416/// are inherently thread-safe.
417///
418/// See @ref bdlt_prolepticdateimputil
420
421 private:
422 // PRIVATE TYPES
423 struct YearMonthDay {
424 short d_year;
425 char d_month;
426 char d_day;
427 };
428
429 enum {
430 k_MAX_SERIAL_DATE = 3652059
431 };
432
433 // PRIVATE CLASS DATA
434 static const int s_firstCachedYear;
435 static const int s_lastCachedYear;
436 static const int s_firstCachedSerialDate;
437 static const int s_lastCachedSerialDate;
438 static const int s_cachedSerialDate[][13];
439 static const YearMonthDay s_cachedYearMonthDay[];
440 static const char s_cachedDaysInMonth[][13];
441
442 public:
443 // CLASS METHODS
444
445 /// Return `true` if the specified `year` is a leap year, and `false` otherwise.
446 ///
447 /// \pre The behavior is undefined unless `1 <= year <= 9999`.
448 static bool isLeapYear(int year);
449
450 /// Return the last day of the specified `month` in the specified `year`.
451 ///
452 /// \pre The behavior is undefined unless `1 <= year <= 9999` and `1 <= month <= 12`.
453 ///
454 /// \note Note that the value returned will be in the
455 /// range `[28 .. 31]`.
456 static int lastDayOfMonth(int year, int month);
457
458 /// Return the number of leap years occurring between the specified `year1` and `year2`, inclusive.
459 ///
460 /// \pre The behavior is undefined unless
461 /// `1 <= year1 <= 9999`, `1 <= year2 <= 9999`, and `year1 <= year2`.
462 static int numLeapYears(int year1, int year2);
463
464 // Is Valid Date
465
466 /// Return `true` if the specified `serialDay` represents a valid date value, and `false` otherwise.
467 ///
468 /// \note Note that valid date values are (as
469 /// fully defined in the component-level documentation) in the range
470 /// `[1 .. 3652059]`.
471 static bool isValidSerial(int serialDay);
472
473 /// Return `true` if the specified `year` and `dayOfYear` represents a valid date value, and `false` otherwise.
474 ///
475 /// \note Note that valid date
476 /// values are (as fully defined in the component-level documentation)
477 /// in the range `[0001/01 .. 9999/366]`.
478 static bool isValidYearDay(int year, int dayOfYear);
479
480 /// Return `true` if the specified `year`, `month`, and `day` represents a valid date value, and `false` otherwise.
481 ///
482 /// \note Note that valid date
483 /// values are (as fully defined in the component-level documentation)
484 /// in the range `[0001/01/01 .. 9999/12/31]`.
485 static bool isValidYearMonthDay(int year, int month, int day);
486
487 /// Return `true` if the specified `year`, `month`, and `day` represents a valid date value, and `false` otherwise.
488 ///
489 /// \note Note that valid date
490 /// values are (as fully defined in the component-level documentation)
491 /// in the range `[0001/01/01 .. 9999/12/31]`. Also note that this
492 /// function is guaranteed not to use any date-cache optimizations.
493 static bool isValidYearMonthDayNoCache(int year, int month, int day);
494
495 // To Serial Date (s)
496
497 /// Return the serial date representation of the date value indicated by
498 /// the specified `year` and `dayOfYear`.
499 ///
500 /// \pre The behavior is undefined unless `isValidYearDay(year, dayOfYear)` returns `true`.
501 static int ydToSerial(int year, int dayOfYear);
502
503 /// Return the serial date representation of the date value indicated by
504 /// the specified `year`, `month`, and `day`.
505 ///
506 /// \pre The behavior is undefined unless `isValidYearMonthDay(year, month, day)` returns `true`.
507 static int ymdToSerial(int year, int month, int day);
508
509 /// Return the serial date representation of the date value indicated by
510 /// the specified `year`, `month`, and `day`.
511 ///
512 /// \pre The behavior is undefined unless `isValidYearMonthDay(year, month, day)` returns `true`.
513 ///
514 /// \note Note that this function is guaranteed not to use any date-cache
515 /// optimizations.
516 static int ymdToSerialNoCache(int year, int month, int day);
517
518 // To Day-Of-Year Date (yd)
519
520 /// Return the day of the year of the date value indicated by the specified `serialDay`.
521 ///
522 /// \pre The behavior is undefined unless
523 /// `isValidSerial(serialDay)` returns `true`.
524 static int serialToDayOfYear(int serialDay);
525
526 /// Load, into the specified `year` and `dayOfYear`, the year-day
527 /// representation of the date value indicated by the specified `serialDay`.
528 ///
529 /// \pre The behavior is undefined unless
530 /// `isValidSerial(serialDay)` returns `true`.
531 static void serialToYd(int *year, int *dayOfYear, int serialDay);
532
533 /// Return the day of the year of the date value indicated by the
534 /// specified `year`, `month`, and `day`.
535 ///
536 /// \pre The behavior is undefined unless `isValidYearMonthDay(year, month, day)` returns `true`.
537 static int ymdToDayOfYear(int year, int month, int day);
538
539 // To Calendar Date (ymd)
540
541 /// Return the day (of the month) of the date value indicated by the specified `serialDay`.
542 ///
543 /// \pre The behavior is undefined unless
544 /// `isValidSerial(serialDay)` returns `true`.
545 static int serialToDay(int serialDay);
546
547 /// Return the day (of the month) of the date value indicated by the specified `serialDay`.
548 ///
549 /// \pre The behavior is undefined unless `isValidSerial(serialDay)` returns `true`.
550 ///
551 /// \note Note that this function
552 /// is guaranteed not to use any date-cache optimizations.
553 static int serialToDayNoCache(int serialDay);
554
555 /// Return the month of the date value indicated by the specified `serialDay`.
556 ///
557 /// \pre The behavior is undefined unless
558 /// `isValidSerial(serialDay)` returns `true`.
559 static int serialToMonth(int serialDay);
560
561 /// Return the month of the date value indicated by the specified `serialDay`.
562 ///
563 /// \pre The behavior is undefined unless `isValidSerial(serialDay)` returns `true`.
564 ///
565 /// \note Note that this function
566 /// is guaranteed not to use any date-cache optimizations.
567 static int serialToMonthNoCache(int serialDay);
568
569 /// Return the year of the date value indicated by the specified `serialDay`.
570 ///
571 /// \pre The behavior is undefined unless
572 /// `isValidSerial(serialDay)` returns `true`.
573 static int serialToYear(int serialDay);
574
575 /// Return the year of the date value indicated by the specified `serialDay`.
576 ///
577 /// \pre The behavior is undefined unless `isValidSerial(serialDay)` returns `true`.
578 ///
579 /// \note Note that this function
580 /// is guaranteed not to use any date-cache optimizations.
581 static int serialToYearNoCache(int serialDay);
582
583 /// Load, into the specified `year`, `month`, and `day`, the date value
584 /// indicated by the specified `serialDay`.
585 ///
586 /// \pre The behavior is undefined unless `isValidSerial(serialDay)` returns `true`.
587 static void serialToYmd(int *year, int *month, int *day, int serialDay);
588
589 /// Load, into the specified `year`, `month`, and `day`, the date value
590 /// indicated by the specified `serialDay`.
591 ///
592 /// \pre The behavior is undefined unless `isValidSerial(serialDay)` returns `true`.
593 /// \note Note that this
594 /// function is guaranteed not to use any date-cache-optimizations.
595 static void serialToYmdNoCache(int *year,
596 int *month,
597 int *day,
598 int serialDay);
599
600 /// Return the day (of the month) of the date value indicated by the specified `year` and `dayOfYear`.
601 ///
602 /// \pre The behavior is undefined unless
603 /// `isValidYearDay(year, dayOfYear)` returns `true`.
604 static int ydToDay(int year, int dayOfYear);
605
606 /// Load, into the specified `month` and `day`, the (partial) calendar
607 /// date representation of the date value indicated by the specified `year` and `dayOfYear`.
608 ///
609 /// \pre The behavior is undefined unless
610 /// `isValidYearDay(year, dayOfYear)` returns `true`.
611 static void ydToMd(int *month, int *day, int year, int dayOfYear);
612
613 /// Return the month of the date value indicated by the specified `year` and `dayOfYear`.
614 ///
615 /// \pre The behavior is undefined unless
616 /// `isValidYearDay(year, dayOfYear)` returns `true`.
617 static int ydToMonth(int year, int dayOfYear);
618
619 // To Day of Week '[SUN = 1, MON .. SAT]'
620
621 /// Return, as an integer (with `1 = SUN`, `2 = MON`, ..., `7 = SAT`),
622 /// the day (of the week) of the date value indicated by the specified `serialDay`.
623 ///
624 /// \pre The behavior is undefined unless
625 /// `isValidSerial(serialDay)` returns `true`.
626 static int serialToDayOfWeek(int serialDay);
627
628 /// Return, as an integer (with `1 = SUN`, `2 = MON`, ..., `7 = SAT`),
629 /// the day (of the week) of the date value indicated by the specified `year` and `dayOfYear`.
630 ///
631 /// \pre The behavior is undefined unless
632 /// `isValidYearDay(year, dayOfYear)` returns `true`.
633 static int ydToDayOfWeek(int year, int dayOfYear);
634
635 /// Return, as an integer (with `1 = SUN`, `2 = MON`, ..., `7 = SAT`),
636 /// the day (of the week) of the date value indicated by the specified `year`, `month`, and `day`.
637 ///
638 /// \pre The behavior is undefined unless
639 /// `isValidYearMonthDay(year, month, day)` returns `true`.
640 static int ymdToDayOfWeek(int year, int month, int day);
641};
642
643// ============================================================================
644// INLINE DEFINITIONS
645// ============================================================================
646
647 // ---------------------------
648 // struct ProlepticDateImpUtil
649 // ---------------------------
650
651// CLASS METHODS
652inline
654{
655 BSLS_REVIEW(1 <= year);
656 BSLS_REVIEW( year <= 9999);
657
658 // Note the relative probabilities, from most likely to least likely:
659 //: o Is not a leap year.
660 //: o Is not the turn of any century (e.g., is not 1900).
661 //: o Is a multiple of 400 (e.g., is 2000).
662
663 return 0 == year % 4 && (0 != year % 100 || 0 == year % 400);
664}
665
666 // Is Valid Date
667
668inline
670{
671 return static_cast<unsigned>(serialDay) - 1 < k_MAX_SERIAL_DATE;
672}
673
674inline
675bool ProlepticDateImpUtil::isValidYearMonthDay(int year, int month, int day)
676{
677 if (s_firstCachedYear <= year && year <= s_lastCachedYear) {
678 // Check 'month' and 'day'; the cache cannot catch out-of-range issues.
679
680 if (month < 1 || month > 12 || day < 1) {
681 return false; // RETURN
682 }
683
684 return day <= s_cachedDaysInMonth[year - s_firstCachedYear][month];
685 // RETURN
686 }
687 else {
688 return isValidYearMonthDayNoCache(year, month, day); // RETURN
689 }
690}
691
692 // To Day-Of-Year Date (yd)
693
694inline
696{
697 BSLS_REVIEW(isValidSerial(serialDay));
698
699 int dayOfYear, year;
700 serialToYd(&year, &dayOfYear, serialDay);
701 return dayOfYear;
702}
703
704 // To Calendar Date (ymd)
705
706inline
708{
709 BSLS_REVIEW(isValidSerial(serialDay));
710
711 int year, month, day;
712 serialToYmdNoCache(&year, &month, &day, serialDay);
713 return day;
714}
715
716inline
718{
719 BSLS_REVIEW(isValidSerial(serialDay));
720
721 int year, month, day;
722 serialToYmdNoCache(&year, &month, &day, serialDay);
723 return month;
724}
725
726inline
728{
729 BSLS_REVIEW(isValidSerial(serialDay));
730
731 int year, dayOfYear;
732 serialToYd(&year, &dayOfYear, serialDay);
733 return year;
734}
735
736inline
738 int *month,
739 int *day,
740 int serialDay)
741{
742 BSLS_REVIEW(year);
743 BSLS_REVIEW(month);
744 BSLS_REVIEW(day);
745 BSLS_REVIEW(isValidSerial(serialDay));
746
747 int dayOfYear;
748 serialToYd(year, &dayOfYear, serialDay);
749 ydToMd(month, day, *year, dayOfYear);
750}
751
752inline
753int ProlepticDateImpUtil::ydToDay(int year, int dayOfYear)
754{
755 BSLS_ASSERT_SAFE(isValidYearDay(year, dayOfYear));
756
757 int month, day;
758 ydToMd(&month, &day, year, dayOfYear);
759 return day;
760}
761
762inline
763int ProlepticDateImpUtil::ydToMonth(int year, int dayOfYear)
764{
765 BSLS_ASSERT_SAFE(isValidYearDay(year, dayOfYear));
766
767 int month, day;
768 ydToMd(&month, &day, year, dayOfYear);
769 return month;
770}
771
772 // To Day of Week '[SUN = 1, MON .. SAT]'
773
774inline
776{
777 BSLS_REVIEW(isValidSerial(serialDay));
778
779 // 0001/01/01 was a Monday (MON == 2).
780
781 return 1 + serialDay % 7;
782}
783
784inline
785int ProlepticDateImpUtil::ydToDayOfWeek(int year, int dayOfYear)
786{
787 BSLS_ASSERT_SAFE(isValidYearDay(year, dayOfYear));
788
789 return serialToDayOfWeek(ydToSerial(year, dayOfYear));
790}
791
792inline
793int ProlepticDateImpUtil::ymdToDayOfWeek(int year, int month, int day)
794{
795 BSLS_ASSERT_SAFE(isValidYearMonthDay(year, month, day));
796
797 return serialToDayOfWeek(ymdToSerial(year, month, day));
798}
799
800} // close package namespace
801
802
803#endif
804
805// ----------------------------------------------------------------------------
806// Copyright 2014 Bloomberg Finance L.P.
807//
808// Licensed under the Apache License, Version 2.0 (the "License");
809// you may not use this file except in compliance with the License.
810// You may obtain a copy of the License at
811//
812// http://www.apache.org/licenses/LICENSE-2.0
813//
814// Unless required by applicable law or agreed to in writing, software
815// distributed under the License is distributed on an "AS IS" BASIS,
816// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
817// See the License for the specific language governing permissions and
818// limitations under the License.
819// ----------------------------- END-OF-FILE ----------------------------------
820
821/** @} */
822/** @} */
823/** @} */
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1917
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_REVIEW(X)
Definition bsls_review.h:1019
Definition bbldc_basicisma30360.h:112
Definition bdlt_prolepticdateimputil.h:419
static int numLeapYears(int year1, int year2)
static int serialToDayOfYear(int serialDay)
Definition bdlt_prolepticdateimputil.h:695
static int ydToDayOfWeek(int year, int dayOfYear)
Definition bdlt_prolepticdateimputil.h:785
static bool isValidSerial(int serialDay)
Definition bdlt_prolepticdateimputil.h:669
static int ymdToDayOfYear(int year, int month, int day)
static int ydToDay(int year, int dayOfYear)
Definition bdlt_prolepticdateimputil.h:753
static int serialToDayNoCache(int serialDay)
Definition bdlt_prolepticdateimputil.h:707
static int serialToYear(int serialDay)
static int lastDayOfMonth(int year, int month)
static void serialToYmdNoCache(int *year, int *month, int *day, int serialDay)
Definition bdlt_prolepticdateimputil.h:737
static int ydToMonth(int year, int dayOfYear)
Definition bdlt_prolepticdateimputil.h:763
static int serialToMonth(int serialDay)
static void serialToYd(int *year, int *dayOfYear, int serialDay)
static void serialToYmd(int *year, int *month, int *day, int serialDay)
static bool isValidYearMonthDay(int year, int month, int day)
Definition bdlt_prolepticdateimputil.h:675
static void ydToMd(int *month, int *day, int year, int dayOfYear)
static int ymdToSerialNoCache(int year, int month, int day)
static int ymdToSerial(int year, int month, int day)
static int serialToDay(int serialDay)
static bool isLeapYear(int year)
Definition bdlt_prolepticdateimputil.h:653
static int ydToSerial(int year, int dayOfYear)
static bool isValidYearMonthDayNoCache(int year, int month, int day)
static int serialToMonthNoCache(int serialDay)
Definition bdlt_prolepticdateimputil.h:717
static int serialToDayOfWeek(int serialDay)
Definition bdlt_prolepticdateimputil.h:775
static int serialToYearNoCache(int serialDay)
Definition bdlt_prolepticdateimputil.h:727
static int ymdToDayOfWeek(int year, int month, int day)
Definition bdlt_prolepticdateimputil.h:793
static bool isValidYearDay(int year, int dayOfYear)