📜 ⬆️ ⬇️

Boost is easy. Part 2. Boost.Date_time

As you already understood, this article will focus on the Boost.Date_Time library. Library to work with time.




In the article we will consider the following parts of the library:
')



Introduction


Now it is probably difficult to find a person who would not be faced with the need to use time for their own purposes, or rather its digital representation. The goals can be completely different, from simple measurements of time intervals in which a certain piece of code is executed (absolutely not the right method of profiling, by the way, but now is not about that), to support full-fledged calendars in their applications that should be relevant for any person on the globe. All these manipulations can be performed using a rather austere and easy to use, but at the same time powerful library Boost.Date_Time. The library includes: leap year, leap second , summer time, etc.
We will understand some terminology used in the library:
There are three global types of time sharing in the library:
  1. Time Point - a certain point in the time continuum, for example, your date of birth
  2. Time Duration - a time interval that is not tied to any point in the time continuum
  3. Time Interval - the time interval associated with a certain point in the time continuum

It is also necessary to remember about the resolution of each method of obtaining time, the resolution ( Resolution ) shows what is the minimum unit of time that can be used when analyzing the time object you have. Ie this is nothing more than the degree of accuracy of the obtained time point. Finally, we turn to a direct acquaintance with the capabilities of the library.

boost :: gregorian


All examples used in this article imply the use of using namespace boost :: <matching_namespace> at the beginning of each compiled unit.
This component represents the Gregorian calendar and every conceivable opportunity to work with it. It in turn is divided into the following components:

Let us examine the purpose of each of them:

boost :: gregorian :: date - designed for simple storage of the date - point in the time continuum. Supports creation of a date from a string of a specific format, as well as through the class boost :: date_time :: day_clock , based on the standard C / C ++ mechanism associated with time_t
In addition to storing the date (which cannot be changed for an object except by using operator =), the class has methods * for getting specific parts of the date (year (), month (), day () etc.), converting the internal representation of the date into a string , of a specific format (to_simple_string (), to_iso_string (), to_iso_extended_string ()) and conversion to (and back) the standard C / C ++ structure tm (to_tm (), date_from_tm ())

* - I do not provide a description of each function, moreover, I will not, provides a complete list of available functions, you can see a list of them in the links corresponding to a particular class. There are a lot of functions and they are quite easy to use, I also omit the availability of function parameters, if I consider it insignificant at the moment.
Example:
date xGPWStart(1941, Jun, 22);
date xNowdays = day_clock::local_day();
std::cout << "The Great Patriotic War was started in " << xGPWStart << std::endl;
std::cout << "And the current data is " << xNowdays;


* This source code was highlighted with Source Code Highlighter .


Conclusion:
The Great Patriotic War was started in 1941-Jun-22
And the current data is 2009-Jul-26

boost :: gregorian :: date_duration - serves to count the days, using boost :: gregorian :: date for calculations.
For convenience of working with date_duration, there are three classes: months_duration , years_duration and weeks_duration (there are also typedefs for these types, presented for convenience: months , years, and weeks, respectively), which can be added or subtracted from date_duration to get the desired result. There is a pitfall associated with these three classes. If you use them in your calculations, you can get a result that you do not expect. I will give an example:
date xSomeDay(1999, Jan, 28);
date xDayInNextMonth;
std::cout << "That's right: " << ( xDayInNextMonth = xSomeDay + months(1) ) << std::endl;
std::cout << "And that's not: " << xDayInNextMonth + months(1);

* This source code was highlighted with Source Code Highlighter .

That's right: 1999-Feb-28
And that's not: 1999-Mar-31

This behavior is due to the special feature of the months_duration class, which will always use the end of the month in arithmetic operations if the original object pointed to one of the possible numbers that end the months (28, 29, 30, 31). Be careful when using this type, by the way month_iterator is deprived of this disadvantage (advantages?), But we'll talk about it later.

