Статьи

Какой лучший формат даты?

Когда дело доходит до отображения даты и времени, не существует единого формата, подходящего для любой ситуации. При таком широком международном и региональном различии форматирования и множестве различных ситуаций, в которых используются даты и время, каждый случай уникален — от подробных и лирических предложений, таких как понедельник 21 марта в 12:18 (EST) , до загадочных и компактный выход как сегодня .

Но когда дело доходит до программной работы с датами — хранения, сравнения и сортировки с ними — действительно нет необходимости в таком большом разнообразии форматов. Действительно, гораздо разумнее объединить использование программных дат и использовать один и тот же формат для всего .

Так какой формат лучше всего использовать?

Это должно было бы отметить несколько полей — думайте о них как о «обязательных» функциях:

  • он хранит полную дату и время, предоставляя всю необработанную информацию, необходимую для создания любого другого формата
  • мы можем использовать его в качестве входных данных для создания и преобразования дат — например. он должен быть совместим с аргументом timestamp new Date конструктора new Date в JavaScript
  • он всегда использует один и тот же фиксированный часовой пояс, чтобы обеспечить систему отсчета для сравнения

Помимо этих основных требований, есть несколько «полезных» функций:

  • его формат изначально сортируется без дополнительного преобразования (т. е. если он используется в качестве имени файла, он создает хронологический порядок сортировки)
  • у него нет внутреннего пробела — чтобы избежать разбора неоднозначностей, таких как чрезмерное непрерывное пространство или разница табуляции / пробела
  • это обеспечивает, по крайней мере, некоторый уровень читабельности, главным образом ради программистов
  • это должно дать нам хотя бы некоторую «бесплатную» информацию, т.е. такие значения, как год или час, которые легко получить при разборе строки, без необходимости каждый раз создавать и анализировать новые объекты даты

Как насчет часовых поясов?

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

Даты JavaScript всегда локальны

Поскольку JavaScript оценивается на клиенте, он использует часы клиента в качестве эталона времени. Таким образом, любая отметка времени, прошедшая через конструктор Date автоматически преобразуется в местное время пользователя .

Моя окончательная рекомендация

В прошлом, пока я на самом деле не сел и, хотя это серьезно, я обычно использовал формат даты RFC 2822 (например, "Mon, 21 Mar 2011 00:18:56 +0000" ) — в основном потому, что его так легко генерировать в PHP (определяется символом форматирования "r" ), и он помечает все обязательные поля. Но это не изначально сортируемый и не тот выбор, к которому я в итоге пришел:

Моя окончательная рекомендация — ISO 8601 (2004) в UTC .

Существует несколько вариаций этого формата, и один из них, который я специально выбрал, использует разделитель даты и времени "T" и указатель часового пояса "Z" (который обозначает UTC ); другие варианты используют пробел в качестве разделителя или обозначают часовой пояс как "+00:00" , но я не рекомендую ни один из них — пробел делает его несовместимым с new Date в Firefox, и более длинный и более сложный указатель часового пояса просто ненужно.

Таким образом, отметки времени, о которых мы говорим, выглядят так: "2011-03-21T00:18:56Z"

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

  • это всегда постоянная длина
  • этот формат изначально используется JSON (например, в JavaScript, если вы передаете объект Date через JSON.stringify , он преобразуется в этот формат)
  • это формат и профиль, рекомендованные W3C
  • он совместим с DATESTAMP столбца DATESTAMP в SQL , хотя и с «расслабленным» синтаксисом
MySQL DATESTAMP получил

Проблема, обнаруженная мной в PHP и MySQL, заключается в том, что когда метка времени в этом формате хранится в столбце DATESTAMP , его разделитель "T" заменяется пробелом, а маркер "Z" удаляется , преобразуя его в строгий. Формат DATESTAMP . Но это не то, что мы хотим, и не приемлемо.

Все, что я делаю, чтобы это исправить — это переконвертирую вывод, но мне бы хотелось услышать о более постоянном решении — опции конфигурации MySQL или что-то еще?

Как использовать формат ISO

В PHP нет заранее определенной константы или токена для создания этого точного формата, хотя токен форматирования "c" создает один очень похожий (тот же стандарт, другой вариант). Затем мы можем преобразовать различия с помощью замены строк; но я считаю, что самое простое, что нужно сделать, это просто скомпилировать его вручную из отдельных компонентов даты и времени, используя функцию gmdate для получения UTC :

 $timestamp = gmdate('Ym-dTH:i:sZ'); 

После того, как у нас есть временная метка, мы можем использовать ее на клиенте в качестве аргумента временной метки для new Date . Например, мы могли бы сначала вывести необработанную временную метку в статический HTML :

 <dl class="listing"> <dt>Date created:</dt> <dd id="listing-timestamp"><?php echo gmdate('Ym-dTH:i:sZ'); ?></dd> </dl> 

А затем используйте JavaScript, чтобы преобразовать его в переформатированную локальную дату и время, например:

 var dd = document.getElementById("listing-timestamp"); dd.innerHTML = new Date(dd.innerHTML).toLocaleString(); 

Конечно, механизм передачи временных меток между клиентом и сервером сильно зависит от приложения. Сценарий PHP может выводить метку времени непосредственно в сгенерированный сервером JavaScript; это может быть ответ на запрос Ajax, или он может быть записан в статический HTML , как в примере выше. Как бы то ни было, наиболее распространенным вариантом использования, вероятно, являются сгенерированные сервером временные метки, которые выводятся клиенту для преобразования , и описанные мной процессы будут это делать. Но как насчет других случаев?

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

 $rfcdate = date('r', strtotime($timestamp)); 

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

 function getTimestamp() { var dateobj = new Date(); dateobj.setTime(dateobj.getTime() + (dateobj.getTimezoneOffset() * 60000)); var datetime = { date : [ dateobj.getFullYear(), dateobj.getMonth() + 1, dateobj.getDate() ], time : [ dateobj.getHours(), dateobj.getMinutes(), dateobj.getSeconds() ] }; for(var key in datetime) { if(!datetime.hasOwnProperty(key)) { continue; } for(var i in datetime[key]) { if(!datetime[key].hasOwnProperty(i)) { continue; } var n = datetime[key][i]; datetime[key][i] = (n < 10 ? '0' : '') + n; } } return datetime.date.join('-') + 'T' + datetime.time.join(':') + 'Z'; } 

Полученная временная метка может быть затем передана new Date и оттуда обработана во время локали:

 var timestamp = getTimestamp(); ... var rfcdate = new Date(timestamp).toString();