У меня проблема, когда мне нужно обрабатывать даты, когда части месяца и дня являются необязательными. Например, год всегда будет известен, но иногда день или месяц и день будут неизвестны.
В MySQL я могу создать таблицу с полем даты, и, хотя я не могу найти ссылку в Руководстве по MySQL, она примет следующее как действительное:
(YYYY-MM-DD format): 2011-02-10 // Current date 2011-02-00 // Day unknown so replaced with 00 2011-00-00 // Day and month unkown so replaced with 00-00
Тестовые вычисления из базы данных работают нормально, поэтому я могу легко сортировать результаты. В руководстве говорится, что месяц должен быть между 01 и 12 и днем между 01 и 31, но он принимает 00.
Первый вопрос: буду ли я сталкиваться с неприятностями, используя 00 в месяцах или днях, или это вполне приемлемо?
Следующий вопрос: есть ли функция PHP (или команда формата MySQL), которая автоматически форматирует следующие даты в нужную строку формата?
2011 becomes 2011-00-00 2011-02 becomes 2011-02-00
Или мне нужно написать специальную функцию для этого?
Не работает следующее:
<?php $date = date_create_from_format('Ym-d', '2011-00-00'); echo date_format($date, 'Ym-d'); // Returns 2010-11-30 $date = date_create_from_format('Ym-d', '2011-02-00'); echo date_format($date, 'Ym-d'); // Returns 2011-01-31 ?>
Третий вопрос: существует ли функция PHP (или команда MySQL) для форматирования дат для использования в PHP?
Наконец, это лучший подход? Или есть метод «лучшей практики»?
РЕДАКТИРОВАТЬ:
Вот что я сейчас делаю:
Поле даты может принимать дату в формате YYYY, YYYY-MM или YYYY-MM-DD, и перед отправкой в базу данных она обрабатывается в этой функции:
/** * Takes a date string in the form: * YYYY or * YYYY-MM or * YYYY-MM-DD * and validates it * * Use date_format($date, $format); to reverse. * * @param string $phpDate Date format [YYYY | YYYY-MM | YYYY-MM-DD] * * @return array 'date' as YYYY-MM-DD, 'format' as ['Y' | 'Ym' | 'Ym-d'] or returns false if invalid */ function date_php2mysql($phpDate) { $dateArr = false; // Pattern match if (preg_match('%^(?P<year>\d{4})[- _/.]?(?P<month>\d{0,2})[- _/.]?(?P<day>\d{0,2})%im', trim($phpDate), $parts)) { if (empty($parts['month'])) { // Only year valid $date = $parts['year']."-01-01"; $format = "Y"; } elseif (empty($parts['day'])) { // Year and month valid $date = $parts['year']."-".$parts['month']."-01"; $format = "Ym"; } else { // Year month and day valid $date = $parts['year']."-".$parts['month']."-".$parts['day']; $format = "Ymd"; } // Double check that it is a valid date if (strtotime($date)) { // Valid date and format $dateArr = array('date' => $date, 'format' => $format); } } else { // Didn't match // Maybe it is still a valid date if (($timestamp = strtotime($phpDate)) !== false) { $dateArr = array('date' => date('Ym-d', $timestamp), 'format' => "Ymd"); } } // Return result return $dateArr; }
Таким образом, шаблон соответствует входному $ phpDate, где он должен начинаться с 4 цифр, а затем необязательно пар цифр за месяц и день. Они хранятся в массиве с именем $ parts.
Затем он проверяет, существуют ли месяцы или дни, указав строку формата и создав дату.
Наконец, если все проверяется, оно возвращает допустимую дату, а также строку формата. В противном случае он возвращает FALSE.
В конечном итоге у меня есть допустимый формат даты для моей базы данных, и у меня есть способ использовать его снова, когда он возвращается.
Кто-нибудь думает о лучшем способе сделать это?
У меня проблема, когда мне нужно обрабатывать даты, когда части месяца и дня являются необязательными. Например, год всегда будет известен, но иногда день или месяц и день будут неизвестны.
Во многих случаях нам нужны такие «более или менее точные» даты, и я использую такие даты, как 2011-04-01
(точный), а также 2011-04
(= апрель 2011 года) и 2011
(только год) в архивных метаданных. Как вы упомянули, поле даты MySQL допускает «2011-00-00», хотя в нем нет часто задаваемых вопросов, и все в порядке.
Но тогда мне пришлось взаимодействовать с MySQL database
через ODBC
а поля даты корректно переводились, за исключением «допустимых» дат (Ex: '2011-04-00 », пустых результатов в базе данных ACCESS, связанной с MySQL-ODBC.
По этой причине я пришел к выводу, что поле даты MySQL может быть преобразовано в простое поле VARCHAR(10)
: до тех пор, пока нам не нужны конкретные функции даты в MySQL, он отлично работает, и, конечно, мы все еще можем использовать функции даты php и вашу прекрасную функцию date_php2mysql ().
Я бы сказал, что единственный случай, когда требуется поле даты MySQL, – это когда нужны сложные SQL-запросы, используя функции даты MySQL
в самом запросе. (Но такие запросы больше не будут работать на более или менее точных датах!)
Вывод : для «более или менее точных» дат я в настоящее время отбрасываю поле даты MySQL и использую простое поле VARCHAR(10)
с aaaa-mm-jj
форматированными данными. Простое красиво.
Поскольку части данных являются необязательными, было бы утомительно хранить месяцы, дни и год в отдельных целочисленных полях? Или в поле VARCHAR? 2011-02-00 не является допустимой датой, и я бы не думал, что mysql или PHP будут в восторге от этого. Протестируйте его с помощью str_to_time и посмотрите, какие результаты вы получите, также вы подтвердили правильность сортировки в MySQL? Если документы говорят, что требуется от 1 до 31, и он принимает 00, вы можете полагаться на то, что по сути является ошибкой.
Поскольку 2011-02-00 не является допустимой датой, ни одна из функций форматирования PHP не даст вам этого результата. Если бы он справился с этим вообще, я бы не удивился, если бы вы получили 2001-01-31, если бы попытались. Тем более разумно либо хранить его как строку в базе данных, либо помещать месяц, день и год в отдельные целые поля. Если вы поехали с последним маршрутом, вы все равно можете сортировать по этим столбцам.
Я также столкнулся с этой проблемой. Я закончил использование пакета PEAR Date. Большинство классов дат не будут работать с дополнительными месяцами или дополнительными днями, но пакет PEAR Date. Это также означает, что вам не нужны пользовательские функции форматирования и вы можете использовать причудливые методы форматирования, предоставляемые пакетом Date.
Я нашел эту ссылку в учебнике. Это означает, что значения месяца и дня могут быть равны нулю, чтобы обеспечить возможность хранения неполных или неизвестных данных
http://books.google.co.uk/books?id=s_87mv-Eo4AC&pg=PA145&lpg=PA145&dq=mysql+date+of+death+when+month+unknown&source=bl&ots=tcRGz3UDtg&sig=YkwpkAlDtBP1KKTDtqSyZCl63hs&hl=en&ei=Btf5TbL1NIexhAfkveyTAw&sa=X&oi= book_result & кт = результат & resnum = 8 & вед = 0CFMQ6AEwBw # v = OnePage & д & е = ложь
Если вы вытащите свою дату из кусочка из базы данных, вы можете получить ее, как будто это 3 поля.
YEAR(dateField) as Year, MONTH(dateField) as Month, DAY(dateField) as DAY
Затем нажатие их в соответствующие поля в следующем бите PHP даст вам результат, который вы ищете.
$day = 0; $month = 0; $year = 2013; echo $datestring; $format = "Y"; if($month) { $format .= "-m"; if($day) $format .="-d"; else $day = 1; } else { $month = 1; $day = 1; } $datestring = strval($year)."-".strval($month)."-".strval($day); $date = date($format, strtotime($datestring)); echo $date; // "2013", if $month = 1, "2013-01", if $day and $month = 1, "2013-01-01"
в$day = 0; $month = 0; $year = 2013; echo $datestring; $format = "Y"; if($month) { $format .= "-m"; if($day) $format .="-d"; else $day = 1; } else { $month = 1; $day = 1; } $datestring = strval($year)."-".strval($month)."-".strval($day); $date = date($format, strtotime($datestring)); echo $date; // "2013", if $month = 1, "2013-01", if $day and $month = 1, "2013-01-01"