Как сделать даты синтаксического анализа strtotime в австралийском (то есть в Великобритании) формате: dd/mm/yyyy?

Я не могу поверить, я никогда раньше не сталкивался с этим.

В принципе, я разбираю текст в текстовых документах, созданных человеком, и одно из полей, которые мне нужно проанализировать, - это дата и время. Поскольку я нахожусь в Австралии, даты отформатированы как dd/mm/yyyy, но strtotime только хочет проанализировать его как дату форматирования в США. Кроме того, взлом / не будет работать, поскольку, как я уже упоминал, эти документы вводятся вручную, а некоторые из них имеют форму d M yy.

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

Я уверен, что setlocale - это ключ, но, похоже, я не могу нанести удар по правильному коду. Пробовал эти:

  • аи
  • аи-ан
  • en_AU
  • Австралия
  • AUS

Что-нибудь еще я могу попробовать?

Для ясности: я запускаю IIS с окном Windows.

Большое спасибо:)

Иэйн

Пример:

$mydatetime = strtotime("9/02/10 2.00PM");
echo date('j F Y H:i', $mydatetime);

Выдает

2 September 2010 14:00

Я хочу, чтобы он создавал:

9 February 2010 14:00

Мое решение

Я даю тик на один из ответов здесь, поскольку это гораздо более легкое для чтения решение для моего, но вот то, что я придумал:

$DateTime = "9/02/10 2.00PM";
$USDateTime = preg_replace('%([0-3]?[0-9]{1})\s*?[\./ ]\s*?((?:1[0-2])|0?[0-9])\s*?[./ ]\s*?(\d{4}|\d{2})%', '${2}/${1}/${3}', $DateTime);  
echo date('j F Y H:i',strtotime($USDateTime));

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

  • 0 или 1 цифра между 0 и 3
  • 1 цифра между 0 и 9 - да, это будет 37, как действительная дата, но я думаю, что регулярное выражение уже достаточно большое!
  • Может быть несколько пробелов
  • Разделительный символ (a '.', a '/' или '')
  • Может быть несколько пробелов
  • Либо:
    • Число от 10 до 12 OR
    • Число от 1 до 9 с необязательным ведущим 0
  • Может быть несколько пробелов
  • Разделительный символ (a '.', a '/' или '')
  • Может быть несколько пробелов
  • Либо:
    • Число в 2 цифры длинное ИЛИ
    • Число в 4 цифры длиной

Надеюсь, это будет соответствовать большинству стилей написания даты...

Ответ 1

Есть быстрое исправление, которое, как кажется, заставляет PHP strtotime использовать формат даты в Великобритании. То есть: заменить все "/" в входящей строке на "-".

Пример:

date('Y-m-d', strtotime('01/04/2011'));

Создать: 2011-01-04

date('Y-m-d', strtotime('01-04-2011'));

Создать: 2011-04-01

Для достижения этой цели вы можете использовать str_replace.

Пример:

str_replace('/', '-', '01/04/2011');

EDIT:

Как указано в комментариях, это работает, потому что PHP интерпретирует косые черты как американские и точки/тире как европейские.

Я использовал этот трюк широко и не имел проблем до сих пор.

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

Ответ 2

Проблема заключается в том, что strtotime не принимает аргумент формата. Что насчет strptime?

Ответ 3

setlocale() сосет именно по той причине, которую вы описываете: вы никогда не знаете, что вы собираетесь получить. Лучше всего обрабатывать строку вручную.

Zend Framework Zend_Date - одна из альтернативных перспективных более точных и последовательных обработок даты. У меня пока нет опыта, я только начинаю работать с ним, но до сих пор мне это нравится.

Ответ 4

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

То, что я делал в прошлом, это что-то вроде этого

public static function getTime($str) { // 3/12/2008

       preg_match_all('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/', $str, $matches);

       return (isset($matches[0][0])) ? strtotime($matches[3][0] . '-' . $matches[2][0] . '-' . $matches[1][0]) : NULL;

    }

Хотя это зависит от дат в этом формате dd/mm/yyyy.

Возможно, вы можете использовать другое регулярное выражение для преобразования из d M yy или использовать измененное. Я не знаю, было ли это правильно, но это может быть начало:

/^(\d{1,2})(?:\/|\s)(\d{1,2})(?:\/|\s)(\d{2,4})$/

Ответ 5

$date = date_create_from_format('d/m/Y', $date_string);
$unix_timestamp = $date->getTimestamp();

или

$date = DateTime::createFromFormat('d/m/Y', $date_string);
$unix_timestamp = $date->getTimestamp();

Ответ 6

Для будущих читателей попробуйте следующее для синтаксического анализа дат из неуправляемого пользовательского ввода, для которого strptime() является слишком жестким. Он выводит строки даты ISO, которые вы можете передать на new Date(), strtotime() и т.д., Или false для недействительных дат, или null для непригодного ввода. Вам придется адаптировать его к процессу. Он также принимает 2-значный год и ввод даты ISO.

function parseUserDate($input, $allow_zero = false) {
    if (!is_string($input)) {
        return $input === null ? null : false;
    }
    $input = preg_split('/\\D+/', $input, null, PREG_SPLIT_NO_EMPTY);
    if (!$input) {
        return null;# no date
    }
    if (count($input) == 3) {
        list($od, , $oy) = $input;
        if (strlen($od) > 2 && strlen($oy) < 3) {# assume ISO
            $oy = $od;
            $input = array_reverse($input);
        }
        $intify = function($dig) {
            return (int) ltrim($dig, '0');# prevent octals
        };
        list($d, $m, $y) = array_map($intify, $input);
        if (strlen($oy) < 3) {
            $current_year = date('Y');
            $current_year_2 = $intify(substr($current_year, -2));
            $diff = $y - $current_year_2;
            if ($diff > 50) {
                $diff -= 100;
            }
            elseif ($diff < -50) {
                $diff += 100;
            }
            $y = $diff + $current_year;
        }
        if (
            ($allow_zero && $d == 0 && $m == 0 && $y == 0)
            || checkdate($m, $d, $y)# murrican function
        ) {
            return sprintf('%04d-%02d-%02d', $y, $m, $d);
        }
    }
    return false;# invalid date
}