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