Сегодня выпуск в основном для программистов. В следующий раз исправлюсь, будет много про бизнес и управление временем.
Совет
Если вам написал заказчик с проблемой, которую вы не можете решить или даже рассмотреть сегодня, обязательно напишите ему, что вы задачу приняли, но сможете ей заняться не сразу. Например, "Да, вашу проблему вижу. Я её смогу исследовать в ближайшие 2 дня, исправлю не позже чем за 2 недели".
Благодаря такому подходу:
- заказчик будет доволен и видит, что вы про него не забыли
- заказчик будет знать, хотя бы примерно, когда ждать рез-та
- заказчик будет понимать, что вы работаете не только с ним и что любая его задача не обязательно выполняется в режиме "всё бросить и начать делать". Со временем он начнёт четче для себя представлять какие задачи для него сейчас приоритетнее, а какие были результатом мимолётного желания и могут подождать некоторое время.
Ну и без фанатизма, иногда действительно нужно всё бросить и делать, но не так часто, как это кажется.
Работа с датами в php
Разберёмся, как работать с датами в php и вообще. Это является проблемой для некоторых, о чём я могу судить по вопросам, которые иногда мне задают.
Time zone
Для начала правильно настройте текущую временную зону (TZ) в php и базе данных. В php смотрите на функцию
date_default_timezone_set, в mysql -
http://dev.mysql.com/doc/refman/5.1/en/time-zone-support.html. В mysql можно задать как дефолтную временную зону, так и зону для каждого соединения.
Если ваш сервер должен работать с несколькими временными зонами, полезно будет для пользователей хранить в настройках его временную зону и выставлять после авторизации. Иначе, работать с сайтом из Владивостока будет не очень удобно : )
Форматы
Сначала разберемся с форматами.
1. Строки без временной зоны. Если вы используете дату в "стиле mysql" (YYYY-MM-DD HH:MM:SS) или подобных человеко-читаемых строковых форматах, где не содержится информация о временной зоне, всегда согласовывайте в какой временной зоне будут данные. Если вопрос идёт о каком-то внешнем API (как получение, так и приём), лучше всегда использовать форматы с указанием временной зоны или не зависящие от неё. На крайний случай согласовать временные зоны и нормализовать данные при обработке.
2. Строки с указанием временной зоны. Например, как в заголовках HTTP - "Thu, 19 Nov 1981 08:52:00 GMT". Основная проблема таких дат - их парсинг. Из-за неразберихи в форматах браузеры, например, хранят эту дату для If-Modified-Since напрямую в том виде, как передавал сервер. Использовать такое представления для внутреннего хранения не рекомендуется.
3. Timestamp, (micto timestamp) - это уже число, а не строка. Показывает кол-во секунд (микросекунд) с 00:00:00 01.01.1970 UTC. Не все знают, что это значение TZ независимо! Оно отсчитывается от времени по гринвичу (UTC), не зависимо от того, какую временную зону вы используете. Т.е. при преобразовании строка -> timestamp и обратно *важно*, какую временную зону вы используете. Например, в strtotime при работе в временной зоне MSK от полученного после парсинга значения даты вычитается 4 часа, затем считает timestamp. В обратную сторону аналогично. Зато если у вас есть время в виде timestamp вы можете не думать о TZ. Это подходящий формат для использования в API.
Важно ещё помнить, что отсчитывается timestamp от 1970 года и, например, хранить даты рождения в таком формате нельзя (ну по крайней мере ещё ближайшие лет 100, потом уже будет можно :) ), а вот записи в журнале изменения это самое оно.
Перевод форматов в php
1. Перевод строка -> timestamp:
1.1 strtotime
$timestamp = strtotime($dateString);
где можно безопасно использовать форматы, типа "YYYY-MM-DD HH:MM:SS" и некоторые другие. Обработка происходит "магическим" методом, поэтому ...
1.2 strptime
Для более точного задания формата можно использовать strptime. Только она возвращает не timestamp, а набор распознанных данных, но можно написать не сложную функцию по преобразованию уже в timestamp. Всё это актуально для php 5.1+, для более старых версий нужно найти реализацию strptime на чистом php.
1.3 через DateTime класс
Актуально для php 5.3+
$mydate = DateTime::createFromFormat('d-M-Y', '15-Feb-2009');
echo $datetime->format('U');
Плюс в том, что форматов поддерживается очень много, минус в том, что формат задаётся в формате, близком к функции date, а я, например, больше люблю формат strftime (%Y-%m-%d).
2. Timestamp -> строка
2.1 strftime
strftime(%Y-%m-%d %H:%M:%S, $timestamp);
2.2 date
date('Y-m-d H:i:s', $timestamp)
2.3 через класс DateTime
$mydate = DateTime::createFromFormat('@'.$timestamp);
$mydate->format('Y-m-d H:i:s');
strftime('%Y-%m-%d %H:%M:%S', (int) $mydate->format('U'));
//но так ещё нужна проверка на unix эпоху
Операции с датами
И так, до 5.2 практически единственным способом операций с датами было использование strtotime, который позволяет писать так:
$tmpstmp = strtotime('now +1 week');
$tmpstmp = strtotime('2011-10-24 12:00:00 +1 month -5 days');
Но опять же из-за "магического свойства" этой функции, иногда были проблемы. Для обхода проблем нагородили кучу сложных способов, например, кто видел реализация Zend_Date, тот в цирке больше не смеётся. Плюс ко всему ниже unix эпохи (1970 год), опуститься нельзя.
В php 5.2 появился новый класс DateTime, а в php 5.3 к нему добавилось пару полезных возможностей. Теперь его можно рекомендовать в виде основного инструменты работы с датами. Там возможны любые операции:
- вычитание дат (DateTime) - (DateTime) = (DateInterval)
- добавление/вычитание из даты: (DateTime) +- (DateInterval) = (DateTime)
- форматирование (см. примеры выше)
- распознание строковых представлений (см. примеры выше)
- работа с временными зонами и пр.
Класс работает с датами от 0 до 9999 года (в "кишочках" используется 64bit целое число).
Крайне рекомендую.
Подроблее читайти manual -
http://ru.php.net/manual/en/class.datetime.php
В PE/ЕИС я собираюсь немного похимичить с этими классами, чтобы заставить их принимать strftime формат, даже с некоторыми расширениями.
Результатом поделюсь со всеми желающими.