Ctime дать календарное время


Содержание

Ctime дать календарное время

Время процесса (process time) — количество процессорного времени, использованного процессом. Иногда его делят на пользовательское (user) и системное (system). Пользовательское время ЦП — это время, потраченное на исполнение кода в режиме пользователя. Системное время ЦП — это время, потраченное ядром, выполняющемся в системном режиме, для процесса (например, на обработку системных вызовов). Команда time(1) позволяет определить количество процессорного времени, затраченного при выполнении программы. Программа может определить количество потраченного процессорного времени с помощью times(2), getrusage(2) или clock(3).

Аппаратные часы

Программные часы, HZ и миги (jiffies)

Значение HZ различно в разных версиях ядра и аппаратных платформах. Для i386: в ядрах до версии 2.4.x включительно, HZ равно 100, то есть значение мига равно 0.01 секунды; начиная с версии 2.6.0 значение HZ увеличено до 1000 и миг равен 0.001 секунды. Начиная с ядра 2.6.13 значение HZ задаётся в параметре настройки ядра и может быть равно 100, 250 (по умолчанию) или 1000, что делает значение мига равным, соответственно, 0.01, 0.004 или 0.001 секунды. Начиная с ядра 2.6.20 добавлено ещё одна частота: 300, количество, которое делится нацело на распространённые частоты видеокадров (PAL — 25 HZ; NTSC — 30 HZ).

Системный вызов times(2) — это особый случай. Он выдаёт время с точностью, определяемой константой ядра USER_HZ. Приложения пользовательского пространства могут определить значение этой константы с помощью sysconf(_SC_CLK_TCK).

Таймеры высокой точности

Начиная с Linux 2.6.21, Linux поддерживает таймеры высокой точности (HRT), включаемые через CONFIG_HIGH_RES_TIMERS. В системе, которая поддерживает HRT, точность сна и таймеров в системных вызовах больше не ограничена мигом, а только точностью аппаратуры (в современной аппаратуре, обычно, микросекундная точность). Вы можете определить поддерживаются ли таймеры высокой точности, проверив результат вызова clock_getres(2) или поискав записи «resolution» в /proc/timer_list.

HRT поддерживаются не на всех аппаратных архитектурах (среди имеющих отметим x86, arm и powerpc).

Эпоха

Программа может определить календарное время c помощью вызова gettimeofday(2), который возвращает время (в секундах и микросекундах), прошедшее с начала эпохи; вызов time(2) выдаёт подобную информацию, но с точностью только до ближайшей секунды. Системное время можно изменять с помощью settimeofday(2).

Календарное время, разделённое на компоненты

Таймеры сна и их установка

Различные системные вызовы позволяют процессу устанавливать таймеры, которые срабатывают в какой-то момент в будущем, и, возможно, через определённые интервалы; смотрите alarm(2), getitimer(2), timerfd_create(2) и timer_create(2).

Ctime дать календарное время

Стандартная библиотека C/C++ включает ряд функций, работающих с датой и временем, а также функции, обрабатывающие геополитическую информацию, связанную с программой. Именно этим функциям и посвящена данная глава.

В языке С использование функций даты и времени требует включения заголовка , а в языке C++ — заголовка . В этой главе для простоты изложения используются имена С-заголовков, но ссылки на заголовок в соответствующей среде нужно заменить ссылками на заголовок .

В заголовке определены три типа данных, связанных с исчислением времени: clock_t, time_t и tin. Типы clock_t и time_t предназначены для представления системного времени и даты в виде некоторого целого значения, называемого календарным временем. Тип структуры tm содержит дату и время в виде разбиения на элементы. Итак, структура tm содержит следующие члены.

Значение tm_isdst положительно, если действует режим летнего времени(Daylight Saving Time), равно нулю, если не действует, и отрицательно, если информация об этом недоступна.

Кроме того, в заголовке определен макрос CLOCKS_PER_SEC, который выдает количество тиканий системных часов в секунду.

Для работы с функциями геополитической среды необходимо использовать в языке С заголовок , а в языке C++ — заголовок . В этих заголовках определена структура lconv, которая приведена в описании функции localeconv().

Список функций

asctime — Возвращает указатель на строку, которая содержит информацию о дате и времени
clock — Возвращает значение, которое приблизительно соответствует продолжительности времени работы вызывающей программы
ctime — Возвращает указатель на строку, которая содержит информацию о дате и времени
difftime — Возвращает значение разности в секундах между значениями заданных параметров
gmtime — Возвращает указатель на поэлементную форму параметра time в виде структуры tm
localeconv — Возвращает указатель на структуру типа, которая содержит различную информацию о геополитической среде
localtime — Возвращает указатель на поэлементную форму параметра time в виде структуры tm
mktime — Возвращает эквивалент календарного времени на основе времени, заданного в поэлементном виде и хранимого в структуре, которая адресуется параметром time
setlocale — Позволяет запросить или установить определенные параметры, которые зависят от геополитической среды выполнения программы
strftime — Помещает информацию о времени и дате(вместе с другой информацией) в строку
time — Возвращает текущее календарное время системы

mktime — Возвращает метку времени Unix для заданной даты

(PHP 4, PHP 5, PHP 7)

mktime — Возвращает метку времени Unix для заданной даты

Описание

Функция возвращает метку времени Unix, соответствующую дате и времени, заданным аргументами. Метка времени — это целое число, равное разнице в секундах между заданной датой/временем и началом Эпохи Unix (The Unix Epoch, 1 января 1970 00:00:00 GMT).

Аргументы могут быть опущены в порядке справа налево. В этом случае их значения по умолчанию равны соответствующим компонентам локальной даты/времени.

Примечания

Начиная с версии PHP 5.1, если mktime() вызывается без аргументов, то будет сгенерировано замечание уровня E_STRICT . Используйте вместо этого функцию time() .

Список параметров

Количество часов, прошедших с начала дня, указанного параметрами month , day и year . Отрицательные значения определяют часы до полуночи указанного дня. Значения большие 23 определяют соответствующий час следующего дня (или дней).

Количество минут, прошедших от начала часа, указанного параметром hour . Отрицательные значения определяют минуты предыдущего часа. Значения большие 59 определяют соответствующие минуты следующего часа (или часов).

Количество секунд, прошедших от начала минуты, указанной параметром minute . Отрицательные значения определяют секунды из предыдущей минуты. Значения большие 59 определяют соответствующие секунды следующей минуты (или минут).

Количество месяцев, прошедших с конца предыдущего года. Значения от 1 до 12 определяют нормальные обычные календарные месяцы года. Значения меньшие 1 (включая отрицательные значения) определяют месяца предыдущего года в обратном порядке, т.е. 0 будет декабрем, -1 — ноябрем и т.д. Значения больше 12 определяют соответствующий месяц в следующем году (или годах).

Количество дней, прошедших с конца предыдущего месяца. Значения от 1 до 28, 29, 30 или 31 (в зависимости от месяца) определяют нормальные дни соответствующего месяца. Значения меньшие 1 (включая отрицательные значения) определяют дни предыдущего месяца, таким образом, 0 является последним днем предыдущего месяца, -1 — предпоследним днем предыдущего месяца и т.д. Значения большие количества дней соответствующего месяца определяют соответствующий день следующего месяца (или месяцев).

Номер года, может быть указан двумя или четырьмя цифрами, причем значения между 0-69 будут трактованы как 2000-2069, а между 70-100 — как 1970-2000. На тех системах, где time_t является 32-битным знаковым целым (наиболее распространенный вариант на сегодня), корректный диапазон для параметра year содержит даты где-то между 1901 и 2038. Однако, до версии PHP 5.1.0, на некоторых системах этот диапазон был ограничен датами между 1970 и 2038 (например, Windows).

Данный параметр может быть установлен в 1, если заданной дате соответствует летнее время (DST), 0 в противном случае, или -1 (значение по умолчанию), если неизвестно, действует ли летнее время на заданную дату. В последнем случае PHP пытается определить это самостоятельно. Это можно привести к неожиданному результату (который, тем не менее, не будет неверным). Некоторые даты могут быть неверными, если летнее время применимо к системе, на которой запущен PHP, или параметр is_dst установлен в 1. Если переход на летнее время происходит, например, в 2:00, все даты между 2:00 и 3:00 станут некорректными и mktime() вернет неопределенное (обычно отрицательное) значение. Некоторые системы (например, Solaris 8) осуществляют переход на летнее время в полночь, так что время 0:30 дня, когда был осуществлен переход на летнее время будет обрабатываться как 23:30 предыдущего дня.