boost :: gregorian :: date_period - the class is presented for conveniently representing the interval between two dates, can be used to determine whether a specific date is included in the time interval (contains ()), the intersection of intervals (intersects (), intersection ()), date adjacency ( is_adjacent ()) and determine the relationship of the location of one date relative to another (is_after (), is_before ()). In addition, there are methods for the combination of intervals (merge (), span ()) and their changes (shift (), expand ()). It is important to remember that the last period in the period is not included in the entire period, that is, in the period 1-Jan-1999 \ 10-Jan-1999 the last day will be January 9, not 10.
Example:
date_period xGPWDuration( date(1941, Jun, 22), date(1945, May, 9) );
date_period xStalinLifeYears( date(1878, Dec, 18), date(1953, Mar, 6) ); date_period xJukovsIncorrectLifeYears( date(1896, Dec, 6), date(1974, Jun, 14) );
std::cout << "The Great Patriotic War duration is " << xGPWDuration << std::endl;
std::cout << "Was the GPW inside the Stalin's life years? " << std::boolalpha << xStalinLifeYears.contains(xGPWDuration) << std::endl;
std::cout << "Jukov's incorrect life years is " << xJukovsIncorrectLifeYears << std::endl;
xJukovsIncorrectLifeYears.expand( days(5) );
std::cout << "Jukov's correct life years is " << xJukovsIncorrectLifeYears << std::endl;
//Last day isn't included in the interval
date_period xFirstPeriod( date(1999, Jan, 1), date(1999, Jan, 10) );
date_period xSecondPeriod( date(1999, Jan, 10), date(1999, Jan, 12) );
std::cout << "Does these periods intersect? " << std::boolalpha << xFirstPeriod.intersects(xSecondPeriod) << std::endl;

* This source code was highlighted with Source Code Highlighter .

Conclusion:
The Great Patriotic War duration is [1941-Jun-22/1945-May-08]
Was the GPW inside the Stalin's life years? true
Jukov's incorrect life years [1896-Dec-06/1974-Jun-13]
Jukov's correct life years is [1896-Dec-01/1974-Jun-18]
Does these periods intersect? false

boost :: gregorian :: date_iterator - as it should be clear from the name - this is a typical iterator designed for “moving” on dates. The date_iterator is not interesting in itself, because it is an abstract class, its descendant classes are more interesting: day_iterator , week_iterator , month_iterator , year_iterator .
As an example, we use the example from date_duration , in which we received an incorrect date (due to pitfalls with months). As I mentioned earlier, there are no similar problems in date_iterator :
month_iterator xSomeDay(date(1999, Jan, 28));
std::cout << "That's right: " << *++xSomeDay << std::endl;
std::cout << "And that's too!: " << *++xSomeDay;

* This source code was highlighted with Source Code Highlighter .

That's right: 1999-Feb-28
And that's too !: 1999-Mar-28


Algorithms for working with dates - a set of various classes and functions for various manipulations of dates. Each class has a get_data () method that allows you to get the date generated by this class. Classes provide us with the following functionality:

Functions provide the following functionality:

Examples:
last_day_of_the_week_in_month xLastFriday(Friday, Jul);
partial_date xJunTen(10, Jun);
std::cout << "What is the date of the last friday in the July 2009? " << xLastFriday.get_date(2009) << std::endl;
std::cout << "Just dusplay 10 Jun of 2009 " << xJunTen.get_date(2009) << std::endl;
std::cout << "How much days from now till next friday? " << days_until_weekday( day_clock::local_day(), greg_weekday(Friday) )<< std::endl;

* This source code was highlighted with Source Code Highlighter .

Conclusion:
What is the date of the last friday in July 2009? 2009-Jul-31
Just dusplay 10 Jun of 2009 2009-Jun-10
How many days from now till next friday? five

boost :: gregorian :: gregorian_calendar - provides a useful set of static functions for working with dates.
Instead of describing functions, I’ll give an example of their use (the functions are simple and their name speaks for itself):
std::cout << "What the day of the GPW begining? " << DayToString( gregorian_calendar::day_of_week( gregorian_calendar::ymd_type(1941, Jun, 22) ) ) << std::endl;
std::cout << "And what is the number of this day frome the epoch start? " << gregorian_calendar::day_number( gregorian_calendar::ymd_type(1941, Jun, 22) ) << std::endl;
std::cout << "And what is the number of this day frome the epoch start? " << gregorian_calendar::day_number( gregorian_calendar::ymd_type(1400, Jan, 1) ) << std::endl;
std::cout << "What is the last day in the February 1941? " << gregorian_calendar::end_of_month_day(1941, Feb) << std::endl;
std::cout << "What is the date of the 3333333 day from the epoch start? " << date( gregorian_calendar::from_day_number(3333333) ) << std::endl;
std::cout << "Is the 2004 year a leap year? " << std::boolalpha << gregorian_calendar::is_leap_year(2004) << std::endl;

* This source code was highlighted with Source Code Highlighter .

Conclusion:
What is the day of the GPW begining? Sunday
And what is the number of this day? 2430168
And what is the number of this day? 2232400
What is the last day of February 1941? 28
What is the date of the 3333333 day from the epoch start? 4414-Apr-03
Is the 2004 year a leap year? true

It was obtained empirically that for the day_number () and from_day_number () functions the minimum values ​​are 1400-Jan-1 and 2232400, respectively. If you try to use a date earlier than 1400-Jan-1, then we get an exception. The same is true for the number of days.

boost :: posix_time


This component provides us with a convenient method of working with points in time, but unlike boost :: gregorian, boost :: posix_time provides the ability to work with lower resolution time points (up to nanoseconds), the high part of the resolution (date) is implemented with the help of boost: : gregorian . The component is especially useful for tasks in which high accuracy of time acquisition is necessary (for example, a recording line in a log file). It is divided into the following parts:

Let us examine the purpose of each part:

boost :: posix_time :: ptime - represents a point in the time continuum. Very similar to boost :: gregorian: date but with a resolution of up to microseconds. When creating an instance of a class only gregorian: date , the “low resolution” part is set at midnight (all zeros).
Example of use:
ptime xTime(date(1961, Apr, 12), hours(9) + minutes(7));
std::cout << "Did you know that Gagrin said \"Poehali\" at " << xTime << "\n" ;
ptime xTimeStr( time_from_string( "1961-04-12 09.07.00.0000" ) );
std::cout << "And the same time point constructed from a string: " << xTimeStr << "\n" ;
std::cout << "Current time with second resolution: " << second_clock::local_time() << "\nAnd with microsecond:" << microsec_clock::local_time();

* This source code was highlighted with Source Code Highlighter .

Conclusion:
Did you know that Gagrin said "Poehali" at 1961-Apr-12 09:07:00
And the same time point constructed from a string: 1961-Apr-12 09:07:00
Current time with second resolution: 2009-Jul-29 16:41:51
And with microsecond: 2009-Jul-29 16: 41: 51.087000


boost :: posix_time :: time_duration - is a duration in time that is not tied to a specific date. The maximum duration resolution is limited to nanoseconds if the library is compiled with the BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG macro, and microseconds, by default. Information about the number of seconds \ microseconds \ milliseconds \ nanoseconds (with the corresponding assembly) that are contained in the current time duration can be obtained from the object.
Example:
time_duration xTime(1,2,3);
std::cout << "Print time: " << xTime << "\n" ;
std::cout << "Print increased time: " << xTime + hours(3) + seconds(2) + minutes(6) + milliseconds(15) + microseconds(25) << "\n" ;
std::cout << "Print total seconds: " << xTime.total_seconds() << " milliseconds: " <<
xTime.total_milliseconds() << " microseconds: " << xTime.total_microseconds() << "\n" ;

* This source code was highlighted with Source Code Highlighter .

Conclusion:
Print time: 01:02:03
Print increased time: 04: 08: 05.015025
Print total seconds: 3723 milliseconds: 3723000 microseconds: 3723000000

boost :: posix_time :: time_period - is a segment in time, the class is similar to gregorian :: date_period , but has a lower resolution. The class functional allows you to define the occurrence (contains ()), the intersection (intersects ()) and the length (length ()) of the intervals. There is also the possibility of expanding (expand), offset (shift ()) and merging (merge ()) intervals.
Example:
ptime xDoomsday( date(2012, Jan, 1) );
time_period xArmageddonLast(xDoomsday, hours(1));
time_period xChakNorrisSmoke(xDoomsday, minutes(1));
std::cout << "Doomsday was during: " << xArmageddonLast<< "\n" ;
std::cout << "Chak Norris was smoking at " << xChakNorrisSmoke << "\n" ;
std::cout << "Did Chak Norris smoke during Doomsday breathtaking?" << std::boolalpha <<xArmageddonLast.contains(xChakNorrisSmoke);


