.: Home :: Contact Us :.  
  



Hans Dietrich Software

free and licensed software

   

XDate

XDate includes implementation of the classes CGregorianDate, 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.
Here are some typical ISO date examples (all represent the same date):
  • 20090317
  • 2009-03-17
  • 2009-03
  • 2009076
  • 2009-076
  • 2009W122
  • 2009-W12-2

XDate.h

The file XDate.h includes implementation of the classes CGregorianDate, 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.
The classes contained in XDate.h do not handle time in any way; they do not store or convert time; only dates. They do not calculate Easter or any other civil or religious holiday. They do not deal with any calendar except Gregorian, Julian (in a limited way), and ISO 8601 (if you consider that a calendar). And they accept only dates after 1582 AD.

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-year
  • CGregorianDate object
  • ordinal date YYYYDDD
  • SYSTEMTIME
  • time_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 a CIsoDate 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...)
%% %
Defined in ISO/IEC 9899:1999 ¶7.23.3.5ff

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 _DEBUG is 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 _DEBUG is 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:

screenshot

XDateCalc

The demo application XDateCalc.exe shows how CGregorianDate and CIsoDate can be used to calculate various date values:

screenshot

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

Revision History

Version 1.0

  • 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.