Начиная с версии PHP 5.1.0 этот параметр более не рекомендуется к использованию. Вместо этого рекомендуется устанавливать соответствующую временную зону.

Возвращаемые значения

mktime() возвращает временную метку Unix в соответствии с переданными аргументами. Если были переданы некорректными аргументы, функция вернет FALSE (до версии PHP 5.1 возвращалась -1).

Ошибки

Каждый вызов к функциям даты/времени при неправильных настройках временной зоны сгенерирует ошибку уровня E_NOTICE , и/или ошибку уровня E_STRICT или E_WARNING при использовании системных настроек или переменной окружения TZ . Смотрите также date_default_timezone_set()

Список изменений

Теперь ошибки, связанные с временными зонами, генерируют ошибки уровня E_STRICT и E_NOTICE .

Примеры

Пример #1 Пример использования функции mktime()

// Устанавливаем используемую по умолчанию временную зону. Доступно, начиная с версии PHP 5.1
date_default_timezone_set ( ‘UTC’ );

// Выводит: July 1, 2000 is on a Saturday
echo «July 1, 2000 is on a » . date ( «l» , mktime ( 0 , 0 , 0 , 7 , 1 , 2000 ));

// Выводит что-то вроде: 2006-04-05T01:02:03+00:00
echo date ( ‘c’ , mktime ( 1 , 2 , 3 , 4 , 5 , 2006 ));
?>

Пример #2 mktime() example

Функцию mktime() удобно использовать для выполнения арифметических операций с датами, так как она вычисляет верные значения при некорректных аргументах. Например, в следующем примере каждая строка выведет «Jan-01-1998».

Пример #3 Последний день месяца

Последний день любого месяца можно вычислить как «нулевой» день следующего месяца, не -1 день. Оба приведенных ниже примера выведут «Последний день февраля 2000 г.: 29».

Примечания

До версии PHP 5.1.0, отрицательные временные метки не поддерживались ни под одной известной версией Windows, а также и некоторыми другими системами. Таким образом, диапазон корректных лет был ограничен датами от 1970 до 2038 г.

Смотрите также

  • checkdate() — Проверяет корректность даты по григорианскому календарю
  • gmmktime() — Возвращает метку времени Unix для времени по Гринвичу
  • date() — Форматирует вывод системной даты/времени
  • time() — Возвращает текущую метку времени Unix

Время

Функций для работы со временем в языке C++ несколько. Рассмотрим некоторые из них.

Первая это функция clock(), которая подключается к проекту с помощью заголовочного файла . Она позволяет вывести время работы программы к определенному моменту. С помощью этого можно вычислять, сколько времени затрачено на тот или иной участок кода. Рассмотрим пример.

Здесь вычисляется затраченное время путем сравнения значения clock() перед началом участка кода и после его конца. Так как clock() показывает время прошедшее с начала программы, остается только такой способ.

Если необходимо не внутреннее время программы, а календарное, то можно использовать функцию time(). Она возвращает текущую дату и время, но делает это в секундах, а если точнее, то выводит количество секунд, прошедшее с 00:00 1 января 1970 года.

Как получить системное время и дату?

В поиске искал и не нашел. Вопрос, значит, такой:

Есть у меня допустим класс t_and_d и в него входят 2 переменные.
в одну необходимо передать текущее системное время, и во вторую текущую системную дату. Как это сделать с помощью стандартных библиотечных функций времени и даты?

Версия Описание
5.3.0 mktime() теперь выбрасывает ошибку уровня E_DEPRECATED при использовании параметра is_dst .
5.1.0 Параметр is_dst теперь считается устаревшим. Функция теперь возвращает FALSE при ошибке, тогда как раньше возвращалась -1. Теперь функция принимает дату с одновременно установленными в ноль годом, месяцем и днем.
5.1.0 Если mktime() была вызвана без аргументов, то будет сгенерировано замечание уровня E_STRICT . Используйте вместо этого функцию time() .
5.1.0 30.12.2008, 14:02

Получить системное время
здравствуйте. как/с помощью какой функции можно полям своей структуры присвоить значения.

Как можно получить дату и время создания файла и его объем?
Здравствуйте! Скажите пожалуйста как можно получить дату и время создания файла и его объем. Задача.

Как в программе можно изменить системное время компьютера?
Как в программе можно изменить системное время компьютера?

Ввести время и от него отнять системное время
Необходимо ввести время и от него отнять системное время,необходимо сделать так Введите часы : 17.

Системное время
как взять системное время в милисикундах?

30.12.2008, 14:27 2
30.12.2008, 15:03 [ТС] 3

30.12.2008, 15:16 4
30.12.2008, 15:16
30.12.2008, 15:19 [ТС] 5
30.12.2008, 15:30 6

блин, что меня все в билдер тянет.
dos.h
gettime и getdate

30.12.2008, 16:42 [ТС] 7

Я нашел функцию time . она присваивает вроде календарное время. Но только не понял, пока как ее применить.

У меня вообще вот такая задача вообще:

Создайте класс t_and_d, которому при его создании передается текущее системное время и дата в виде параметров конструктора. Этот класс должен включать в себя функцию-член, выводящую время и дату на экран.
(Подсказка: Для нахождения и вывода на экран этих данных воспользуйтесь стандартной бибилиотечной функцией времени и даты.)

Собственно структуры использовать нельзя, пока что. Я знаю все как оформить и сделать, но как присвоить переменным вот именно дату и время системные не знаю.

Класс CTime – дата и время

Класс CTime – дата и время

Для работы с календарными датами и временем в состав библиотеки классов MFC включен класс CTime. Класс основан на элементе типа time_t, в котором будет храниться дата и время. Элемент типа time_t объявлен как private, поэтому вы не можете обращаться непосредственно к этому элементу. Для этого в состав класса CTime входит набор методов.

Класс CTime включает несколько конструкторов, которые можно использовать для создания и инициализации объектов данного класса. Выберите тот конструктор, который наиболее удобен в каждом конкретном случае.

Если вам требуется создать массив, состоящий из объектов класса CTime, используйте конструктор без указания параметров:

Объекты, созданные этим конструктором не инициализированы. Перед тем как ими пользоваться, запишите в них дату и время:

Параметр timeSrc определяет уже существующий объект класса CTime. Новый объект класса инициализируется значением даты и времени, взятым из существующего объекта.

Если в программе уже существует переменная типа time_t, в которой хранится значение, то можно создать новый объект класса CTime, основываясь на этой переменной:

Параметр time определяет переменную типа time_t, значение которой будет записано в создаваемый объект.

Если существует несколько переменных, в которых отдельно хранятся год, месяц, день, часы, минуты и секунды, то можно создать объект класса CTime, сразу же записав в него значения из этих переменных:

CTime(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec, int nDST = –1);

Первые 6 параметров метода определяют время и дату. Параметр nYear должен содержать год, nMonth – месяц, nDay – день, nHour – час, nMin – минуты, nSec – секунды. NYear может принимать значения от 1900 до 2038, nMonth – от 1 до 12 и nDay от 1 до 31.

Параметр nDST управляет режимом перехода на летнее время. Если nDST содержит нуль, то время представляется в стандартном виде, режим перехода на летнее время не используется. Чтобы включить этот режим, параметр nDST должен содержать значение, больше нуля. Параметр nDST является необязательным. Если его не указать, считается, что он равен нулю. В этом случае конструктор самостоятельно определяет режим перехода на летнее время.

Следующий конструктор позволяет создать объект класса CTime и записать в него дату и время, определенные в формате, принятом в операционной системе MS-DOS:

CTime(WORD wDosDate, WORD wDosTime, int nDST = –1);

Параметры wDosDate и wDosTime должны содержать, соответственно, дату и время в формате MS-DOS. Параметр nDST управляет режимом перехода на летнее время. Мы уже рассматривали его выше.

