Boost.Locale
|
There are several important flaws in the standard C, C++ and Boost libraries that handle dates and time:
boost::date_time
, std::tm
, and standard functions like localtime
and gmtime
, all assume the Gregorian calendar.mktime
and localtime
, but they do not give user the information about the first day of week. This information is locale dependent. It is Monday in France and it is Sunday in United States.Boost.Locale provides generic date_time, and calendar classes that allow you to perform operations on dates and times for non-Gregorian calendars such as Hebrew, Islamic, Japanese and others.
Non-ICU based backends support the Gregorian calendar only. Unlike boost::date_time
, they are fully aware of the local first day of week. Thus, if the current day of week is Monday, then setting "current day of week" to Sunday would move the actual date 6 days forward in Russian or French locales and move one day backward in USA and Israeli locales.
For example:
using namespace boost::locale; date_time now; // Create date_time class with default calendar initialized to current time date_time tomorrow = now + period::day(); cout << "Let's meet tomorrow at " << as::date << tomorrow << endl; date_time some_point = period::year(1995) + period::january() + period::day(1); // Set some_point's date to 1995-Jan-1. cout << "The "<< as::date << some_point << " is the " << as::ordinal << some_point / period::day_of_week_local() << " day of the week" << endl;
You can calculate the difference between dates by dividing the difference by a period:
date_time now; cout << " There are " << (now + 2 * period::month() - now) / period::day() << " days " "between " << as::date << now << " and " << now + 2*period::month() << endl;
You can also use different syntax (less operator overloading)
date_time now; cout << " There are " << period::day(now + period::month(2) - now) << " days " "between " << as::date << now << " and " << now + period::month(2) << endl;
date_time -- provides the member functions minimum and maximum to get the information about smallest and largest possible values of a certain period for a specific time.
For example, for February the maximum(period::day())
would be 28 (or 29 for a leap year), and for January it would be 31.
We recommend you to look at the calendar.cpp
example provided with this library to get an understanding of how to manipulate dates and times using these classes.
To convert between various calendar dates, you may get the current POSIX time via the time member function.
For example:
using namespace boost::locale; using namespace boost::locale::period; generator gen; // Create locales with Hebrew and Gregorian (default) calendars. std::locale l_hebrew=gen("en_US.UTF-8@calendar=hebrew"); std::locale l_gregorian=gen("en_US.UTF-8"); // Create a Gregorian date from fields date_time greg(year(2010) + february() + day(5),l_gregorian); // Assign a time point taken from the Gregorian date to date_time with // the Hebrew calendar date_time heb(greg.time(),l_hebrew); // Now we can query the year. std::cout << "Hebrew year is " << heb / year << std::endl;
Non-ICU based backends support the same date-time range as mktime
and localtime
C library functions.
time_t
is 32 bits wide (mingw), then the upper limit is year 2038The current operating system's time zone is used by default, however the time zone can be modified at several different levels:
Non-ICU based backends support only two kinds of time zones:
localtime
and mktime
the standard library functions - the default time zoneWriting a date_time is equivalent to:
For example this code:
using namespace boost::locale; date_time now; std::cout << now << std::endl;
Would print in the default format, something like:
2/3/2011 12:00 am
However if you need to change the default behavior (for example show only date), then you need to use specific iostream manipulator in order to display current date or time, it would override the default formatting.
For example
Would print something like:
2/3/2011
This is important to remember that date_time
object is always rendered and parsed in the context of the iostream's
locale and time zone and not in the context of specific date_time
object.
Why should I use Boost.Locale over Boost.DateTime when I need Gregorian calendar only?
date_time(some_time.time() + 3600)
may be not equal to some_time + hour()
, because of the daylight savings time.Why don't you use Boost.DateTime time zone support?
Boost.DateTime's time zone support is broken. Time zones can not be represented with a simple table of rules where daylight saving depend only on certain n'th day of week in month. The daylight savings time may vary by year, political issues and many other things.
Most of the modern operating systems (Linux, *BSD, Mac OS X, OpenVMS) and many important software packages (ICU, Java, Python) use so called Olson database in order to handle daylight saving time correctly.
If you need full time zone database support, then you should use ICU library.