Здравствуйте. Давно свою задачу решил (начало тут: http://www.linux.org.ru/forum/development/5150307 ), но всё руки не доходили описать конкретно, что было нужно и как удалось достичь результата.
Итак, задача ставилась таким образом: перевести произвольно взятую дату/время из UTC в локальное время системы и обратно. Казалось бы задача совсем тривиальная, однако есть некоторые нюансы.
Судя по всему, исторически так сложилось, что структура данных time_t автоматически предполагает, что дата/время в этой структуре представлено только и исключительно в UTC, хотя ничего и не мешает эти секунды отсчитывать от 1 января 1970 года в любом часовом поясе. Для представления же локального времени используются другие структуры, но не time_t. Таким образом, функции преобразования времени из локального в UTC и обратно требуют разных типов данных для входных и выходных параметров.
В моём же случае дата/время были представлены в структуре, которая использовалась как для хранения времени в формате UTC, так и для локального времени, и мне была необходима функция, принимающая и отдающая дату в одном и том же формате, но осуществляющая «сдвиг» времени в нужном направлении и на нужное количество часов. Задача, таким образом, свелась к необходимости конвертации формата даты во всех возможных направлениях, и вызова нужных функций преобразования, однако количество подводных камней впечатляет. Здесь приведу то, что получилось в сухом остатке.
Для фактического преобразования из UTC в локальное время использовалась функция struct tm* localtime_r( const time_t* timer, struct tm* result ); (просто localtime не может быть использована в многопоточных приложениях, поскольку использует свой внутренний буфер). Грабля, на которую я наступил, была связана с тем, что эта функция повреждает области памяти, расположенные рядом с переданными ей структурами, пришлось вставлять PAD-ы. Вторая грабля - возвращаемый функцией в структуре tm номер года начинается с 1900 (т.е. 0 в результате=1900год, 110 в результате=2010год), а месяц - с нуля (0=январь). Неочевидно, и при чтении манов на глаза не попадалось.
Для обратного преобразования из локального времени в UTC использовалась функция time_t mktime ( struct tm * timeptr ); Здесь тоже без граблей не обошлось: в структуре tm есть поле is_dst, указывающее, включено ли летнее время. Оно должно быть установлено _до_ вызова mktime, однако его значение для произвольной даты заранее неизвестно. К счастью, это поле функция выставляет сама в процессе работы, но если переданное значение изначально было неверным, то и результат тоже получается неверным. Таким образом, для правильного преобразования функцию необходимо вызвать дважды - первый раз она выставит в правильное значение флаг is_dst, но, возможно вернет неверный результат, а второй вызов уже с правильным значением dst возвращает правильный результат. Между вызовами все поля структуры tm (кроме is_dst) нужно инициализировать заново, т.к. функция их модифицирует, приводя время к правильному (по её мнению) значению в зависимости от флага is_dst.