Кроме класса CTime, существует, как минимум, еще две структуры, в которых может храниться значения даты и времени. Первая такая структура называется SYSTEMTIME. В ней хранятся текущие значения даты и времени. Структура SYSTEMTIME определена следующим образом:

typedef struct _SYSTEMTIME <

WORD wYear; // год

WORD wMonth; // месяц

WORD wDayOfWeek; // день недели

WORD wDay; // календарная дата

WORD wHour; // часы

WORD wMinute; // минуты

WORD wSecond; // секунды

WORD wMilliseconds; // миллисекунды

Если необходимо создать объект класса CTime, сразу записав в него текущие значения времени и даты, используйте конструктор, представленный ниже:

Параметр sysTime является указателем на структуру типа SYSTEMTIME. Необязательный параметр nDST управляет режимом отсчета даты и описан нами выше.

Вторая структура, в которой хранятся значения даты и времени, называется FILETIME. Она служит для хранения 64-битового числа, представляющего дату и время как количество 100 наносекундных интервалов времени, прошедших с первого января 1601 года.


Linux.yaroslavl.ru

Эта глава описывает функции для управления датой и временем, включая функции для определения текущего времени и преобразование между различными представлениями времени.

Функции времени относятся к трем категориям:

  • Функции для измерения прошедшего времени CPU обсуждены в Разделе 17.1 [Время Процессора].
  • Функции календарного времени обсуждены в Разделе 17.2 [Календарное Время].
  • Функции для установки будильников и таймеров обсуждены в Разделе 17.3 [Установка Сигнализации].

Если вы пробуете оптимизировать вашу программу или измерять эффективность, очень полезно знать, сколько времени процессора или CPU времени она использовала в любой заданной точке. Процессорное время является отличным от фактических часов, потому что оно не включает все потраченное время на ожидание ввода-вывода или когда выполняется некоторый другой процесс. Процессорное время представляется типом данных clock_t, и дано как ряд импульсов времени относительно произвольного базового времени, отмечающего начало одиночного вызова программы.

Запрос Основного Времени CPU

Чтобы получить прошедшее CPU время, используемое процессом, Вы можете использовать функцию clock. Это средство объявлено в заглавном файле » time.h «.

Обычно, Вы вызываете функцию clock в начале и конца интервала, который Вы хотите измерить, вычитаете значения, и тогда делите на CLOCKS_PER_SEC (число импульсов времени clock в секунду), примерно так:

В системе GNU, clock _t эквивалентен long int, а CLOCKS_PER_SEC — целочисленное значение. Но в других системах, и clock _t и тип макрокоманды CLOCKS_PER_SEC может быть или целое число, или с плавающей точкой. Приведением значения времени процессора к double, см. пример выше, удостоверяется, что нужные операции работают правильно и последовательно независимо от того, каково основное представление.

Детализированный Запрос Времени CPU

Функция times возвращает более детализированную информацию относительно прошедшего процессорного времени в struct tmsobject. Вы должны включить заглавный файл » sys/times.h » чтобы использовать это средство.

Все времена даны в импульсах сигналов времени. Они — абсолютные значения; в новом процессе, они — все нуль. См. Раздел 23.4 [Создание Процесса].

Возвращаемое значение — также как значение clock (): прошедшее реальное время относительно произвольной основы. Основа — константа внутри специфического процесса, и обычно представляет время начиная с запуска системы. Значение (clock_t) (-1) возвращается, чтобы указать отказ.

Примечание Переносимости: функция clock, описанная в Разделе 17.1.1 [Базисное процессорное Время], определена в соответствии c стандартом ANSI C. Функция times — возможность POSIX.1. В системе GNU, значение, возвращенное функцией clock эквивалентно сумме tms_utime и tms_stime полей, возвращенных times.

Этот раздел описывает средства для слежения за датами и временем согласно Грегорианскому календарю.

Имеются три представления информации даты и времени:

  • Календарное время (time_t тип данных) — компактное представление, обычно дает число секунд, истекающих начиная с некоторого основного времени.
  • Имеется также представление времени с высоким разрешением (struct timeval тип данных) которое включает доли секунды. Используйте это представление времени вместо обычного календарного времени, когда нужна большая точность.
  • Местное время (struct tm тип данных) представляет дату и время как набор компонентов, определяющих год, месяц, и так далее, для специфического часового пояса. Это представление обычно используется вместе с форматированием значений даты и времени.

Простое Календарное Время

Этот раздел описывает time_t тип данных для представления календарного времени, и функции, которые используют объекты календарного времени. Эти средства объявлены в заглавном файле » time.h «.

В других системах, time_t может быть или целым числом или с плавающей запятой.

В системе GNU, Вы можете просто вычитать значения time_t. Но в других системах, time_t тип данных может использовать некоторое другое кодирование, где вычитание не работает непосредственно.

Календарь с высоким разрешением

Тип данных time_t, используемый, чтобы представить календарное вермя имеет разрешающую способность только в одну секунду.

Некоторые приложения нуждаются в большей точности.

Так, библиотека GNU C также содержит функции, которые способны представить календарь с более высокой разрешающей способностью чем одна секунда. Функции и связанные типы данных, описанные в этом разделе объявлены в » sys/time.h «.

Некоторые значения struct timeval — используются для временных интервалов. Тогда tv_sec элемент — число секунд в интервале, а tv_usec — число микросекунд.

Часто необходимо вычесть два значения типа struct timeval. Вот самый лучший способ делать это. Он работает даже на некоторых специфических операционных системах, где tv_sec элемент имеет тип unsigned.

Возвращаемое значение — 0 при успехе и -1 при отказе. Следующее errno условие ошибки определено для этой функции: ENOSYS

операционная система не поддерживает получение информации часового пояса, и tzp — не пустой указатель. Операционная система GNU не поддерживает использование struct timezoneto для представления информации часового пояса; это — устаревшая возможность 4.3 BSD. Вместо этого, используйте средства, описанные в Разделе 17.2.6 [Функции Часового пояса].

Вы должны быть привилегированным пользователем, чтобы использовать settimeofday.

Возвращаемое значение — 0 при успехе и -1 при отказе. Следующие errno условия ошибки определены для этой функции: EPERM

Этот процесс не может устанавливать время, потому что он не привилегированный. ENOSYS

операционная система не поддерживает установку информации часового пояса, и tzp — не пустой указатель.

Аргумент delta определяет относительную корректировку, которая будет сделана относительно текущего времени. Если он отрицателен, часы системы замедляются. Если положителен, часы системы ускоряются.

Если аргумент olddelta — не пустой указатель, функция adjtime, возвращает информацию относительно любой предыдущей корректировки, которая еще не завершилась.

Эта функция обычно используется, чтобы синхронизировать часы компьютеров в местной сети.

Вы должны быть привилегированным пользователем, чтобы использовать ее. Возвращаемое значение — 0 при успехе и -1 при отказе. Следующее errno условие ошибки определено для этой функции: EPERM

Вы не имеют привилегий, чтобы установить время. Примечание Переносимости: функции gettimeofday, settimeofday, и adjtime — из BSD.


Разделенное Время

Календарное время представляется как число секунд. Это удобно для вычисления, но не имеет никакого отношения к способу, которым люди обычно представляют даты и время. Нпротив, разделенное время ­ двоичное представление, разделенное на год, месяц, день, и так далее.

Разделенное время всегда зависит от выбора зоны местного времени, и оно также указывает, какой часовой пояс использовался.

Символы в этом разделе объявлены в заглавном файле » time.h «.

Tm_gmtoff поле ­ расширение библиотеки GNU.

Возвращаемое значение — указатель на статическую структуру разделенного времени, которая могла бы быть записана поверх последующими обращениями к любой из функций date и time. (Но никакая другая библиотечная функция не записывает поверх содержимого этого объекта.)

Вызов localtime имеет и другой эффект: она устанавливает переменную tzname с информацией относительно текущего часового пояса. См. Раздел 17.2.6 [Функции Часового пояса].

Вспомните, что календарное время всегда выражается в координированном универсальном времени.

Mktime функция игнорирует заданное содержимое tm_wday и tm_yday элементов структуры разделенного времени. Она использует значения других компонентов, чтобы вычислить календарное время; для этих компонентов допустимо иметь ненормализованные значения вне их нормальных диапазонов. Еще mktime корректирует компоненты структуры brokentime (включая tm_wday и tm_yday).

