The Boost C++ Libraries Part 4 - boost::date_time

Andrew Stephens, Monday the 9th of February, 2009

Living on a spherical planet can sometimes be a real pain in the neck This post was automatically imported from my old sandfly.net.nz blog. It may look a little weird since it was not originally written for this format.. It makes what should be a simple concept, Time, inordinately complex. Timezones, daylight savings, leap years (and worse: leap seconds) all conspire to destroy any simple abstraction. So boost provides a complex one.

First up is the gregorian::date class, which specifies a day in the gregorian calendar (sorry fans of the French Revolutionary Calendar, boost::date_time is not for you). Along with normal days, gregorian::date supports positive/negative infinite dates as well as a special not_a_date_time value that make certain algorithms very easy.

A closely related type is gregorian::days, which represents duration. Durations can be freely added or taken away from dates to create new dates. Special classes for longer units also exist: gregorian::weeks, gregorian::months, and gregorian::years come in very handy. gregorian::months and gregorian::years even have special handling to ensure that dates "snap" to the end of the month during calculations.

gregorian::date leapYearMonth( 2008, Feb, 29 );
gregorian::months oneMonth(1);
gregorian::date endOfMarch = leapYearMonth + oneMonth; 
// endOfMarch == 31/3/2008, not 29/3/2008

gregorian::date_period represents a fixed period between two dates, and has the methods you would expect for determining if a date exists within a period or two periods overlap. Because the date class can represent abstract concepts like dates infinity days into the future or past, date_periods can represent segments of time without fixed ends.

gregorian::date_period untilFurtherNotice( gregorian::day_clock::local_day(),
                                           gregorian::pos_infin );

Date Iterators and Generators are both very cool concepts. Iterators produce a series of dates that are all some duration (ie: 1 month) apart. Generators provide even more complex factories for producing non-uniform dates such a "the last monday in January" for a given year.

Times are just dates with an offset into the specified day. In boost::date_time this is handled by the posix_time::ptime class. Like date, ptime can represent positive and negitive infinity as well as not_a_date_time giving great flexibility. Also like gregorian::date there are time_duration, time_period, and time_iterator classes which serve the same purpose.

I haven't even mentioned the most useful part of boost::date_time yet - a full set of streaming operators and conversions to and from standard string formats. If for some reason the standard input/output formats aren't enough it is possible to imbue a stream with a custom date/time facet for that fancy touch of class.

Aside from strings, dates and times are probably the most common data-types that must be represented in programs dealing with human affairs. It is a pleasure to finally have a library that is up to the task.