XDate
XDate includes implementation of the classesCGregorianDate, CIsoDate, and CFiscalDate. Please click on the following links for more information:
- CGregorianDate: manipulating dates in the Gregorian calendar
- CIsoDate: manipulating ISO-8601 dates; and XDateCalc, a calculator to display Gregorian and ISO dates
- CFiscalDate: manipulating fiscal dates, weeks, quarters, and years; and XFisCal, a program that lets you create a printable fiscal calendar
CIsoDate
In modern times, there have been several attempts to standardize the formatting of dates. The most successful of these efforts is ISO 8601. This comprehensive standard is now widely used in timestamping documents, log files, emails, and other computer-generated files. It also introduced what has been called the ISO date/time, which is actually a set of rules for the representation of dates and times.Because of the complexity of ISO 8601, there have been some attempts to define a subset, or "profile", of ISO 8601, such as W3C Date and Time Formats. Among other things, the W3C effort tries to eliminate ambiguities by requiring a 4-digit year (YYYY) in all cases.
The ISO 8601 standard can be found here and here. The key characteristics of ISO date formatting are:
- YYYY-MM-DD - also known as big-endian date notation, this is the most common ISO 8601 date format; see ISO 8601 ¶4.1.2.2.
-
ISO 8601 week date formats -
While ISO 8601 specifies many formats that use the Gregorian calendar, it also introduces an entirely new date representation called
ISO weeks. You
can read the details in ISO 8601, ¶2.2.10 and ¶3.2.2.
In the ISO 8601 system of calendar weeks, there can be 52 or 53 weeks in an ISO 8601 year. The first week of the ISO year (just like all ISO weeks) begins on a Monday, and specifically includes January 4 (ISO 8601 ¶3.2.2). ISO 8601 week dates can be represented by YYYY-Www-D, where YYYY is the ISO year, ww is the 2-digit week number( 1..53), and D is the day number (1..7) within the week (Monday = 1, Sunday = 7). Thus, an ISO year may include up to three days from the preceding Gregorian year (if January 4 falls on a Sunday). In the same way, the end of an ISO year may include up to three days from the following Gregorian year. Example of this format: 1994-W52-7, which is January 1, 1995.
- ISO 8601 ordinal dates - Another ISO 8601 date format is YYYY-DDD, where YYYY is the Gregorian calendar year and DDD is the sequential day number (1..366) within the year. ISO 8601 (see ¶4.1.3ff) calls this an ordinal date. Example of this format: 1985-102. Ordinal dates should not be confused with Julian dates. See also: ¶3.2.1, Table 1.
- 20090317
- 2009-03-17
- 2009-03
- 2009076
- 2009-076
- 2009W122
- 2009-W12-2
XDate.h
The file XDate.h includes implementation of the classesCGregorianDate, CIsoDate, and CFiscalDate. This article discusses
CIsoDate; Parts 1 and 3 discuss CGregorianDate and
CFiscalDate.
At the end of this article, there is a list of
CIsoDate class members.
CIsoDate implements a class based on ISO 8601 date formats. Its data members are:
//=============================================================================
// Data
//=============================================================================
private:
// Note that all w-d-y values are one-based.
int week; // 1..52 or 53
int day; // 1..7
int year; // 1583..INT_MAX
Whereas CGregorianDate function parameters are typically month-day-year (MDY),
CIsoDate is based on week-day-year (WDY).
CIsoDate has constructors for the following date types:
week-day-yearCGregorianDate objectordinal date YYYYDDDSYSTEMTIMEtime_t
CIsoDate implements overloaded math operators for +, -, ++, --, +=, and -=, as well as logical compare operators ==, !=, <, >, <=, and >=.
CIsoDate Construction
Examples of CIsoDate construction:
-
Construction from Gregorian date MM/DD/YYYY
CIsoDate id; id.SetFromGregorian(3, 17, 2009); -
Construction from ISO date WW/DD/YYYY
CIsoDate id(52, 2, 2009); or CIsoDate id; id.Set(52, 2, 2009); -
Construction from current time
CIsoDate id(CIsoDate::GetCurrentTime()); or CIsoDate id = CIsoDate::GetCurrentTime(); -
Construction from CGregorianDate object
CGregorianDate gd(3, 17, 2009); CIsoDate id(gd); or CIsoDate id; id = gd; -
Construction from ordinal date YYYYDDD
CIsoDate id(2009, 76);
-
Construction from SYSTEMTIME
SYSTEMTIME st; GetLocalTime(&st); CIsoDate id(st); -
Construction from time_t
time_t t; time(&t); CIsoDate id(t);
CIsoDate Usage
Once you have created aCIsoDate object, you can use class functions to find out if the date is an ISO long year (IsIsoYearLong()), get its Gregorian date (GetGregorian()), get its ordinal date (GetOrdinalDate()), and get its Julian day number (GetJulianDayNumber()). Of course, at any time you can retrieve the date information (GetDay(), GetWeek(), GetYear()), or check if the date is valid (IsValidDate()).
Example: Get Gregorian Date
To get the Gregorian date from an ISO date: // from XDateTestDlg.cpp
CIsoDate id1;
id1.Set(12, 2, 2009); // ISO week, day, year
id1.GetGregorian(m, d, y);
m_List.Printf(CXListBox::Black, CXListBox::White, 0,
_T("2009-W12-2 is %d-%d-%d"), y, m, d);
The above code produces this output:
2009-W12-2 is 2009-3-17
Example: Get ISO Week from Gregorian Date
To get the ISO week: // from XDateTestDlg.cpp
id1.SetFromGregorian(5, 1, 2009);
m_List.Printf(CXListBox::Black, CXListBox::White, 0,
_T("2009-5-1 is ISO week %d"), id1.GetWeek());
The above code produces this output:
2009-5-1 is ISO week 18
Example: Get ISO Date for 1st Day of Month
To get the ISO date for the 1st day of the months in 2009: // from XDateTestDlg.cpp
for (int i = 1; i <= 12; i++)
{
id1.SetFromGregorian(i, 1, 2009);
m_List.Printf(CXListBox::Black, CXListBox::White, 0,
_T("2009-%d-1 is %d-W%02d-%d"),
i, id1.GetYear(), id1.GetWeek(), id1.GetDay());
}
The above code produces this output:
2009-1-1 is 2009-W01-4
2009-2-1 is 2009-W05-7
2009-3-1 is 2009-W09-7
2009-4-1 is 2009-W14-3
2009-5-1 is 2009-W18-5
2009-6-1 is 2009-W23-1
2009-7-1 is 2009-W27-3
2009-8-1 is 2009-W31-6
2009-9-1 is 2009-W36-2
2009-10-1 is 2009-W40-4
2009-11-1 is 2009-W44-7
2009-12-1 is 2009-W49-2
Please see XDateTestDlg.cpp for more examples of how to use CIsoDate.
CIsoDate Date Formatting
CIsoDate::Format() differs from CGregorianDate::Format()
in the way these functions create the formatted date string. CGregorianDate::Format()
uses the C runtime function
strftime() to format the date. However, since the Microsoft version of strftime() does not yet support the ISO format specifiers as defined in
ISO/IEC 9899:1999, it was necessary to write a custom version of strftime() for CIsoDate. The CIsoDate::Format() function supports the following format specifiers:
| Use this | To get this output |
| %d | day of month as decimal number (01..31) |
| %g ‡ | ISO year without century, as decimal number (00..99) |
| %G ‡ | ISO year with century, as decimal number (1583...) |
| %j | day of year as decimal number (001..366) |
| %m | month as decimal number (01..12) |
| %u ‡ | ISO weekday as decimal number (1..7; Monday is 1) |
| %V ‡ | ISO week of year as decimal number (01..53) |
| %y | Gregorian year without century, as decimal number (00..99) |
| %Y | Gregorian year with century, as decimal number (1583...) |
| %% | % |
The # flag may prefix any of the above format specifiers, to indicate that leading zeros should be suppressed.
CIsoDate Debugging
CIsoDate provides the following debugging facilities:
-
virtual void Trace(LPCTSTR lpszMsg = NULL) const - This virtual function can be called anytime to write the week, day, and year, along with an optional message, to
OutputDebugString(). The non-MFC XTrace.h is used to write the output when_DEBUGis defined, just like MFC's TRACE. To enable this, un-comment the line that is highlighted below://============================================================================= // TRACE output //============================================================================= // if you want to see the TRACE output, uncomment this line: //#define XDATE_ENABLE_TRACE #undef TRACE_XDATE #ifdef XDATE_ENABLE_TRACE #include "XTrace.h" // non-MFC TRACE #define TRACE_XDATE TRACE #else #define TRACE_XDATE __noop #endif -
virtual void AssertValid() const - This virtual function can be called anytime to verify the date and display a diagnostic message via
_ASSERTE(when_DEBUGis defined). - virtual void Dump() const - This virtual function may be overriden to provide custom debug output.
If you want to use the CIsoDate Trace facility, don't forget to un-comment the line shown above, and also include XTrace.h in your project directory.
XDateTest
The demo application XDateTest.exe tests the various features and APIs of the XDate classes:
XDateCalc
The demo application XDateCalc.exe shows howCGregorianDate and CIsoDate can be used to calculate various date values:
When a date is selected by clicking a date on the calendar or by entering it in the edit box, the fields on the right are updated to show the date in different calendar systems.
How To Use
To integrate XDate into your own program, you first need to add XDate.h to your project.
Next, include XDate.h in the module
where you want to use the XDate classes.
If you want to use the CIsoDate Trace facility, also include XTrace.h in your project directory.
For more details on how to use, please see XDateTestDlg.cpp.
CIsoDate Class Members
| Construction | ||
| CIsoDate() | Default constructor | |
| CIsoDate(int w, int d, int y) | Construction from week, day, year | |
| CIsoDate(const CIsoDate& id) | Copy constructor | |
| CIsoDate(const CGregorianDate& gd) | Construction from a CGregorianDate | |
| CIsoDate(int y, int d) | Ordinal date YYYYDDD | |
| CIsoDate(time_t t) | C runtime; seconds since 1 Jan 1970 | |
| CIsoDate(const SYSTEMTIME& SystemTime) | System SYSTEMTIME date | |
Assignment |
||
| CIsoDate& operator=(const CIsoDate& id) | CIsoDate object | |
| CIsoDate& operator=(const CGregorianDate& gd) | CGregorianDate object | |
| CIsoDate& operator=(const time_t& t) | C runtime; seconds since 1 Jan 1970 | |
| CIsoDate& operator=(const SYSTEMTIME& SystemTime) | System SYSTEMTIME date | |
Attributes |
||
| int GetCentury() | Returns century; eg, returns 19 for 1985. | |
| static CIsoDate GetCurrentTime() | Returns a CIsoDate object that represents the current time. | |
| int GetDay() const | Returns current day of week (1..7). | |
| bool GetGregorian(int& m, int& d, int& y) const | Returns the current date in mdy. Returns true if date is valid. | |
| bool GetIso(int& w, int& d, int& y) const | Returns the current as wdy. Returns true if current date is valid. | |
| int GetJulianDayNumber() | Returns the current date as a Julian day number. | |
| bool GetOrdinalDate(int& y, int& d) const | Returns the current date as an ordinal date YYYY-DDD. Returns true if date is valid. | |
| bool GetSystemTime(SYSTEMTIME& SystemTime) const | Returns SYSTEMTIME value for current date. | |
| int GetWeek() const | Returns current ISO week (1..53). | |
| int GetYear() const | Returns current ISO year (1583..INT_MAX) | |
| int GetYearWithoutCentury() const | Returns year without century; eg, returns 85 for 1985. | |
| static bool IsIsoYearLong(int y) | Returns true if y is a long year (53 weeks). | |
| bool IsIsoYearLong() const | Returns true if current year is long (53 weeks). | |
| static bool IsValidDate(int w, int d, int y) | Returns true if wdy is a valid date, false if not. | |
| bool IsValidDate() const | Returns true if current date is a valid date, false if not. | |
| bool Set(int w, int d, int y) | Sets the current week, day, and year. Returns true if date is valid | |
| void SetDay(int d) | Set current day to d. | |
| bool SetFromGregorian(int m, int d, int y) | Sets the date from mdy. Returns true if date is valid. | |
| bool SetFromJulianDayNumber(int jdn) | Sets the date from the Julian day number jdn. Returns true if date is valid. | |
| bool SetFromOrdinalDate(int y, int d) | Sets the date from the ordinal date. Returns true if date is valid. | |
| bool SetFromSystemTime(const SYSTEMTIME& SystemTime) | Sets the current date to the date represented by the SYSTEMTIME SystemTime. Returns true if date is valid. | |
| bool SetFromSystemTime() | Sets the current date to the date returned by the system function GetLocalTime(). Returns true if date is valid. | |
| void SetWeek(int w) | Set current week to w. | |
| void SetYear(int y) | Set current year to y. | |
Logical Operators |
||
| bool operator==(const CIsoDate& rhs) const | Returns true if dates are equal. | |
| bool operator!=(const CIsoDate& rhs) const | Returns true if dates are not equal. | |
| bool operator<(const CIsoDate& rhs) const | Returns true if lhs is less than rhs. | |
| bool operator>(const CIsoDate& rhs) const | Returns true if lhs is greater than rhs. | |
| bool operator<=(const CIsoDate& rhs) const | Returns true if lhs is less than or equal to rhs. | |
| bool operator>=(const CIsoDate& rhs) const | Returns true if lhs is greater than or equal to rhs | |
Math Operators |
||
| CIsoDate& operator+(int days) | Add days to current date. | |
| CIsoDate& operator-(int days) | Subtract days from current date. | |
| CIsoDate& operator+=(int days) | Add days to current date. | |
| CIsoDate& operator-=(int days) | Subtract days from current date. | |
| CIsoDate& operator++() | Add one day to current date (prefix). | |
| CIsoDate& operator--() | Subtract one day from current date (prefix). | |
| CIsoDate& operator++(int) | Add one day to current date (postfix). | |
| CIsoDate& operator--(int) | Subtract one day from current date (postfix). | |
Operations |
||
| bool AddDays(int n) | Add n days to current date. Returns true if resulting date is valid. | |
| bool AddWeeks(int n) | Add n weeks to current date. Returns true if resulting date is valid. | |
| bool AddYears(int n) | Add n years to current date. Returns true if resulting date is valid. | |
| size_t Format(LPTSTR lpszDest, size_t maxsize, LPCTSTR format) const | Formats the current date with the formatting specifiers contained in the format parameter. The date string is returned in lpszDest. Its size is returned by Format() See code for details. | |
Dump/Trace |
||
| virtual void AssertValid() const | Virtual function. By default returns true if current date is valid. | |
| virtual void Dump() const | Virtual function. By default outputs the current date using OutputDebugString(). | |
| virtual void Trace(LPCTSTR lpszMsg = NULL) const | Virtual function. By default outputs an optional message and the current date using OutputDebugString(). | |
References
- The ISO 8601 standard can be found here and here.
- Wikipedia has some background on ISO 8601 here.
- A summary of the international standard date and time notation by Markus Kuhn
- Date and Time Formats, web site maintained by JR Stockton. Comprehensive and accurate discussion of date systems and formats.
- The Hermetic Systems web site has many articles discussing dates and calendars. Very informative.
- The ISO/IEC 9899:1999 Standard for the C Programming Language defines new strftime() format specifiers for ISO dates. A draft version can be found here. The Microsoft strftime() function, which does not include the new ISO format specifiers, is documented here.
Revision History
Version 1.0 - 2009 April 29
- Initial release
Buy latest version
| Buy XDate 1.0 license – $30.00 per developer. Includes full source code to XDateCalc.exe, XFisCal.exe, and XDateTest.exe. |