Если заданное разделенное время не может представляться как календарное время, mktime, возвращает значение (time_t) (-1) и не изменяет содержимое brokentime.

Вызов mktime также устанавливает переменную tzname с информацией относительно текущего часового пояса. См. Раздел 17.2.6 [Функции Часового пояса].

Форматирование Даты и времени

Функции, описанные в этом разделе форматирнуют значения времени как строки. Эти функции объявлены в заглавном файле » time.h «.

Сокращения для месяцев: `Jan’, `Feb’, `Mar’, `Apr’, `May’, `Jun’, `Jul’, `Aug’, `Sep’, `Oct’, `Nov’, and `Dec’.

Возвращаемое значение указывает на статически размещенную строку, которая могла бы быть записана поверх последующими обращениями к любой из функций date и time. (Но никакая другая библиотечная функция не записывает поверх содержимого этой строки.)

Обычные символы, появляющиеся в шаблоне копируются в строку вывода s; она может включать многобайтовые символы. Спецификаторы Преобразования представляются символом ` % ‘, и заменяются в строке вывода следующим образом:

  • %a сокращенный день недели согласно текущему стандарту.
  • %A полный день недели согласно текущему стандарту.
  • %b сокращенный месяц согласно текущему стандарту.
  • %B полное название месяца согласно текущему стандарту.
  • %c привилегированное представление даты и времени для текущего стандарта.
  • %d день месяца как десятичное число (от 01 до 31).
  • %H час как десятичное число, используя 24-часовые часы (от 00 до 23).
  • %I час как десятичное число, используя 12-часовые часы (от 01 до 12).
  • %j день года как десятичное число (от 001 до 366).
  • %m месяц как десятичное число (от 01 до 12).
  • %M минуты как десятичное число.
  • %p Или «am» или «pm», согласно данному значению времени; или соответствующие строки для текущего стандарта.
  • %S секунды как десятичное число.
  • %U число недель текущего года как десятичное число, начинающееся с первого воскресенья как первый день первой недели.
  • %W число недель текущего года как десятичное число, начинающееся с первого понедельника как первый день первой недели.
  • %w день недели как десятичное число, воскресенье — 0.
  • %x привилегированное представление даты для текущего стандарта, но без времени.
  • %X привилегированное представление времени для текущего стандарта, но без даты.
  • %y год как десятичное число, но без столетия (от 00 до 99).
  • %Y год как десятичное число, включая столетие.
  • %Z часовой пояс или имя или сокращение (пусто, если часовой пояс не может быть определен).
  • %% литеральный символ ` % ‘.

Параметр size может использоваться, чтобы определить максимальное число символов, которое будет сохранено в массиве s, включая пустой символ завершения. Если форматируемое время требует больше чем size символов, лишние символы отбрасываются. Возвращаемое значение из strftime — число символов, помещенное в массив s, не включая пустой символ завершения. Если значение равняется размеру, это означает что массив s был слишком мал; Вы должны повторить обращение, обеспечивая больший массив.

Если s — пустой указатель, strftime не делает фактической записи чего-нибудь, но взамен возвращает число символов, которое она написала бы.

Для примера strftime, см. Раздел 17.2.7 [Пример Функции Времени].

Определение Часового пояса с TZ

В системе GNU, пользователь может определять часовой пояс посредством TZ переменной среды.

Для уточнения инфрмации относительно того, как устанавливать переменные среды, см. Раздел 22.2 [Переменные среды]. Функции для доступа к часовому поясу объявлены в » time.h «.

Значение TZ переменной может иметь один из трех форматов. Первый формат используется, когда не имеется никакого Смещения светового дня (или в летнее время) в зоне местного времени:

Смещение определяет значение которое нужно добавить к местному времени, чтобы получить значение Координированного Универсального времени. Она имеет синтаксис подобно [+ | -] hh [: mm [: ss]]. Она положительно, если зона местного времени — к западу от Главного меридиана и отрицательно, если она восточнее. Час должен быть от 0 до 24, а минуты и секунды от 0 до 59.

Например, вот, как мы определили бы Восточное Стандартное Время, но без любых Смещений Светового дня:

Остаточный член от спецификации описывает, когда смещение светового дня действует. Поле start — то, когда смещение светового дня входит в силу, а поле end — то, когда изменение будет сделано обратно к стандартному времени. Следующие форматы распознаваемы для этих полей: Jn определяет Юлианский день, с n между 1 и 365. 29 февраля никогда не рассчитывается, даже в високосные годы. N определяет Юлианский день, с n между 0 и 365. 29 февраля рассчитан в високосные годы. Mm.w.d определяет день d недели w месяца m. день d должен быть между 0 (воскресеньем) и 6. Неделя w должна быть между 1 и 5; неделя 1 — первая неделя, в которой есть день d , а неделя 5 определяет последний d день в месяце. Месяц m должен быть между 1 и 12.

Поля time определяют, когда, по местному времени происходит изменение к другому времени. Значение по умолчанию — 02:00:00.

Например, вот, как можно определить Восточный часовой пояс в Соединенных Штатах, включая соответствующее смещение светового дня и даты применимости. Нормальное смещение ПО ГРИНВИЧУ — 5 часов; так как это — к западу от главного меридиана, знак положителен. Летний период начинается в первое воскресенье апреля в 2:00am, и кончается в последнее воскресенье октября в 2:00am.

Чтобы быть строго правильным, преобразование дат и времени должно быть основано на действующем плане. Однако, система не имеет никаких средств, чтобы допустить Вам определять, как план изменился. Наибольшее что Вы может сделать — определить один специфический план обычно план текущего дня.

Третий формат походит на:

Если переменная среды TZ не имеет значения, операция выбирает часовой пояс по умолчанию. Каждая операционная система имеет собственные правила для выбора заданного по умолчанию часового пояса, так что относительно этого мы можем сказать совсем немного.

Функции и Переменные для Часовых поясов

Следующие переменные определены для совместимости с System V Unix. Эти переменные устанавливаются вызоввом localtime.

Пример Функции Времени

Вот пример программы, показывающий использование некоторых функций местного и календарного времени.

Функции alarm и setitimer обеспечивают механизм прерывания процесса, в некоторое время. Они делают это, устанавливая таймер; когда время таймер истекает, процесс получает сигнал.

Каждый процесс имеет три доступных независимых таймера интервала:

  • Таймер в реальном времени, который считает время как часы. Этот таймер посылает сигнал SIGALRM процессу, когда время истекает.
  • Виртуальный таймер, который считает процессорное время, используемое процессом. Этот таймер посылает сигнал SIGVTALRM процессу, когда время истекает.
  • Таймер профилирования, который считает оба: процессорное время, используемое процессом, и процессорное время, потраченное в системных вызовах от имени процесса. Этот таймер посылает сигнал SIGPROF процессу, когда время истекает.

Вы можете иметь только один таймер каждого вида в любое заданное время. Если Вы устанавливаете таймер, который еще не истек, этот таймер будет сброшен в новое значение.

Вы должны установить обработчик для соответствующего сигнала alarm, используюя signal или sigaction перед обращением к setitimer или alarm. Иначе, необычная цепочка событий может заставлить таймер исчерпать время прежде, чем ваша программа установит обработчик, и в этом случае она будет завершена, так как это — заданное по умолчанию действие для сигналов alarm. См. Главу 21 [Обработка Сигнала].


Функция setitimer — первичный способ для установки будильника. Это средство объявлено в заглавном файле » sys/time.h «. Функция alarm, объявленная в » unistd.h «, обеспечивает несколько более простой интерфейс для установки таймера в реальном времени.

Тип данных Struct timeval описан в Разделе 17.2.2 [Календарь с высоким разрешением].

Если old — не пустой указатель, setitimer возвращает информацию относительно любого предыдущего неистекшего таймера того же самого вида в структуре, на которую он указывает.

Возвращаемое значение — 0 при успехе и -1 при отказе. Следующие errno условия ошибки определены для этой функции: EINVAL

интервал таймера был слишком большой.

Возвращаемое значение и условия ошибки — такие же как для setitimer.

