BDE 4.14.0 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
413/// `0001/01/01` (`9999/12/31`). Note that all of the functions, whether or
414/// not implemented in terms of a static cache, are stateless, and, as such,
415/// are inherently thread-safe.
417
418 private:
419 // PRIVATE TYPES
420 struct YearMonthDay {
421 short d_year;
422 char d_month;
423 char d_day;
424 };
425
426 enum {
427 k_MAX_SERIAL_DATE = 3652059
428 };
429
430 // PRIVATE CLASS DATA
431 static const int s_firstCachedYear;
432 static const int s_lastCachedYear;
433 static const int s_firstCachedSerialDate;
434 static const int s_lastCachedSerialDate;
435 static const int s_cachedSerialDate[][13];
436 static const YearMonthDay s_cachedYearMonthDay[];
437 static const char s_cachedDaysInMonth[][13];
438
439 public:
440 // CLASS METHODS
441
442 /// Return `true` if the specified `year` is a leap year, and `false`
443 /// otherwise. The behavior is undefined unless `1 <= year <= 9999`.
444 static bool isLeapYear(int year);
445
446 /// Return the last day of the specified `month` in the specified
447 /// `year`. The behavior is undefined unless `1 <= year <= 9999` and
448 /// `1 <= month <= 12`. Note that the value returned will be in the
449 /// range `[28 .. 31]`.
450 static int lastDayOfMonth(int year, int month);
451
452 /// Return the number of leap years occurring between the specified
453 /// `year1` and `year2`, inclusive. The behavior is undefined unless
454 /// `1 <= year1 <= 9999`, `1 <= year2 <= 9999`, and `year1 <= year2`.
455 static int numLeapYears(int year1, int year2);
456
457 // Is Valid Date
458
459 /// Return `true` if the specified `serialDay` represents a valid date
460 /// value, and `false` otherwise. Note that valid date values are (as
461 /// fully defined in the component-level documentation) in the range
462 /// `[1 .. 3652059]`.
463 static bool isValidSerial(int serialDay);
464
465 /// Return `true` if the specified `year` and `dayOfYear` represents a
466 /// valid date value, and `false` otherwise. Note that valid date
467 /// values are (as fully defined in the component-level documentation)
468 /// in the range `[0001/01 .. 9999/366]`.
469 static bool isValidYearDay(int year, int dayOfYear);
470
471 /// Return `true` if the specified `year`, `month`, and `day` represents
472 /// a valid date value, and `false` otherwise. Note that valid date
473 /// values are (as fully defined in the component-level documentation)
474 /// in the range `[0001/01/01 .. 9999/12/31]`.
475 static bool isValidYearMonthDay(int year, int month, int day);
476
477 /// Return `true` if the specified `year`, `month`, and `day` represents
478 /// a valid date value, and `false` otherwise. Note that valid date
479 /// values are (as fully defined in the component-level documentation)
480 /// in the range `[0001/01/01 .. 9999/12/31]`. Also note that this
481 /// function is guaranteed not to use any date-cache optimizations.
482 static bool isValidYearMonthDayNoCache(int year, int month, int day);
483
484 // To Serial Date (s)
485
486 /// Return the serial date representation of the date value indicated by
487 /// the specified `year` and `dayOfYear`. The behavior is undefined
488 /// unless `isValidYearDay(year, dayOfYear)` returns `true`.
489 static int ydToSerial(int year, int dayOfYear);
490
491 /// Return the serial date representation of the date value indicated by
492 /// the specified `year`, `month`, and `day`. The behavior is undefined
493 /// unless `isValidYearMonthDay(year, month, day)` returns `true`.
494 static int ymdToSerial(int year, int month, int day);
495
496 /// Return the serial date representation of the date value indicated by
497 /// the specified `year`, `month`, and `day`. The behavior is undefined
498 /// unless `isValidYearMonthDay(year, month, day)` returns `true`. Note
499 /// that this function is guaranteed not to use any date-cache
500 /// optimizations.
501 static int ymdToSerialNoCache(int year, int month, int day);
502
503 // To Day-Of-Year Date (yd)
504
505 /// Return the day of the year of the date value indicated by the
506 /// specified `serialDay`. The behavior is undefined unless
507 /// `isValidSerial(serialDay)` returns `true`.
508 static int serialToDayOfYear(int serialDay);
509
510 /// Load, into the specified `year` and `dayOfYear`, the year-day
511 /// representation of the date value indicated by the specified
512 /// `serialDay`. The behavior is undefined unless
513 /// `isValidSerial(serialDay)` returns `true`.
514 static void serialToYd(int *year, int *dayOfYear, int serialDay);
515
516 /// Return the day of the year of the date value indicated by the
517 /// specified `year`, `month`, and `day`. The behavior is undefined
518 /// unless `isValidYearMonthDay(year, month, day)` returns `true`.
519 static int ymdToDayOfYear(int year, int month, int day);
520
521 // To Calendar Date (ymd)
522
523 /// Return the day (of the month) of the date value indicated by the
524 /// specified `serialDay`. The behavior is undefined unless
525 /// `isValidSerial(serialDay)` returns `true`.
526 static int serialToDay(int serialDay);
527
528 /// Return the day (of the month) of the date value indicated by the
529 /// specified `serialDay`. The behavior is undefined unless
530 /// `isValidSerial(serialDay)` returns `true`. Note that this function
531 /// is guaranteed not to use any date-cache optimizations.
532 static int serialToDayNoCache(int serialDay);
533
534 /// Return the month of the date value indicated by the specified
535 /// `serialDay`. The behavior is undefined unless
536 /// `isValidSerial(serialDay)` returns `true`.
537 static int serialToMonth(int serialDay);
538
539 /// Return the month of the date value indicated by the specified
540 /// `serialDay`. The behavior is undefined unless
541 /// `isValidSerial(serialDay)` returns `true`. Note that this function
542 /// is guaranteed not to use any date-cache optimizations.
543 static int serialToMonthNoCache(int serialDay);
544
545 /// Return the year of the date value indicated by the specified
546 /// `serialDay`. The behavior is undefined unless
547 /// `isValidSerial(serialDay)` returns `true`.
548 static int serialToYear(int serialDay);
549
550 /// Return the year of the date value indicated by the specified
551 /// `serialDay`. The behavior is undefined unless
552 /// `isValidSerial(serialDay)` returns `true`. Note that this function
553 /// is guaranteed not to use any date-cache optimizations.
554 static int serialToYearNoCache(int serialDay);
555
556 /// Load, into the specified `year`, `month`, and `day`, the date value
557 /// indicated by the specified `serialDay`. The behavior is undefined
558 /// unless `isValidSerial(serialDay)` returns `true`.
559 static void serialToYmd(int *year, int *month, int *day, int serialDay);
560
561 /// Load, into the specified `year`, `month`, and `day`, the date value
562 /// indicated by the specified `serialDay`. The behavior is undefined
563 /// unless `isValidSerial(serialDay)` returns `true`. Note that this
564 /// function is guaranteed not to use any date-cache-optimizations.
565 static void serialToYmdNoCache(int *year,
566 int *month,
567 int *day,
568 int serialDay);
569
570 /// Return the day (of the month) of the date value indicated by the
571 /// specified `year` and `dayOfYear`. The behavior is undefined unless
572 /// `isValidYearDay(year, dayOfYear)` returns `true`.
573 static int ydToDay(int year, int dayOfYear);
574
575 /// Load, into the specified `month` and `day`, the (partial) calendar
576 /// date representation of the date value indicated by the specified
577 /// `year` and `dayOfYear`. The behavior is undefined unless
578 /// `isValidYearDay(year, dayOfYear)` returns `true`.
579 static void ydToMd(int *month, int *day, int year, int dayOfYear);
580
581 /// Return the month of the date value indicated by the specified `year`
582 /// and `dayOfYear`. The behavior is undefined unless
583 /// `isValidYearDay(year, dayOfYear)` returns `true`.
584 static int ydToMonth(int year, int dayOfYear);
585
586 // To Day of Week '[SUN = 1, MON .. SAT]'
587
588 /// Return, as an integer (with `1 = SUN`, `2 = MON`, ..., `7 = SAT`),
589 /// the day (of the week) of the date value indicated by the specified
590 /// `serialDay`. The behavior is undefined unless
591 /// `isValidSerial(serialDay)` returns `true`.
592 static int serialToDayOfWeek(int serialDay);
593
594 /// Return, as an integer (with `1 = SUN`, `2 = MON`, ..., `7 = SAT`),
595 /// the day (of the week) of the date value indicated by the specified
596 /// `year` and `dayOfYear`. The behavior is undefined unless
597 /// `isValidYearDay(year, dayOfYear)` returns `true`.
598 static int ydToDayOfWeek(int year, int dayOfYear);
599
600 /// Return, as an integer (with `1 = SUN`, `2 = MON`, ..., `7 = SAT`),
601 /// the day (of the week) of the date value indicated by the specified
602 /// `year`, `month`, and `day`. The behavior is undefined unless
603 /// `isValidYearMonthDay(year, month, day)` returns `true`.
604 static int ymdToDayOfWeek(int year, int month, int day);
605};
606
607// ============================================================================
608// INLINE DEFINITIONS
609// ============================================================================
610
611 // ---------------------------
612 // struct ProlepticDateImpUtil
613 // ---------------------------
614
615// CLASS METHODS
616inline
618{
619 BSLS_REVIEW(1 <= year);
620 BSLS_REVIEW( year <= 9999);
621
622 // Note the relative probabilities, from most likely to least likely:
623 //: o Is not a leap year.
624 //: o Is not the turn of any century (e.g., is not 1900).
625 //: o Is a multiple of 400 (e.g., is 2000).
626
627 return 0 == year % 4 && (0 != year % 100 || 0 == year % 400);
628}
629
630 // Is Valid Date
631
632inline
634{
635 return static_cast<unsigned>(serialDay) - 1 < k_MAX_SERIAL_DATE;
636}
637
638inline
639bool ProlepticDateImpUtil::isValidYearMonthDay(int year, int month, int day)
640{
641 if (s_firstCachedYear <= year && year <= s_lastCachedYear) {
642 // Check 'month' and 'day'; the cache cannot catch out-of-range issues.
643
644 if (month < 1 || month > 12 || day < 1) {
645 return false; // RETURN
646 }
647
648 return day <= s_cachedDaysInMonth[year - s_firstCachedYear][month];
649 // RETURN
650 }
651 else {
652 return isValidYearMonthDayNoCache(year, month, day); // RETURN
653 }
654}
655
656 // To Day-Of-Year Date (yd)
657
658inline
660{
661 BSLS_REVIEW(isValidSerial(serialDay));
662
663 int dayOfYear, year;
664 serialToYd(&year, &dayOfYear, serialDay);
665 return dayOfYear;
666}
667
668 // To Calendar Date (ymd)
669
670inline
672{
673 BSLS_REVIEW(isValidSerial(serialDay));
674
675 int year, month, day;
676 serialToYmdNoCache(&year, &month, &day, serialDay);
677 return day;
678}
679
680inline
682{
683 BSLS_REVIEW(isValidSerial(serialDay));
684
685 int year, month, day;
686 serialToYmdNoCache(&year, &month, &day, serialDay);
687 return month;
688}
689
690inline
692{
693 BSLS_REVIEW(isValidSerial(serialDay));
694
695 int year, dayOfYear;
696 serialToYd(&year, &dayOfYear, serialDay);
697 return year;
698}
699
700inline
702 int *month,
703 int *day,
704 int serialDay)
705{
706 BSLS_REVIEW(year);
707 BSLS_REVIEW(month);
708 BSLS_REVIEW(day);
709 BSLS_REVIEW(isValidSerial(serialDay));
710
711 int dayOfYear;
712 serialToYd(year, &dayOfYear, serialDay);
713 ydToMd(month, day, *year, dayOfYear);
714}
715
716inline
717int ProlepticDateImpUtil::ydToDay(int year, int dayOfYear)
718{
719 BSLS_ASSERT_SAFE(isValidYearDay(year, dayOfYear));
720
721 int month, day;
722 ydToMd(&month, &day, year, dayOfYear);
723 return day;
724}
725
726inline
727int ProlepticDateImpUtil::ydToMonth(int year, int dayOfYear)
728{
729 BSLS_ASSERT_SAFE(isValidYearDay(year, dayOfYear));
730
731 int month, day;
732 ydToMd(&month, &day, year, dayOfYear);
733 return month;
734}
735
736 // To Day of Week '[SUN = 1, MON .. SAT]'
737
738inline
740{
741 BSLS_REVIEW(isValidSerial(serialDay));
742
743 // 0001/01/01 was a Monday (MON == 2).
744
745 return 1 + serialDay % 7;
746}
747
748inline
749int ProlepticDateImpUtil::ydToDayOfWeek(int year, int dayOfYear)
750{
751 BSLS_ASSERT_SAFE(isValidYearDay(year, dayOfYear));
752
753 return serialToDayOfWeek(ydToSerial(year, dayOfYear));
754}
755
756inline
757int ProlepticDateImpUtil::ymdToDayOfWeek(int year, int month, int day)
758{
759 BSLS_ASSERT_SAFE(isValidYearMonthDay(year, month, day));
760
761 return serialToDayOfWeek(ymdToSerial(year, month, day));
762}
763
764} // close package namespace
765
766
767#endif
768
769// ----------------------------------------------------------------------------
770// Copyright 2014 Bloomberg Finance L.P.
771//
772// Licensed under the Apache License, Version 2.0 (the "License");
773// you may not use this file except in compliance with the License.
774// You may obtain a copy of the License at
775//
776// http://www.apache.org/licenses/LICENSE-2.0
777//
778// Unless required by applicable law or agreed to in writing, software
779// distributed under the License is distributed on an "AS IS" BASIS,
780// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
781// See the License for the specific language governing permissions and
782// limitations under the License.
783// ----------------------------- END-OF-FILE ----------------------------------
784
785/** @} */
786/** @} */
787/** @} */
#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_prolepticdateimputil.h:416
static int numLeapYears(int year1, int year2)
static int serialToDayOfYear(int serialDay)
Definition bdlt_prolepticdateimputil.h:659
static int ydToDayOfWeek(int year, int dayOfYear)
Definition bdlt_prolepticdateimputil.h:749
static bool isValidSerial(int serialDay)
Definition bdlt_prolepticdateimputil.h:633
static int ymdToDayOfYear(int year, int month, int day)
static int ydToDay(int year, int dayOfYear)
Definition bdlt_prolepticdateimputil.h:717
static int serialToDayNoCache(int serialDay)
Definition bdlt_prolepticdateimputil.h:671
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:701
static int ydToMonth(int year, int dayOfYear)
Definition bdlt_prolepticdateimputil.h:727
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:639
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:617
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:681
static int serialToDayOfWeek(int serialDay)
Definition bdlt_prolepticdateimputil.h:739
static int serialToYearNoCache(int serialDay)
Definition bdlt_prolepticdateimputil.h:691
static int ymdToDayOfWeek(int year, int month, int day)
Definition bdlt_prolepticdateimputil.h:757
static bool isValidYearDay(int year, int dayOfYear)