
DTime+ v3.09 A Collection of Date and Time Classes
Description
DTime+ is a collection of classes & functions designed to ease the MFC
programmers’ burden when handling date and time values. If like me, having taken
a look at the built in MFC classes CTime and CTimeSpan or the OLE based
COleDateTime and COleDateTimeSpan classes, you decided they did not meet your
requirements, and you decided to write your own super-duper date and time
classes, but deadlines were looming, then look no further. The basis of the
algorithms for conversion from the Julian and Gregorian calendar to the
underlying storage was adopted from an article by Peter J.G. Meyer for the March
1993 issue of Dr Dobbs Journal. You can find the article online at
http://www.ddj.com/184408959. The algorithm used to determine the date of
Easter Sunday is taken from the book ‘Astronomical
Algorithms’ by Jean Meeus. The algorithms for the Moslem (Islamic)
calendar and the Hebrew calendar are provided by the book "Calendrical Calculations, The Millenium
Edition" by Edward M. Reingold and Nachum Dershowitz. Calendrical Calculations has always been a
favourite topic of the author and was in fact some of the first code which I
published on the web back in the mid 90's. Originally the code was shareware but
I've now decided to make it freeware in the hope that more people will find it
useful in their day to day projects.
Features
- The classes provided are implemented as a C++ template based class
framework.
- The code fully supports the Gregorian, Julian
and Moslem (Islamic) and Hebrew calendars. DTime+ also supports proleptic
versions of all of these calendars. You can also easily
convert between all the calendar types. The 4 most common forms of the
Moslem Arithmetic calendar are supported namely the 15th and 16th year leap
year rules as well as the Civil Epoch (16 July 622 C.E. O.S) and the
Astronomical Epoch (15 July 622 C.E. O.S).
- The classes stick very
closely to the MFC class structures and provide routines to map from
CTime, COleDateTime, COleDateTimeSpan and CTimeSpan. Mappings are also
available to convert to and from Win32 SDK date and time structures.
- The classes do not rely
on the ‘C’ runtime library like CTime does. If you have used the CTime
class then you will no doubt have come across its dependence on the
environment variable ‘TZ’ and all the problems that can give. The
classes use of UTC / Local is much less vague than CTime which performs
automatic mappings which can confuse even the most experienced
developer. There are also various static buffer issues with the built in
MFC classes which can provide for very difficult to debug issues.
- A number of date / time
classes are provided namely CDate, CLTimeSpan, CLTimeOfDay and CLDate.
- Methods are provided to integrate with the date time UI controls on
Windows.
- Includes comprehensive support for Holidays, Christian Saints Days,
National Holidays, US Specific Holidays, Christian Feast Days, Moslem and
Hebrew holidays.
- Tight integration with
the Win32 NLSAPI. For example all the day of week and month strings are
taken from Win32. This means that if DTime+ is used on an international
version of Windows, the days of week etc. will be in the local language.
- Format functions with a superset of the functionality provided by
CTime/CTimeSpan::Format.
- The Format
functions are also able to display a date or time according to display
characteristics as specified in the Windows Control Panel.
- The
CDate class provides a resolution of 1 day and uses a long to represent
the count of days. Its range is valid for roughly the whole range of a
long i.e. +/- 2 billion days (or just under 5.5 million years!) from the current era.
- The
CLTimeOfDay class represents a time of day i.e. 00:00:00 to 23:59:59 and provides a
resolution of 1 second.
- The
CLTimeSpan class represents the time
interval between two CLDate instances and provides a resolution of 1 second.
- The
CLDate class represents the composite of a date and a time of day
together and provides a granularity of 1 second. As with CDate, the full
range of a long is valid i.e. +/- 5.5 million years. This is ‘quite’ larger than the roughly
60-year time span for CTime (assuming you are not using the 64 bit CTime data type available in Visual Studio 2005) and the 100 CE - 9999CE time span for
COleDateTime. Using CLDate means that you can represent +/- 5.5 million
years from the current era with a resolution of 1 second.
- All classes are fully Unicode enabled and Unicode build configurations
are provided in the sample apps provided.
- All classes and defines are declared in a C++ namespace called DTimePlus.
This helps reduce pollution of the C++ global namespace.
- DTime+ is compatible with
MFC and Microsoft Visual C++ 6 and later.
The enclosed
zip file contains the
source code, a simple console based application which exercises all the class
and a CDialog based application to exercise the UI support provided by the class
framework.
Copyright
- You are allowed to include the source code in
any product (commercial, shareware, freeware or otherwise) when your product
is released in binary form.
- You are allowed to modify the source code in
any way you want except you cannot modify the copyright details at the top
of each module.
- If you want to distribute source code with
your application, then you are only allowed to distribute versions released
by the author. This is to maintain a single distribution point for the
source code.
Updates
v3.0 (22 April 2006)
- Following a long term of hibernation, DTime is now back. It is
now freeware as opposed to Shareware, has been extensively reworked and has been renamed to DTime+.
- Updated copyright details.
- Classes are no longer derived from CObject as this was not
really necessary.
- Reworked the layout of the directories to ship as a more
standard collection of standard C++ modules. Like other code
provided by the author. the code now does not ship pre-built as an
extension dll, instead it is provided as a pure source code library.
You are of course free to include DTime+ in an extension dll if you
so desire.
- Removed the timeframe concept from the CLDate class.
- Removed support for ET and DeltaT. If you would like support for
this please check out the author's AA+ class framework at
http://www.naughter.com/aa.html.
- Integrating the concept of a Windows locale (LCID) into all
functions which return strings. This allows the code to easily mix
and match calendar strings from multiple languages in the one
program.
- Because the code now tightly integrates with the Win32 NLS
API's, DTime+ now does not need to carry around any resources of its
own.
- Removed all virtual functions from all DTime+ classes.
- Removed the need to use friend classes.
- Updated the references to where the basic algorithms used by
DTime+ are based on. See the comments in the CDate::Set() method.
- Provided updated UI support via the standard Windows date / time
controls.
- Updated the code to ensure relatively clean compiles using
Visual Studio 2003 and 2005 (Still warnings in 2005 with calling the
so called unsafe "C" runtime functions).
- Did a full spell check and update of the documentation.
v3.01 (1 May 2006)
- Reworked the CDate and CLDate classes to use templates to
specify the calendar type to use (Julian, Gregorian or Moslem). By
making these classes template based, we have dispensed with a bool
member variable in each instance, thereby reducing the per instance
memory size of each of these classes. It also means that the
serialized size for both of these classes has shrunk by 1 byte. By
also making the classes template based, the code should also have a
better chance of being optimized by the compiler. An example of the
changes this implies to client code is as follows:
CDate x(1990, CDate::March, 4, CDate::Gregorian) -> DTimePlus::CDate<CGregorianCalendar>(1990,
March, 4) and
CDate x(1990, CDate::March, 4, CDate::Julian) -> DTimePlus::CDate<CJulianCalendar>(1990,
March, 4)
- Because of the move to templates, I had a problem getting
CLTimeSpan and CLTimeOfDay to compile because there is a circular
dependence between these two classes. When you make a class template
based, using forward class references to resolve these issues now no
longer works. Instead the CLTimeOfDay is now also template based
which works around the circular reference issue. An example of the
change this implies to client code is as follows:
CLTimeOfDay y(10, 12, 14) -> DTimePlus::CLTimeOfDay<> y(10, 12, 14);
- Moved all the classes and methods out of the global namespace
and into a namespace called "DTimePlus"
- Implemented extensive support for the Moslem Calendar. The
algorithms are taken from the book "Calendrical Calculations, The
Millenium Edition" by Edward M. Reingold and Nachum Dershowitz. The
4 most common forms of the Moslem Arithmetic calendar are supported
namely the 15th and 16th year leap year rules as well as the Civil
Epoch (16 July 622 C.E. O.S) and the Astronomical Epoch (15 July 622
C.E. O.S). These are implemented by the template classes
CMoslemCalendarCivil16, CMoslemCalendarCivil15,
CMoslemCalendarAstronomical16 and finally
CMoslemCalendarAstronomical15. For example to create a date which
represents Muharram 1, A.H. 1 using the Civil epoch and the 16th
year leap rule you would use:
DTimePlus::CDate<CMoslemCalendarCivil16> FirstDayOfMoslemEpoch(1,
Muharram, 1);
The Moslem month's are defined as a standard enum in the DTimePlus
namespace just like you can use the Julian / Gregorian
month names.
- Optimized the operation of the various Format methods.
v3.02 (20 May 2006)
- Canonical DaysInMonth method now takes a Year and a Month
parameter instead of a month and a leap year boolean. This is
required for support of the Hebrew calendar where knowing whether a
year is a leap year or not is not good enough to determine the
number of days in any month. This is because of the more complex
nature of the Hebrew calendar and its' postponement rules for the
Hebrew New Year (Rosh ha-Shannah). Please note that this means you
should examine all calls to this method in client code to ensure it
is updated correctly.
- Canonical DaysInYear method layout has been updated to take a
year instead of a leap year boolean. The reason is as for item one
above. Again you should examine all calls to this method in client
code to ensure it is updated correctly.
- Canonical DaysSinceEndPreviousYear and DaysSinceFirstOfYear
parameter layout has been updated. Both now take a year, month and
day value. The reason is as for item one above. Again you should
examine all calls to this method in client code to ensure it is
updated correctly.
- Moslem classes now uses functors for leap year functionality.
This does not affect client code in any way.
- CJulianCalendar now uses functors for leap year calculations.
This does not affect client code in any way.
- CGregorianCalendar now uses functors for leap year calculations.
This does not affect client code in any way.
- Now includes comprehensive support for the Hebrew calendar. The
algorithms are taken from the book "Calendrical Calculations, The
Millenium Edition" by Edward M. Reingold and Nachum Dershowitz. For example to create a date which
represents the date of Passover in 922 C.E., that is Nisan 15 A.M.
4682, you would use:
DTimePlus::CDate<CHebrewCalendar> Passover(4682,
Nisan, 15);
The Hebrew month's are defined as a standard enum in the DTimePlus
namespace just like you can use the Julian / Gregorian
month names. Also various helper functions are provided in the class
CHebrewCalendar to handle the various intricacies of this calendar.
- Addition of a AsHebrewCDate method to CDate class.
- Addition of a constructor and Set method to CLDate which allows
construction from a floating point days value.
- Updated the sample app, to verify the algorithms produce
monotonically increasing day counts for all Calendars (Gregorian,
Julian, 4 flavours of the Moslem calendar and Hebrew).
- Updated the sample app to widen the verification years for the
algorithms to cover the span -100,000 to 100,000 C.E.
- Updated the sample app to report the relative speeds of the
various calendar algorithms.
v3.03 (22 May 2006)
- Fixed a compile issue in VC 2003 with the multiplication
operator for CLTimeSpan. The issue was related to the tighter ISO
conformance of the compiler. Thanks to Itamar Syn-Hershko for reporting this
issue.
v3.04 (25 May 2006)
- Updated the string and enums for the 7th month in the Hebrew
calendar to be "Tishrei". Thanks to Itamar Syn-Hershko for reporting
this issue.
- Updated the string and enums for the first month in the Hebrew
calendar to be "Nissan". Thanks to Itamar Syn-Hershko for reporting
this issue.
- Updated the string and enums for the 8th month in the Hebrew
calendar to be "Cheshvan". Thanks to Itamar Syn-Hershko for
reporting this issue.
- Now includes spaces in the strings returned for AdarI and AdarII
(the 12th and 13th month of the Hebrew calendar).
- Fixed a typo in the string and enums for the 11th month in the
Hebrew calendar "Shevat". Thanks to Itamar Syn-Hershko for reporting
this issue.
- Optimized the code in CJulianGregorianCalendar::DaysInMonth.
- Optimized the DTimePlus::WeekOfDayModulo and DTimePlus::lfloor
functions. This results in a 2 fold increase in the speed of the key
algorithms for the Julian and Gregorian calendars.
- made all the functions in CJulianGregorianCalendar inline.
- Optimizied the CBaseMoslemCalendar::DaysInMonth code.
- Made some Moslem functions inline to aid optimization. These
tweaks to the Moslem algorithms result in a c. 40% speed improvement
- Made some Hebrew functions inline to aid optimization.
v3.05 (27 May 2006)
- Renamed the CHebrewCalendar::LongMarheshvan function to
LongCheshvan.
- Renamed the CHebrewCalendar::ShortMarheshvan function to
ShortCheshvan.
- Reworked Hebrew algorithms to support dates before the Hebrew
epoch i.e. a proleptic Hebrew calendar.
- Reworked Moslem algorithms to support dates before the Moslem
epoch i.e. a proleptic Moslem calendar.
- Updated the month enum names and month strings for the Moslem
calendar.
- Updated the weekday strings for the Moslem calendar.
- Removed the need for the function DTimePlus::WeekOfDaysModulo.
v3.06 (29 May 2006)
- Further performance optimizations for the core CJulianCalendar
algorithms. There is a 3% increase in performance compared to v3.05.
On my Quad Opteron system, the round trip tests for 1000 years of Julian
dates takes just 48 ms.
- Further performance optimizations for the core
CGregorianCalendar algorithms. There is a 3% increase in performance
compared to v3.05. On my Quad Opteron system, the round trip tests
for 1000 years of Gregorian dates takes just 79 ms.
- Now includes comprehensive support for Holidays, Christian
Saints Days, National Holidays, US Specific Holidays, and Christian
Feast Days via the new class CJulianGregorianHolidays.
- Updated the month enum name and month strings for Moslem month
"Ramadan".
- Now includes comprehensive support for Moslem Holidays via the
new module DTime+MoslemHolidays.h. Also you can determine Moslem
holidays occurring in a Gregorian year via
MoslemOccurencesInGregorianYear.
- Now includes comprehensive support for Hebrew Holidays via the
new module DTime+HebrewHolidays.h. Also you can determine Hebrew
holidays occurring in a Gregorian year via
HewbrewOccurencesInGregorianYear.
- Removed the now unnecessary defines DTIMEPLUS_EXT_CLASS and
DTIMEPLUS_EXT_API. These are no longer required because DTime+ is
template based.
v3.07 (30 May 2006)
- Added support for Rosh HaShanah 2
- Renamed CSimhatTorahFunctor to CCSimhatTorahOutsideIsraelFunctor
- Renamed CPassoverFunctor to CPesachFunctor
- Renamed CEndingOfPassoverFunctor to CShviiPesachFunctor
- Added support for Yom Ha'atzmaut
- Added support for Erev Pesach
- Added support for Ta'anit Bechorim
- Added support for Pesach Shenni
- Added support for Yom Yerushalaiym
- Renamed to CHoshahaRabbaFunctor to CHoshanahRabahFunctor. All of
these updates for the Hebrew calendar for v3.07 are thanks to Itamar Syn-Hershko.
v3.08 (2 July 2006)
- Updated the code to clean compile on VC 2005
- Code now uses new C++ style casts rather than old style C
casts where necessary.
v3.09 (13 April 2007)
- Updated copyright details.
- Updated sample apps to clean compile on VC 2005
- Fixed a bug in CDate::Set(const CTime& ctime, ...) and CLDate&
CLDate::Set which incorrectly used GetGmtTm instead of GetLocalTm.
Thanks to Martin Copland for reporting this bug.