Возвращаемое значение указывает, сколько секунд оставалось прежде, чем предыдущий сигнал был бы послан. Если не было никакого предыдущего сигнала, alarm возвращает нуль.

Функция alarm могла бы быть определена в терминах setitimer примерно так:

Если Вы просто хотите, чтобы ваш процесс ждал данное число секунд, Вы должен использовать функцию sleep. См. Раздел 17.4 [Sleep].

Вы не должны рассчитать на сигнал, прибывающий точно, когда таймер истекает. В многопроцессорной среде имеется обычно некоторая задержка.

Примечание Переносимости: setitimer и getitimer — функции UNIX BSD, в то время как функция alarm определена POSIX.1 стандартом. Setitimer более мощная чем alarm, но alarm более широко используется.

Sleep дает простой способ заставить программу ждать некоторый период времени. Если ваша программа не использует сигналы (за исключением завершения), то Вы можете расчитывать, что sleep будет ждать заданное количество времени. Иначе, sleep может возвращаться, если прибывает сигнал; если Вы хотите ждать данный период независимо от сигналов, используйте select (см. Раздел 8.6 [Ждущий ввод — вывод] ) и не определяйте ни каких описателей ожидания.

Если функция sleep возвращает значение по истечении времени, то это значение нуль. Если она возвращается после сигнала, возвращаемое значение — остающееся время ожидания sleep.

Функция sleep объявлена в » unistd.h «.

Вы можете использовать select и делать период ожидания, совершенно точным. (Конечно, загрузка системы может вызывать неизбежные дополнительные задержки, если машина не специализирована одному приложению, не имеется никакого способа, которым Вы можете избежать этого.)

Функция getrusage и тип данных struct rusage используется для исследования типа использования процесса. Они объявлены в » sys/resource.h «.

В большинстве систем, processes имеет только два допустимых значения:

В системе GNU, Вы можете также запрашивать относительно специфического дочернего процесса, определяя ID процесса.

Возвращаемое значение getrusage — нуль при успехе, и -1 при отказе.

Аргумент EINVAL processes не допустим.

Еще один способ получения типа использования для специфического дочернего процесса — функцией wait4, которая возвращает общие количества для дочернего процесса при его завершении. См. Раздел 23.8 [BSD Функции Ожидания].

Дополнительная историческая функция для исследования типов использования, vtimes, обеспечивается но здесь не описана. Она объявлена в » sys/vtimes.h «.

Вы можете определять ограничения использования ресурса для процесса. Когда процесс пробует превышать ограничение, он может терпеть неудачу, в зависимости от ограничения. Каждый процесс первоначально наследует значения ограничений от родителя, но он может впоследствии изменять их.

Символы в этом разделе определены в » sys/resource.h «.

Возвращаемое значение — 0 при успехе и -1 при отказе. Единственое возможное errno условие ошибки — EFAULT.

Возвращаемое значение — 0 при успехе и -1 при отказе. Следующее errno условие ошибки возможно: EPERM

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

Rlim_cur Текущее значение рассматриваемого ограничения.

Rlim_max Максимально допустимое значение рассматриваемого ограничения. Вы не можете устанавливать текущее значение ограничения больше чем этот максимум. Только root может изменять максимально допустимое значение.

В getrlimit, эта структура — вывод; она получает текущие значения. В setrlimit она определяет новые значения.

Вот список ресурсов, для которых Вы можете определять ограничения.

Две исторических функции для установки ограничений ресурса, ulimit и vlimit, не зарегистрированы здесь. Они объявлены в » sys/vlimit.h » и исходят ИЗ BSD.

Когда отдельные процессы выполняются, их приоритеты определяют то, какую часть ресурсов CPU каждый процесс получает. Этот раздел описывает, как Вы можете читать и устанавливать приоритет процесса. Все эти функции и макрокоманды объявлены в » sys/resource.h «.

Промежуток допустимых значений зависит от операционной системы, но обычно он выполняется от -20 до 20. Меньшее значение приоритета означает что процесс выполняет чаще. Эти константы описывают некоторые значения: PRIO_MIN самое маленькое допустимое значение приоритета. PRIO_MAX самое большое допустимое значение приоритета.

Возвращаемое значение — значение приоритета при успехе, и -1 при отказе. Следующее errno условие ошибки возможно для этой функции: ESRCH

комбинация class и id не соответствует никакому существующему процессу. EINVAL

значение class не допустимо. Когда возвращаемое значение -1, это может указывать отказ, или значение приоритета.

Единственый способ различить состоит в том, чтобы установить errno = 0 перед вызовом getpriority, и тогда использовать errno!= 0 позже как критерий для отказа.


Возвращаемое значение — 0 при успехе и -1 при отказе. Следующее errno условие ошибки определено для этой функции: ESRCH

комбинация class и id не соответствует никакому существующему процессу. EINVAL

значение класса не допустимо. EPERM

Вы пробовали устанавливать приоритет процесса некоторого другого пользователя, и Вы не имеете привилегий для этого. EACCES

Вы пробовали понизить приоритет процесса, и Вы не имеете привилегий для этого. Аргументы class и id вместе определяет набор процессов, которыми Вы заинтересованы. Вот возможные значения для class:

Если id аргумент — 0, то обрабатывается текущий процесс, текущая группа процесса, или текущий пользователь, согласно классу.

mktime

(PHP 4, PHP 5, PHP 7)

mktime — Возвращает метку времени Unix для заданной даты

Описание

Функция возвращает метку времени Unix, соответствующую дате и времени, переданных в качестве аргументов. Метка времени — это целое число, равное разнице в секундах между заданной датой/временем и началом эпохи Unix (1 января 1970 00:00:00 GMT).

Аргументы могут быть опущены в порядке справа налево. В этом случае их значения по умолчанию равны соответствующим компонентам локальной даты/времени.

Примечания

Начиная с версии PHP 5.1, если mktime() вызывается без аргументов, то будет сгенерировано замечание уровня E_STRICT . Используйте вместо этого функцию time() .

Список параметров

Количество часов, прошедших с начала дня, указанного параметрами month , day и year . Отрицательные значения определяют часы до полуночи указанного дня. Значения больше 23 определяют соответствующий час следующего дня (или дней).

Количество минут, прошедших от начала часа, указанного параметром hour . Отрицательные значения определяют минуты предыдущего часа. Значения больше 59 определяют соответствующие минуты следующего часа (или часов).

Количество секунд, прошедших от начала минуты, указанной параметром minute . Отрицательные значения определяют секунды из предыдущей минуты. Значения больше 59 определяют соответствующие секунды следующей минуты (или минут).

Количество месяцев, прошедших с конца предыдущего года. Значения от 1 до 12 определяют нормальные обычные календарные месяцы года. Значения меньше 1 (включая отрицательные значения) определяют месяца предыдущего года в обратном порядке, то есть 0 будет декабрем, -1 — ноябрем и т.д. Значения больше 12 определяют соответствующий месяц в следующем году (или годах).

Количество дней, прошедших с конца предыдущего месяца. Значения от 1 до 28, 29, 30 или 31 (в зависимости от месяца) определяют нормальные дни соответствующего месяца. Значения меньше 1 (включая отрицательные значения) определяют дни предыдущего месяца, таким образом, 0 является последним днем предыдущего месяца, -1 — предпоследним днем предыдущего месяца и т.д. Значения больше количества дней соответствующего месяца определяют соответствующий день следующего месяца (или месяцев).

Номер года, может быть указан двумя или четырьмя цифрами, причем значения между 0-69 будут трактованы как 2000-2069, а между 70-100 — как 1970-2000. На тех системах, где time_t является 32-битным знаковым целым (наиболее распространенный вариант на сегодня), корректный диапазон для параметра year содержит даты где-то между 1901 и 2038. Однако, до версии PHP 5.1.0, на некоторых системах этот диапазон был ограничен датами между 1970 и 2038 (например, Windows).

