Преобразование даты, введенной человеком, в значение
time_t
трудно: надо принять во внимание високосные годы, учесть часовые пояса и т.д. Поэтому стандарт C89 ввел функцию
mktime()
:
#include <time.h> /* ISO С */
time_t mktime(struct tm *tm);
Для использования
mktime()
укажите в
struct tm
соответствующие значения — год, месяц, день и т.д. Если вы знаете, действовало ли для данной даты летнее время, установите соответствующим образом поле
tm_isdst
: 0 для «нет» и положительное значение для «да». В противном случае, используйте отрицательное значение для «не знаю». Поля
tm_wday
и
tm_yday
игнорируются.
mktime()
предполагает, что
struct tm
представляет локальное время, не UTC. Она возвращает значение
time_t
, представляющее переданные дату и время, или
(time_t)(-1)
, если данные дата/время не могут быть правильно представлены. После успешного возвращения все значения
struct tm
выверены на попадание в правильные диапазоны, a
tm_wday
и
tm_yday
также корректно установлены. Вот простой пример:
1 /* ch06-echodate.c --- демонстрирует mktime(). */
2
3 #include <stdio.h>
4 #include <time.h>
5
6 int main(void)
7 {
8 struct tm tm;
9 time_t then;
10
11 printf("Enter a Date/time as YYYY/MM/DD HH:MM:SS : ");
12 scanf("%d/%d/%d %d:%d:%d",
13 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
14 &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
15
16 /* Проверка ошибок значений для краткости опущена. */
17 tm.tm_year -= 1900;
18 tm.tm_mon--;
19
20 tm.tm_isdst = -1; /* He знаю о летнем времени */
21
22 then = mktime(&tm);
23
24 printf("Got: %s", ctime(&then));
25 exit(0);
26 }
В строке 11 запрашиваются дата и время, а в строках 12–14 соответствующие значения считываются. (В коде изделия возвращаемые
scanf()
значения должны проверяться.) Строки 17 и 18 компенсируют различную базу для лет и месяцев соответственно. Строка 20 указывает, что мы не знаем, представляют ли данные дата и время летнее время. Строка 22 вызывает
mktime()
, а строка 24 выводит результат преобразования. После компилирования и запуска мы видим, что это работает:
$ <b>ch06-echodate</b>
Enter a Date/time as YYYY/MM/DD HH:MM:SS : 2003/5/25 19:07:23
Got: Sun May 25 19:07:23 2003
6.1.5. Получение сведений о часовом поясе
На ранних системах Unix сведения о часовом поясе внедрялись в ядро при компиляции. Правила перехода на летнее время обычно были жестко вшиты в код, что создавало трудности для пользователей вне Соединенных Штатов или в местах внутри Соединенных Штатов, в которых не осуществлялся переход на летнее время.
В современных системах эти сведения выделены в двоичные файлы, которые читаются библиотекой С при извлечении функций, связанных со временем. Эта методика позволяет избежать необходимости в перекомпилировании библиотек и системных файлов при изменении правил и гораздо упрощает обновление правил.
Интерфейс языка С для сведений о часовых поясах развивался в разных версиях Unix, как на System V, так и Berkley, пока, наконец, не был стандартизован POSIX следующим образом.
#include <time.h> /* POSIX */
extern char *tzname[2];
extern long timezone;
extern int daylight;
void tzset(void);
Функция
tzset()
проверяет переменную окружения
TZ
для получения сведений о часовом поясе и переходе на летнее время.
[65] Если эта переменная не установлена,
tzset()
использует «определенный в реализации часовой пояс по умолчанию», который скорее всего является часовым поясом машины, на которой вы работаете.
После вызова
tzset()
сведения о локальном часовом поясе доступны в нескольких переменных:
extern char *tzname[2]
Стандартное имя и имя летнего времени для часового пояса. Например, для областей США в восточном часовом поясе именами часового пояса являются 'EST' (Eastern Standard Time) и 'EDT' (Eastern Daylight Time).
extern long timezone
Разница в секундах между текущим часовым поясом и UTC. Стандарт не определяет, как эта разница работает. На практике отрицательные значения представляют часовые пояса восточнее (перед, или те, которые позже) UTC; положительные значения представляют часовые пояса западнее (за, или те, которые раньше) UTC. Если вы посмотрите на это значение как «насколько изменить местное время, чтобы оно стало равно UTC», тогда знак этого значения имеет смысл.
extern int daylight
Эта переменная равна нулю, если правила перехода на летнее время никогда не должны использоваться для данного часового пояса, и не равны нулю в противном случае.
ЗАМЕЧАНИЕ. Переменная
daylight
не означает, действует ли в настоящий момент летнее время! Вместо этого она просто констатирует, может ли текущий часовой пояс вообще иметь летнее время.
Стандарт POSIX указывает, что
ctime()
,
localtime()
,
mktime()
и
strftime()
действуют, «как если бы» они вызывали
tzset()
. Это означает, что им в действительности не нужно вызывать
tzset()
, но они должны вести себя, как если бы эта функция была вызвана. (Формулировка призвана дать определенную гибкость при реализации, в то же время гарантируя правильное поведение кода уровня пользователя.)