* This source code was highlighted with Source Code Highlighter .

Conclusion:
Doomsday was during: [2012-Jan-01 00: 00: 00/2012-Jan-01 00: 59: 59.999999]
Chak Norris was smoking at [2012-Jan-01 00: 00: 00/2012-Jan-01 00: 00: 59.999999]
Did Chak Norris smoke during Doomsday breathtaking? True

boost :: posix_time :: time_iterator - designed (as everyone probably guessed :)) to iterate over time. A nice feature of this iterator is the ability to set the time interval to be used during the iteration, i.e. how much and in what units the current point in the time continuum will change at each iteration. As time units, all units from an hour to nanoseconds can be used (if assembled with the appropriate flag)
I will give a small example:
ptime xTime(date(2012, Jan, 1));
time_iterator xIt(xTime, hours(6));
std::cout << "6 hours after Domsday has come!!!" << *++xIt;

* This source code was highlighted with Source Code Highlighter .

Conclusion:
6 hours after Domsday has come !!! 2012-Jan-01 06:00:00

Local time system


This component gives us the opportunity to work with time, in different time zones and with different rules for the transition to summer time. This is quite a powerful and necessary component, especially necessary for those applications where not just the current (local) time is important, but taking into account various time shifts, according to regional agreements regarding time (summer time, time zone, etc.). So, here is a list of parts that are included in this component:


boost :: local_time :: posix_time_zone is a set of data and rules for representing time zones (offset relative to GMT, daylight saving time rules, the name of the time zone and its abbreviation). An object of this type is created based on a string, the format of a string is the standardized POSIX format (IEEE Std 1003.1) for time zones.
In general, this line looks like this:
std offset dst [offset], start [/ time], end [/ time]
std - time zone abbreviation.
offset - Offset relative to GMT.
dst - time zone abbreviation during summer time.
[offset] - Shows how much the time changes (in hours) when switching to summer time. Optional parameter.
start and end - Set the interval of the summer time.
[/ time] - Sets the exact time within the day at which the transition to summer time begins or the summer time ends.
offset and time have the following format: [+ | -] hh [: mm [: ss]] {h = 0-23, m / s = 0-59}
start and end can be presented in one of the following formats:

You can get each part of this string separately using the methods of this class. I see no reason to give their names here, they are quite transparent and reflect the essence of their purpose, so refer to the documentation for their list.
As an example, I used the time zone GMT + 3 (Moscow time):
posix_time_zone xZone( "MSK+3MSD+01,M3.5.0/02:00,M10.5.0/02:00" );
std::cout << "Dailight period in 2009 started at " << xZone.dst_local_start_time(2009) << "\nAnd it will finish at " << xZone.dst_local_end_time(2009);


* This source code was highlighted with Source Code Highlighter .


Conclusion:
Dailight period in 2009 started on 2009-Mar-29 02:00:00
And it will finish at 2009-Oct-25 02:00:00


boost :: local_time :: tz_database is a convenient class for storing a variety of different time zones. When creating an object, an empty database is created (loudly said of course :)), after which it can be manually filled in using the add_record () method or read from the csv (comma separated values) file, an example of such a file (with a lot of records ) is contained in % boost% \ libs \ date_time \ data \ date_time_zonespec.csv
The format of the record inside this file must meet the following standard:
“ID”, “STD ABBR”, “STD NAME”, “DST ABBR”, “DST NAME”, “GMT offset”, “DST adjustment”, “DST Start Date rule”, “Start time”, “DST End date rule "," End time "

Where:
ID — Contains a string that uniquely identifies a given time zone.
STD ABBR, STD NAME, DST ABBR, DST NAME - These fields are filled with strings with standard and summer time names and abbreviations, often names and abbreviations are identical.
GMT offset - The offset in time, relative to Greenwich. Its format is: {+ | -} hh: mm [: ss]
DST adjustment - Offset relative to GMT offset during the “summer time” action. The format is the same as GMT offset .
DST Start Date rule - A string describing the day of the year that heralds the start of the “summer time” period. It also has its own format (how many different formats are possible?):
weekday; day-of-week; month
Where:
weekday - Ordinal number, indicating what the day of the month counts, interests us.
day-of-week is the day of the week.
month - month.
Example:
-1; 0; 3 - The beginning of "summer time" in Russia (the last Sunday of March)