Данный параметр может быть установлен в 1, если заданной дате соответствует летнее время (DST), 0 — в противном случае, или -1 (значение по умолчанию), если неизвестно, действует ли летнее время на заданную дату. В последнем случае PHP пытается определить это самостоятельно. Это может привести к неожиданному результату (который, тем не менее, не будет неверным). Некоторые даты могут быть неверными, если летнее время применимо к системе, на которой запущен PHP, или параметр is_dst установлен в 1. Если переход на летнее время происходит, например, в 2:00, все даты между 2:00 и 3:00 станут некорректными и mktime() вернет неопределенное (обычно отрицательное) значение. Некоторые системы (например, Solaris 8) осуществляют переход на летнее время в полночь, так что время 0:30 дня, когда был осуществлен переход на летнее время будет обрабатываться как 23:30 предыдущего дня.

Начиная с версии PHP 5.1.0, этот параметр более не рекомендуется к использованию. Вместо этого рекомендуется устанавливать соответствующую временную зону.

Этот параметр был удален в PHP 7.0.0.

Возвращаемые значения

mktime() возвращает временную метку Unix в соответствии с переданными аргументами. Если были переданы некорректными аргументы, функция вернет FALSE (до PHP 5.1 возвращалась -1).

Ошибки

Каждый вызов к функциям даты/времени при неправильных настройках временной зоны сгенерирует ошибку уровня E_NOTICE , и/или ошибку уровня E_STRICT или E_WARNING при использовании системных настроек или переменной окружения TZ . Смотрите также date_default_timezone_set()

Список изменений

Теперь ошибки, связанные с временными зонами, генерируют ошибки уровня E_STRICT и E_NOTICE .

Примеры

Пример #1 Пример использования функции mktime()

// Устанавливаем используемую по умолчанию временную зону. Доступно с PHP 5.1
date_default_timezone_set ( ‘UTC’ );

// Выводит: July 1, 2000 is on a Saturday
echo «July 1, 2000 is on a » . date ( «l» , mktime ( 0 , 0 , 0 , 7 , 1 , 2000 ));

// Выводит что-то вроде: 2006-04-05T01:02:03+00:00
echo date ( ‘c’ , mktime ( 1 , 2 , 3 , 4 , 5 , 2006 ));
?>

Пример #2 Пример использования mktime()

Функцию mktime() удобно использовать для выполнения арифметических операций с датами, так как она вычисляет верные значения при некорректных аргументах. Например, в следующем примере каждая строка выведет «Jan-01-1998».

Пример #3 Последний день месяца


Последний день любого месяца можно вычислить как «нулевой» день следующего месяца, не -1 день. Оба приведенных ниже примера выведут «Последний день февраля 2000 г.: 29».

Примечания

До версии PHP 5.1.0, отрицательные временные метки не поддерживались ни под одной известной версией Windows, а также и некоторыми другими системами. Таким образом, диапазон корректных лет был ограничен датами от 1970 до 2038 г.

Смотрите также

  • checkdate() — Проверяет корректность даты по григорианскому календарю
  • gmmktime() — Возвращает локальную метку времени Unix для времени по Гринвичу
  • date() — Форматирует вывод системной даты/времени
  • time() — Возвращает текущую метку системного времени Unix

Правильная работа с датой и временем

Практически все проекты сталкиваются с проблемами, вызванными неправильной обработкой и хранением даты и времени. Даже если проект используется в одном часовом поясе, все равно после перехода на зимнее/летнее время можно получить неприятные неожиданности. При этом мало кто озадачивается реализацией правильного механизма со старта, потому что кажется, что с этим проблем быть не может, так как все тривиально. К сожалению, в последствии реальность показывает, что это не так.

Логически можно выделить следующие типы значений, относящиеся к дате и времени:

  • Дата и время — «материал для медицинского анализа был собран 15 января 2014 года в 13:17:15»
  • Дата без времени — например, «новый контракт вступает в силу 2 февраля 2020 года»
  • Временной интервал — «отчет был сформирован за 3 минуты 15 секунд»
  • Расписание запланированных событий — «импорт данных из другой системы должен происходить каждый будний день в 10:00»

Рассмотрим каждый пункт по отдельности, не забывая об общих рекомендациях.

Дата и время

Допустим, лаборатория, которая собрала материал для анализа находится в часовом поясе +2, а центральный филиал, в котором следят за своевременным выполнением анализов — в поясе +1. Время, приведенное в примере, было отмечено при сборе материала первой лабораторией. Возникает вопрос — какую цифру времени должен увидеть центральный офис? Очевидно, что программное обеспечение центрального офиса должно показывать 15 января 2014 года 12:17:15 — на час меньше, так как по их часам событие произошло именно в этот момент.

Рассмотрим одну из возможных цепочек действий, через которую проходят данные с клиента на сервер и обратно, позволяющую всегда корректно отображать дату/время согласно текущему часовому поясу клиента:

  1. Значение создается на клиенте, например, 2 марта 2020 15:13:36, клиент находится в часовом поясе +2.
  2. Значение преобразуется в строковое представление для передачи на сервер — “2020-03-02T15:13:36+02:00”.
  3. Сериализованные данные передаются на сервер.
  4. Сервер десериализует время в объект даты/времени, приводя его при этом к своему текущему часовому поясу. Например, если сервер работает в +1, значит объект будет содержать 2 марта 2020 14:13:36.
  5. Сервер сохраняет данные в базу, при этом она не содержит никакой информации о часовом поясе — наиболее часто используемые типы даты/времени просто о нем ничего не знают. Таким образом, в базу будет сохранено 2 марта 2020 14:13:36 в «неизвестном» часовом поясе.
  6. Сервер читает данные из базы и создает соответствующий объект со значением 2 марта 2020 14:13:36. И так как сервер работает в часовом поясе +1, то и это значение будет трактоваться в рамках того же часового пояса.
  7. Значение преобразуется в строковое представление для передачи на клиент — “2020-03-02T14:13:36+01:00”.
  8. Сериализованные данные отправляются на клиент.
  9. Клиент десериализует полученное значение в объект даты/времени, приводя его при этом к своему текущему часовому поясу. Например, если это -5, то отображаемое значение должно быть равно 2 марта 2020 09:13:36.

Вроде бы все целостно, но давайте подумаем, что в этом процессе может пойти не так. На самом деле, проблемы здесь могут случиться почти на каждом шаге.

  • Время на клиенте может быть сформировано вообще без часового пояса — например, DateTime тип в .NET с DateTimeKind.Unspecified.
  • Механизм сериализации может использовать формат, который не включает в себя смещение часового пояса.
  • При десериализации в объект может игнорироваться смещение часового пояса, особенно в «самодельных» десериализаторах — как на сервере, так и на клиенте.
  • При чтении из базы объект даты/времени может быть сформирован вообще без часового пояса — например, DateTime тип в .NET с DateTimeKind.Unspecified. Более того, с DateTime в .NET на практике именно так и получается, если сразу после вычитки явно не указывать другой DateTimeKind.
  • Если сервера приложения, работающие с общей базой данных, находятся в разных часовых поясах — будет серьезная путаница в смещениях во времени. Значение даты/времени, записанное в базу сервером А и прочитанное сервером Б будет заметно отличаться от того же исходного значения, записанного сервером Б и прочитанного сервером А.
  • Перевод серверов приложения из одного пояса в другой приведет к неправильной трактовке уже сохраненных значений даты/времени.

Но самый серьезный недостаток в описанной выше цепочке — это использование локального часового пояса на сервере. Если в нем нет перехода на летнее/зимнее время, то никаких дополнительных проблем не будет. А вот в противном случае можно получить массу неприятных неожиданностей.

Правила перевода на летнее/зимнее время — вещь, строго говоря, переменная. Разные страны могут иногда менять свои правила, и эти изменения должны быть заблаговременно заложены в обновления системы. На практике неоднократно встречались ситуации некорректной работы этого механизма, которые по итогу решались установкой хотфиксов либо операционной системы, либо используемых сторонних библиотек. Вероятность повторения тех же проблем — не нулевая, поэтому лучше иметь способ гарантированно их избежать.

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

