Расстояние UTC — местное время в Linux

Я пишу приложение для Linux (Ubuntu и Debian Lenny) на С++.

Теперь мне нужно знать расстояние/смещение между UTC и текущим установленным системным временем в данный день в прошлом. Поскольку мне нужно преобразовать записанные данные, расстояние нужно рассчитать относительно даты в прошлом (которая может иметь настройку летнего времени, отличную от текущего дня).

Кто-нибудь знает, как это сделать?

Изменить: читая первый ответ, я думаю, что меня неправильно поняли: я не хочу сравнивать даты/время. У меня есть значения даты/времени, которые я хочу преобразовать из UTC в местное время.


person Gabriel Schreiber    schedule 12.11.2010    source источник
comment
одна проблема, с которой вы можете столкнуться, - это разница местного времени с UTC на основе различных законов перехода на летнее время.   -  person warren    schedule 13.11.2010


Ответы (3)


Подготовьте структуру tm с датой:

struct tm date;
memset(&date,0,sizeof(date));
date.tm_year = year - 1900;
date.tm_mon = month - 1;
date.tm_mday = day;
date.tm_hour = hour;
date.tm_min = minute;
date.tm_sec = second;
date.tm_isdst = -1; // VERY IMPORTANT

mktime(&date); /// fill rest of fields

А потом взгляните на tm_gmtoff

printf("%d\n",date.tm_gmtoff);

Это расстояние от UTC.

Теперь это специфично для Linux и BSD, это не будет работать на других системах, и это работает в отношении летнего времени.

Прочтите man mktime для получения дополнительной информации. И заполнение struct tm правильными значениями

P.S.: Преобразование из UTC в местное и обратно?

time_t posix_time = timegm(&UTC_Filled_struct_tm); // Linux specific line
localtime_r(&posix_time,&local_Filled_struct_tm);

Местный для UTC

time_t posix_time = mktime(&local_Filled_struct_tm);
gmtime_r(&posix_time,&UTC_Filled_struct_tm);
person Artyom    schedule 12.11.2010

Я думаю, вам будет полезно использовать Boost.DateTime или ICU.

Что касается Boost.DateTime, tt может быть таким:

1) Вы подготавливаете базу данных с информацией о часовом поясе Boost.Datetime и создайте часовой пояс. Часовые пояса важны, поскольку они содержат информацию о переходе на летнее время

tz_database tz_db;
tz_db.load_from_file("./date_time_zonespec.csv");
time_zone_ptr nyc = tz_db.time_zone_from_region("America/New_York"); // or other timezone


Или просто создайте часовой пояс, подобный этому.

std::string kaliningrad_string = "EET+02:00:00EEST+01:00:00,M3.5.0/02:00:00,M10.5.0/03:00:00";
boost::local_time::time_zone_ptr kaliningrad_tzone_posix(new boost::local_time::posix_time_zone(kaliningrad_string));
std::string vladivostok_string = "VLAT+10:00:00VLAST+01:00:00,M3.5.0/02:00:00,M10.5.0/03:00:00";
boost::local_time::time_zone_ptr vladivostok_tzone_posix(new boost::local_time::posix_time_zone(vladivostok_string));

Создание часовых поясов с использованием строковой спецификации часовых поясов выглядит более сложным, но вы можете использовать его, если не можете найти конкретный часовой пояс в date_time_zonespec.csv. Например, до марта 2010 года Самара была в формате UTC+4, а теперь в формате UTC+3. date_time_zonespec.csv не имеет истории изменений, поэтому в этой ситуации необходимо создать часовой пояс из спецификации строки. Однако я помню, что у ICU, кажется, есть часовые пояса с такой историей ICU TimeZone Classes:

Данные о часовых поясах часто меняются в ответ на то, что правительства по всему миру меняют свои местные правила и области, в которых они применяются. Данные о часовом поясе ICU обновляются для каждого выпуска, и самый простой способ оставаться в курсе — это обновиться до последней версии ICU, которая также содержит исправления ошибок, улучшения кода и дополнительные функции.


3) Установите нужное местное время, например

local_date_time tmp(boost::gregorian::date(2010, 3, 28), boost::posix_time::time_duration(1,59,0),nyc, boost::local_time::local_date_time::EXCEPTION_ON_ERROR);

4) А затем вычислить разницу, используя функции utc_time и local_time
На этой странице есть пример:

ptime pt(date(2004,Nov,5), 
         hours(10));
time_zone_ptr zone(new posix_time_zone("MST-07"));
local_date_time az(pt, zone);
az.utc_time(); // 10am 2004-Nov-5
az.local_time(); // 3am 2004-Nov-5


5) Другой пример. Местное время то же самое, но UTC отличается

local_date_time tmp(boost::gregorian::date(2010, 3, 28), boost::posix_time::time_duration(1,59,0),kaliningrad_tzone_posix, boost::local_time::local_date_time::EXCEPTION_ON_ERROR);
std::cout << "As is: " << tmp << ", UTC: "  << tmp.utc_time() << std::endl;

local_date_time tmp(boost::gregorian::date(2010, 3, 28), boost::posix_time::time_duration(1,59,0),vladivostok_tzone_posix, boost::local_time::local_date_time::EXCEPTION_ON_ERROR);
std::cout << "As is: " << tmp << ", UTC: "  << tmp.utc_time() << std::endl;
person Community    schedule 12.11.2010

Убедитесь, что все время конвертировано в формат UTC (см., например, mktime()). Затем вы можете использовать либо difftime(), либо timeval_subtract пример функции по той же ссылке, в зависимости от того, в какой структуре хранится время.

person Flexo    schedule 12.11.2010