Start time - The time after midnight when summer time comes into effect. The format is the same as GMT offset .
DST End date rule - A string describing the day in the year that heralds the end of the “summer time” period. The format is identical to the DST Start Date rule .
End time - Analogous to Start time , only for the end of “summer time”.
Example:
tz_database xDb;
xDb.load_from_file( "G:\\Program files\\boost\\boost_1_39_0\\\libs\\date_time\\data\\date_time_zonespec.csv" );
const std::vector<std:: string >& xAllRegions = xDb.region_list();
std::cout << "Print first 10 zone IDs from the boost time zone file:" << std::endl;
for (std::vector<std:: string >::const_iterator it = xAllRegions.begin(); it != xAllRegions.begin() + 10; ++it)
std::cout << *it << std::endl;
std::cout << "And time when daylight saving was started at 2009: " << xDb.time_zone_from_region( "Europe/Moscow" )->dst_local_start_time(2009) << std::endl;

* This source code was highlighted with Source Code Highlighter .


Conclusion:
Print first 10 zone IDs from the boost time zone file:
Africa / Abidjan
Africa / Accra
Africa / Addis_Ababa
Africa / Algiers
Africa / Asmera
Africa / Bamako
Africa / Bangui
Africa / Banjul
Africa / Bissau
Africa / Blantyre
Daylight saving was started at 2009: 2009-mar-29 02:00:00


boost :: local_time :: custom_time_zone is a class for creating a description of the time zone, but unlike the previously described boost :: local_time :: posix_time_zone , this class uses four other classes when constructing a time zone. These classes are: time_duration , time_zone_names , dst_adjustment_offsets and dst_calc_rule . Since the class does not stand out outstanding, just give an example of its use:
time_zone_names xNames( "Moscow Standart Time" , "MST" , "Moscow Daylight Time" , "MDT" );
time_duration xGMTOffset(3, 0, 0);
dst_adjustment_offsets xRulesOffsets( time_duration(1,0,0), time_duration(2,0,0), time_duration(3,0,0) );
//Mak daylight's rule
last_day_of_the_week_in_month xStartRule(Sunday, Mar);
last_day_of_the_week_in_month xEndRule(Sunday, Oct);

boost::shared_ptr<dst_calc_rule> xRules( new last_last_dst_rule(xStartRule, xEndRule) );
custom_time_zone xCustomTimeZone(xNames, xGMTOffset, xRulesOffsets, xRules);

std::cout << "The our time zone name is: " << xCustomTimeZone.std_zone_name() << "\n"
<< "It has an " << xCustomTimeZone.base_utc_offset() << " offset from GMT.\n"
<< "And daylight period will end at " << xCustomTimeZone.dst_local_end_time(2009) <<std::endl;
std::cout << "Posix string which represents our custom_time_zone object is:\n" << xCustomTimeZone.to_posix_string();

* This source code was highlighted with Source Code Highlighter .

Conclusion:
Our time zone name is: Moscow Standart Time
It has an 03:00:00 offset from GMT.
And daylight period will end at 2009-Oct-25 03:00:00
Posix string which represents our custom_time_zone object is:
MST + 03MDT + 01, M3.5.0 / 02: 00, M10.5.0 / 03: 00

Classes boost :: local_time :: local_date_time and boost :: local_time :: local_time_period repeat similar classes from boost :: posix_time , with reference to the time zone, so I will not consider them.

Useful features and conclusion


In Boost.Data_time, in addition to the classes for creating dates, there are useful utilities, such as: formatted input / output processing and serialization . Both mechanisms are fairly simple to use and I consider their description redundant because the article, so it turned out to be quite voluminous.
As a conclusion, I would like to thank all those who have mastered reading this point, and also wish good luck in using Boost.Date_time in their projects, I hope those who have not used it before will be encouraged to use this article (I was already encouraged :)).
PS I spent almost a month on this article, I will hope that I will continue to write more often. If you find a mistake in the article, please let me know in a personal, do not clutter up these comments.

Source: https://habr.com/ru/post/66318/


All Articles