Рассмотрим, что нам дает такое правило:

  • При отправке данных на сервер клиент должен передать смещение часового пояса, чтобы сервер мог корректно преобразовать время в UTC. Альтернативный вариант — обязать клиент делать это преобразование, но первый вариант гибче. При получении данных обратно с сервера клиент будет переводить дату и и время в свой локальный часовой пояс зная, что ему в любом случае придет время в UTC.
  • В UTC нет переходов на летнее и зимнее время, соответственно связанные с этим проблемы будут неактуальны.
  • На сервере при чтении из базы не нужно преобразовывать значения времени, достаточно только явно указывать, что оно соответствует UTC. В .NET, например, этого можно достичь установкой DateTimeKind для объекта времени в DateTimeKind.Utc.
  • Разница часовых поясов между серверами, работающими с общей базой данных, как и перевод серверов из одного пояса в другой, никак не отразятся на корректности получаемых данных.

Для реализации такого правила достаточно позаботиться о трех вещах:

  1. Сделать механизм сериализации и десериализации такой, чтобы значения даты/времени корректно переводились из UTC в локальный часовой пояс и обратно.
  2. Убедиться, что десериализатор на стороне сервера создает объекты даты/времени в UTC.
  3. Сделать так, чтобы при вычитке из базы объекты даты/времени создавались в UTC. Этот пункт иногда обеспечивают без изменений кода — просто системный часовой пояс на всех серверах устанавливается в UTC.

Описанные выше соображения и рекомендации отлично работают при сочетании двух условий:

  • В требованиях к системе нет надобности отображать локальное время и/или смещение часового пояса именно в том виде, в котором оно было сохранено. Например, в авиабилетах время вылета и прибытия должно быть распечатано в часовом поясе, соответствующем расположению аэропорта. Или если сервер отправляет на печать инвойсы, созданные в разных странах, на каждом должно в итоге стоять локальное время, а не преобразованное в часовой пояс сервера.
  • Все значения даты и времени в системе являются «абсолютными» — т.е. описывают момент времени в будущем или прошлом, которому соответствует единственное значение в UTC. Например, «пуск ракеты-носителя состоялся в 23:00 по киевскому времени», или «совещание будет идти с 13:30 до 14:30 по минскому времени». В разных часовых поясах цифры для этих событий будут разные, но они будут описывать один и тот же момент времени. Но может так случиться, что требования к программному обеспечению подразумевают «относительное» локальное время для некоторых случаев. Например, «эта передача на телевидении будет идти с 9:00 до 10:00 утра в каждой стране, где есть филиал телеканала». Получается, что показ передачи — это не одно событие, а несколько, причем потенциально все они могут происходить в разные отрезки времени по «абсолютной» шкале.

Для случаев, где нарушается первое условие, задачу можно решить использованием типов данных, содержащих часовой пояс – как на сервере, так и в базе данных. Ниже приведен небольшой перечень примеров для разных платформ и СУБД.

Версия Описание
7.0.0 Параметр is_dst был удален.
5.3.0 mktime() теперь выбрасывает ошибку уровня E_DEPRECATED при использовании параметра is_dst .
5.1.0 Параметр is_dst теперь считается устаревшим. Функция теперь возвращает FALSE при ошибке, тогда как раньше возвращалась -1. Теперь функция принимает дату с одновременно установленными в ноль годом, месяцем и днем.
5.1.0 Если mktime() была вызвана без аргументов, то будет сгенерировано замечание уровня E_STRICT . Используйте вместо этого функцию time() .
5.1.0
.NET DateTimeOffset
Java org.joda.time.DateTime, java.time.ZonedDateTime
MS SQL datetimeoffset
Oracle, PostgreSQL TIMESTAMP WITH TIME ZONE
MySQL

