我不敢相信我以前从未遇到过这个。

基本上,我正在解析人工创建的文本文档中的文本,我需要解析的字段之一是日期和时间。因为我在澳大利亚,所以日期格式如下 dd/mm/yyyystrtotime 只想将其解析为美国格式的日期。另外,爆炸式的 / 行不通,因为正如我提到的,这些文档是手写的,其中一些采用以下形式 d M yy.

我尝试过多种组合 setlocale 但无论我如何尝试,语言始终设置为美国英语。

我相当确定 setlocale 是这里的关键,但我似乎无法找到正确的代码。尝试过这些:

  • 非盟
  • 奥恩
  • en_AU
  • 澳大利亚
  • 澳大利亚

我还能尝试什么吗?

为了清楚起见:我在 Windows 机器上运行 IIS。

非常感谢 :)

伊恩

例子:

$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 到 3 之间的 0 或 1 位数字
  • 0 到 9 之间的 1 位数字——是的,这将匹配 37 作为有效日期,但我认为正则表达式已经足够大了!
  • 可能有一些空白
  • 定界字符(“.”、“/”或“”)
  • 可能有一些空白
  • 任何一个:
    • 10 到 12 之间的数字或
    • 1 到 9 之间的数字,可选前导 0
  • 可能有一些空白
  • 定界字符(“.”、“/”或“”)
  • 可能有一些空白
  • 任何一个:
    • 2 位数字长的数字 OR
    • 4 位数字长的数字

希望这能匹配大多数日期书写风格......

有帮助吗?

解决方案

有一个快速修复似乎可以强制 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');

编辑:

正如评论中所述,这是有效的,因为 PHP 将斜杠解释为美国的,将点/破折号解释为欧洲的。

我已经广泛使用了这个技巧,到目前为止没有遇到任何问题。

如果有人有任何充分的理由不使用此功能,请发表评论。

其他提示

问题是 strtotime 不需要 格式 争论。关于什么 strptime?

setlocale() 很糟糕,原因正是您所描述的:你永远不知道你会得到什么。最好手动处理字符串。

Zend框架的 Zend_Date 是一种承诺更准确和一致的日期处理的替代方案。我自己还没有使用它的经验,刚刚开始使用它,但到目前为止,我喜欢它。

啊,这是我们幸运的澳大利亚人遇到的老问题。

我过去做过的事情是这样的

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})$/

$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();

对于未来的读者,请尝试以下方法来解析不受信任的用户输入的日期,其中 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
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top