(Язык / API: Стандартная библиотека C 89 и / или POSIX)
Возможно, это тривиальный вопрос, но у меня такое ощущение, что я что-то упустил.
Мне нужно реализовать эту функцию:
time_t get_local_midnight_timestamp(time_t ts);
То есть мы получаем произвольную метку времени (например, из прошлого года) и возвращаем ее с округлением до полуночи того же дня.
Проблема заключается в том, что функция должна знать о переключателях DST и изменениях правил DST (например, об отмене и / или расширении DST).
Функция также должна быть ориентирована на будущее и справляться со странными изменениями TZ (такими как смещение часового пояса на 30 минут вперед и т. Д.).
(Причина, по которой мне нужно все это, для реализации, искать в более старых статистических данных.)
Насколько я понимаю, наивный подход с обнулением struct tm
полей временине работает - именно из-за летнего времени (похоже, что в день смены летнего времени есть две локальные метки времени time_t в полночь).
Пожалуйста, укажите мне правильное направление ...
Я сомневаюсь, чтоэто может быть сделано со стандартом C 89, так что POSIX-специфичные решения являются приемлемыми.Если не POSIX, то что-то специфичное для Debian будет делать ...
Обновление: Также: что-то подсказывает мне, что я должен также учитывать дополнительные секунды.Может быть, я должен попытаться напрямую использовать Tz базу данных ... (что довольно печально - так много / воспринимается / накладных расходов для такой маленькой задачи.) ... Или нет - кажется, что libc должен использовать этотак что, возможно, я просто делаю это неправильно ...
Обновление 2: Вот почему я думаю, что наивное решение не работает:
#include <stdio.h>
#include <time.h>
int main()
{
struct tm date_tm;
time_t date_start = 1301173200; /* Sunday 27 March 2011 0:00:00 AM MSK */
time_t midnight = 0;
char buf1[256];
char buf2[256];
int i = 0;
for (i = 0; i < 4 * 60 * 60; i += 60 * 60)
{
time_t date = date_start + i;
localtime_r(&date, &date_tm);
strftime(buf1, 256, "%c %Z", &date_tm);
date_tm.tm_sec = 0;
date_tm.tm_min = 0;
date_tm.tm_hour = 0;
midnight = mktime(&date_tm);
strftime(buf2, 256, "%c %Z", &date_tm);
printf("%d : %s -> %d : %s\n", (int)date, buf1, (int)midnight, buf2);
}
}
Вывод(местное время было MSD в тот момент, когда я запускаю это):
$ gcc time.c && ./a.out
1301173200 : Sun Mar 27 00:00:00 2011 MSK -> 1301173200 : Sun Mar 27 00:00:00 2011 MSK
1301176800 : Sun Mar 27 01:00:00 2011 MSK -> 1301173200 : Sun Mar 27 00:00:00 2011 MSK
1301180400 : Sun Mar 27 03:00:00 2011 MSD -> 1301169600 : Sat Mar 26 23:00:00 2011 MSK
1301184000 : Sun Mar 27 04:00:00 2011 MSD -> 1301169600 : Sat Mar 26 23:00:00 2011 MSK
Как видите, две ночи.