Нарушение второго условия — более сложный случай. Если это «относительное» время нужно хранить просто для отображения, и нет задачи определить «абсолютный» момент времени, когда событие наступило или наступит для заданного часового пояса — достаточно просто запретить преобразование времени. Например, пользователь ввел начало передачи для всех филиалов телекомпании 25 марта 2020 года в 9:00, и оно в таком виде будет передаваться, храниться и отображаться. Но может случиться, что какой-то планировщик должен автоматически выполнить специальные действия за час до начала каждой передачи (разослать уведомления или проверить наличие каких-то данных в базе телекомпании). Надежная реализация такого планировщика является нетривиальной задачей. Допустим, планировщик осведомлен о том, в каком часовом поясе находится каждый из филиалов. И одна из стран, где есть филиал, через некоторое время решает сменить часовой пояс. Случай не настолько редкий, как может показаться — за этот и два предыдущих года я насчитал больше 10 подобных событий (http://www.timeanddate.com/news/time/). Получается, что либо пользователи должны поддерживать привязки к часовым поясам в актуальном состоянии, либо планировщик должен в автоматизированном режиме брать эту информацию из глобальных источников типа Google Maps Time Zone API. Я не берусь предложить универсальное решение для подобных случаев, просто отмечу, что такие ситуации требуют серьезной проработки.

Как видно из вышесказанного, не существует единого подхода, покрывающего 100% случаев. Поэтому сперва нужно четко понять из требований, какие из упомянутых выше ситуаций будут в вашей системе. С большой вероятностью, все ограничится первым предложенным подходом с хранением в UTC. Ну а описанные исключительные ситуации его не отменяют, а просто добавляют другие решения для частных случаев.

Дата без времени

Допустим, с правильным отображением даты и времени с учетом часового пояса клиента разобрались. Перейдем к датам без времени и примеру, указанному для этого случая в начале — «новый контракт вступает в силу 2 февраля 2020 года». Что будет, если для таких значений использовать те же типы и тот же механизм, что и для «обычных» даты с временем?

Не во всех платформах, языках и СУБД есть типы, хранящие только дату. Например, в .NET есть только тип DateTime, отдельного «просто Date» нет. Даже если при создании такого объекта была указана только дата, время все равно присутствует, и оно равно 00:00:00. Если мы значение «2 февраля 2020 00:00:00» из пояса со смещением +2 переведем в +1, то получим «1 февраля 2020 23:00:00». Для указанного выше примера это будет равносильно тому, что в одном часовом поясе новый контракт начнет действовать 2 февраля, а в другом — 1 февраля. С юридической точки зрения это абсурд и так, конечно же, быть не должно. Общее правило для «чисто» дат предельно простое — такие значения не должны преобразовываться ни на одном шаге сохранения и чтения.

Есть несколько способов избежать преобразование для дат:

  • Если платформа поддерживает тип, представляющий дату без времени, то его и нужно использовать.
  • Добавлять в метаданные объектов специальный признак, который будет говорить сериализатору, что для данного значения часовой пояс нужно игнорировать.
  • Передавать дату с клиента и обратно как строку, а хранить как дату. Такой подход неудобен, если на клиенте дату нужно не только отображать, но еще и производить какие-то операции над ней: сравнение, вычитание и т.д.
  • Передавать и хранить как строку, а преобразовывать в дату только для форматирования с учетом региональных настроек клиента. Имеет еще больше недостатков чем предыдущий вариант — например, если в хранимой строке части даты идут не в порядке «год, месяц, день», то будет невозможно сделать эффективный индексированный поиск по диапазону дат.

Можно, конечно, попытаться привести контрпример и сказать, что контракт имеет смысл только в пределах страны, в которой он заключен, страна находится в одном часовом поясе, и поэтому можно однозначно определить момент вступления его в силу. Но даже в этом случае пользователям из других часовых поясов не будет интересно, в какой момент по их локальному времени произойдет это событие. А даже если бы была нужда показывать этот момент времени, то отображать пришлось бы не только дату, но и время, что противоречит исходному условию.

Временной интервал

С хранением и обработкой временных интервалов все просто: их величина не зависит от часового пояса, поэтому никаких особых рекомендаций здесь нет. Их можно хранить и передавать как количество единиц времени (целое или с плавающей точкой, в зависимости от необходимой точности). Если важна секундная точность — то как количество секунд, если миллисекундная — то как количество миллисекунд и т.д.

А вот вычисление интервала может иметь подводные камни. Предположим, у нас есть типовой код на C#, который считает интервал времени между двумя событиями:

На первый взгляд, никаких проблем здесь нет, но это не так. Во-первых, могут возникнуть проблемы с юнит-тестированием такого кода, но об этом мы поговорим чуть позже. Во-вторых, давайте представим, что начальный момент времени пришелся на зимнее время, а конечный — на летнее (например, таким образом замеряется количество рабочих часов, а у работников есть ночная смена).

Предположим, код работает в часовом поясе, в котором переход на летнее время в 2020 году происходит в ночь 27 марта, и смоделируем описанную выше ситуацию:


Этот код даст в результате 9 часов, хотя фактически между этими моментами прошло 8 часов. В этом легко убедиться, изменив код вот таким образом:

Отсюда вывод — любые арифметические операции с датой и временем нужно делать, используя либо UTC значения, либо типы, хранящие информацию о часовом поясе. А потом обратно переводить в локальные в случае надобности. С этой точки зрения, изначальный пример легко исправить, поменяв DateTime.Now на DateTime.UtcNow.

Этот нюанс не зависит от конкретной платформы или языка. Вот аналогичный код на Java, имеющий тот же недостаток:

Исправляется он также легко — например, использованием ZonedDateTime вместо LocalDateTime.

Расписание запланированных событий

Расписание запланированных событий – более сложная ситуация. Универсального типа, позволяющего хранить расписания, в стандартных библиотеках нет. Но такая задача возникает не так уж редко, поэтому готовые решения можно найти без проблем. Хорошим примером является формат планировщика cron, который в том или ином виде используется другими решениями, например, Quartz: http://quartz-scheduler.org/api/2.2.0/org/quartz/CronExpression.html. Он покрывает практически все нужды составления расписаний, включая варианты типа «вторая пятница месяца».

В большинстве случаев писать свой планировщик не имеет смысла, так как существуют гибкие проверенные временем решения, но если по какой-то причине есть надобность в создании своего механизма, то как минимум формат расписания можно позаимствовать у cron.

Общие рекомендации

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

Во-первых, по поводу использования статических членов класса для получения текущего времени — DateTime.UtcNow, ZonedDateTime.now() и т.д. Как и было сказано, использование их напрямую в коде может серьезно усложнить юнит-тестирование, так как без специальных мок фреймворков подменить текущее время не получится. Поэтому, если вы планируете писать юнит тесты, следует позаботиться о том, чтобы реализацию таких методов можно было подменить. Для решения этой задачи есть как минимум два способа:

  • Выделить интерфейс IDateTimeProvider с единственным методом, возвращающим текущее время. Затем добавить зависимость на этот интерфейс во всех единицах кода, где нужно получать текущее время. При обычном выполнении программы во все эти места будет инжектиться реализация «по умолчанию», которая возвращает реальное текущее время, а в юнит тестах – любая другая необходимая реализация. Такой способ является наиболее гибким с точки зрения тестирования.
  • Сделать свой статический класс с методом для получения текущего времени и возможностью установить любую реализацию этого метода извне. Например, в случае C# кода этот класс может выставлять наружу свойство UtcNow и метод SetImplementation(Func impl). Использование статического свойства или метода для получения текущего времени избавляет от надобности везде явно прописывать зависимость от дополнительного интерфейса, но с точки зрения принципов ООП не является идеальным решением. Однако, если по каким-то соображениям предыдущий вариант не подходит, то можно воспользоваться этим.

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

Второй нюанс с получением текущего времени — это то, что клиенту доверять нельзя. Текущее время на компьютерах пользователей может очень сильно отличаться от реального, и если есть логика, завязанная на него, то эта разница может все испортить. Все места, где есть необходимость получать текущее время, должны по возможности выполняться на стороне сервера. И, как уже было сказано ранее, все арифметические операции с временем должны производиться либо в UTC значениях, либо с использованием типов, хранящих смещение часового пояса.

И еще одна вещь, которую хотелось упомянуть — это стандарт ISO 8601, описывающий формат даты и времени для обмена информацией. В частности, строковое представление даты и времени, используемое при сериализации, должно соответствовать этому стандарту для предотвращения потенциальных проблем с совместимостью. На практике крайне редко приходится самому реализовывать форматирование, поэтому сам стандарт может быть полезен в основном в ознакомительных целях.

Работа с датой и временем в Python

Python содержит несколько инструментов, которые разработчик может использовать для работы с датой и временем. В данном разделе статье мы рассмотрим модули datetime и time. Мы изучим принципы их работы и способы их применения. Начнем с модуля datetime.

Модуль datetime

Мы изучим следующие классы модуля:

  • datetime.date
  • datetime.timedelta
  • datetime.datetime

Благодаря этим классам мы в будущем сможем работать с большей частью случаев, в которых нам понадобятся объекты date и datetime. Также существует класс tzinfo, который применяется для работы с часовыми поясами. Для дополнительной информации об этом классе вы можете обратиться к документации Python.

datetime.date

Python может представлять даты различными способами. Для начала, рассмотрим формат datetime.date, так как это один из самых простых объектов date.

В данном коде показано, как создать простой объект даты. Класс date принимает три аргумента: год, месяц и день. Если вы укажите неправильное значение, вы увидите ошибку ValueError, как в случае выше. В противном случае вы увидите, что объект datetime.date вернулся. Давайте взглянем на еще один пример:

Здесь мы присваиваем объекту date переменную d. Теперь мы можем получить доступ к различным компонентам даты по названиям, таким как d.year или d.month. Давайте посмотрим, какой сейчас день:

Это может быть полезно, когда вам нужно записать, какой сейчас день. Или, если вам нужно выполнить основанный на сегодняшней дате расчет. Мелочь, а приятно.

datetime.datetime

Объект datetime.datetime содержит всю информацию объектов datetime.date плюс datetime.time. Давайте приведем несколько примеров, для лучшего понимания разницы между этим объектом, и объектом datetime.date.

Мы видим, что datetime.datetime принимает несколько дополнительных аргументов: год, месяц, день, час, минута и секунда. Это также позволяет вам указывать информацию о микросекундах и часовом поясе. При работе с базами данных, данные типы объектов будут использоваться достаточно часто. Большую часть вашей работы, вам нужно будет конвертировать форматы date или datetime Python в форматы SQL datetime или timestamp. Обратите внимание на то, что today совместно с datetime.datetime использует два разных метода:

Модуль datetime содержит другой метод, под названием strftime. Этот метод позволяет разработчику создавать строку, отображающую время в более понятной для человека форме. Существует целая таблица параметров форматирования, с которой рекомендуется ознакомиться в документации Python, в секции 8.1.7. Давайте взглянем на несколько примеров, показывающих всю полезность данного метода:

Первый пример – это скорее хитрость. В нем показано, как конвертировать сегодняшний объект datetime в строку, следующую за форматом YYYYMMDD (ГГГГММДД). Второй пример более наглядный.

В нем мы присваиваем объект datetime переменной под названием today и применяем два разных параметра форматирования строки. Первый параметр добавляет косые черточки между элементами datetime, а также перегруппировывает datetime, теперь он делится на месяц, день и год. В последнем примере мы создаем временную отметку, которая следует типичному формату: YYYY-MM-DD.HH.MM.SS. Если вам нужно указать год как двухзначный (“YY”), вы можете заменить %Y на %y.

datetime.timedelta

Объект datetime.timedelta отображает длительность времени. Другими словами, это разница между двумя датами или временными отметками. Давайте взглянем на наглядный пример:

Мы создали два объекта datetime. Один указывает на сегодняшний день, второй – на прошедшую неделю. После этого, мы берем разницу между ними. Это возвращает объект timedelta, который мы можем далее использовать, чтобы выяснить, сколько прошло дней или секунд, между этими двумя датами. Если вам нужно узнать количество часов или минут между двумя датами, вам понадобится немножко математики, чтобы выяснить это. Давайте взглянем на проверенный способ:

Отсюда мы узнаем, что в неделе 186 часов и 13 минут. Обратите внимание на то, что мы используем двойную косую черту в качестве нашего оператора деления, также известного как floor division. Теперь мы готовы к тому, чтобы узнать больше о модуле time Python.

Модуль time

Модуль time открывает разработчику Python доступ к нескольким связанным со временем функциям. Модуль основан на «эпохе», точке, с которой начинается время. Для систем Unix, эпоха началась в 1970 году. Чтобы узнать, какая эпоха в вашей системе, попробуйте запустить следующий код:

Я запустил его на Windows 7, которая также уверена в том, что начало времен датируется 1970м годом. В любом случае, в данном разделе мы ознакомимся со следующими функциями:

Илон Маск рекомендует:  Как сделать фоновую картинку на всю ширину
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL