If your application depends not only on local time, but also on its representation in other time zones, you must have experienced the difficulty of representing time in different time zones. Did not come across? So you have not ported your application to the world of Unix.
Indeed, in Windows for working with time zones, the programmer is provided with a convenient set of specialized WinAPI functions. An example is the
TIME_ZONE_INFORMATION structure and
the GetTimeZoneInformation function to it in addition.
But what to do if you need to know the offset relative to UTC + 0, the rules for the transition to "summer time", while taking into account leap years with leap seconds and other specific information for any region, but all this in unix-like operating systems? The article is devoted to the practice of working with all this junk in C / C ++.
This topic was repeatedly covered in many articles from different points of view, but rarely from practical with examples of specific languages, systems and technologies. Examples can be found on the Stack Overflow (of which there are a lot of questions), and
on Habré this topic was touched on quite deeply, but from a theoretical point of view. In addition, there is even a
mini-study on the topic of local time, from which we can learn that the problem of computer time is not at all trivial, which seems at first glance. Having conducted my own investigation, I would like to briefly and intelligibly share a considerable amount of information I received, filling it in the form of ways to convert time in different time zones.
')
Classic: C Standard Library
Yes, with the help of that function maser defined in the header
time.h
, you can also perform time conversions. With certain restrictions.
The fact is that all locale-dependent functions (such as
gmtime()
or
localtime()
) use the
TZ
environment variable to determine the locale parameters. This means that in order to convert the time to the desired time zone, you must first set this variable (with the name of the required zone), call the conversion function, and then remove the
TZ
from the environment again. All anything, if not multitasking and multithreading. Naturally, this method can cause conflicts and lead to difficult predictable errors.
Sample code using this approach:
putenv("TZ=Asia/Calcutta");
Using the
Olson database for your own purposes is the preferred option. The advantages are obvious: the base most fully reflects all conceivable transition rules for any corner of the Earth (given the changes in these rules since the beginning of the last century), is distributed with many systems (see
/usr/share/zoneinfo
) and has a unified format, while the base updated with the system. However, having tried to work with her, I decided to refuse from this option.
The database is distributed in binary format (for this, the
zic
compiler is used). The format description can be found in the
tzfile.h
header file (use the official
FTP database to find it). I did not find any tools for working with the database (perhaps I looked badly?). But having tried to read the file of the necessary time zone, I was faced with the problem of data interpretation - in all these subtleties and terminology you can turn your head, forgetting about the purpose of all this digging. And, in order to abstract from such trifles, it was decided to use the most adequate and convenient tool.
Boost.Date_Time
As it often happens in such situations, the
boost comes to the rescue. On the wide possibilities of the Date_Time library set, there has already been
an article containing a brief translation of the official documentation. By the way, the good news is for those who do not want to introduce unnecessary dependencies into their project - the library is header-only (with the exception of a couple of specific places, like creating a timestamp object from a string of a specific format).
To resolve the issue, there are two ways: write the rules for the desired time zone with a hardcode in the program (and then hate yourself for it), or store all the rules in a special CSV-format file. Such a file can be subsequently updated automatically (and keep the transition rules up to date, which is extremely important). The file is distributed with the boost distribution (called
date_time_zonespec.csv
), but can be taken from
other places . Plus the use of the file, among other things - it stores the rules for all regions.
No cons, too, will not do. What if you need to convert that timestamp somewhere near the beginning of the twentieth century, when the transition rules were different? Such cases also have to be taken into account, and, unfortunately, the boost here can be of little help.
For example, here’s the code that uses the Date_Time library set feature to convert time.
#include "boost/date_time/local_time/local_time.hpp" #include "boost/date_time/posix_time/posix_time.hpp" using namespace boost::local_time; using namespace boost::posix_time; ptime convertUTC0toCustomTimeZone(const ptime &utcTime, const std::string &tzName) {
Results
I preferred to use the boost option. Of course, using the tz database will relieve you of the headwash with keeping information about time zones up to date or when converting a timestamp, the transition rules of which have been changed. But in most applications such frills come to nothing, and the boost allows you to work with dates extremely conveniently.