【问题标题】:Explode date/time string into assoc array将日期/时间字符串分解为关联数组
【发布时间】:2012-09-29 15:09:00
【问题描述】:

我有一个从 DB 选项返回的字符串,允许用户设置她/他的日期格式:

F j, Y

这将(今天)然后在我的get_date() 函数中返回以下值:

string 'September 24, 2012' (length=18)

现在我需要一个关联数组来拆分该字符串:

array( 
    'day'   => 24,
    'month' => 'September',
    'year'  => 2012
)

由于不知道用户如何设置她/他的日期,我有一个问题,我不能简单地说F = month, j = day, Y = yearphp date() function 允许的一切,在系统中都是允许的。

问题:我怎样才能“匹配”这些?是否有一些我监督过的本机功能,可以告诉我某事是否是月/日/年/小时/...?

编辑:最大值。我可以使用的 PHP 版本是 PHP 5.2.1

【问题讨论】:

  • 为什么不在数据库中存储时间戳?
  • 存储一个普通的DATETIME,然后在检索时对其进行格式化,但不要以自定义格式保存它 - 进行基于日期的查询怎么样?
  • 我想说你已经监督了快速扫描日期扩展中的函数列表。你不是吗?同样以这种方式存储在数据库中也是做错了事。还是这个 wordpress 你不能改变?
  • @hakra 我应该说什么:就像 wordpress 默认做的一样。
  • 如果可能的话,您真的应该要求主机商升级他们的 PHP 版本。 5.2.1 于 2007 年 2 月 8 日发布。那是 5 年前的事了。 And isn't supported anymore.

标签: php arrays date


【解决方案1】:

如果您有 PHP 5.3 或更高版本,请使用DateTime::createFromFormat

$date = DateTime::createFromFormat($inputFormat, $gotDate);

$result = array(
    'day' => (int)$date->format('j'),
    'month' => $date->format('F'),
    'year' => (int)$date->format('Y')
);

【讨论】:

  • +1,但我没有说明这一点(更新的问题)。 最大值。我可以使用的 PHP 版本 是 PHP 5.2.1 - 因此我的回答是 date_parse()。无论如何谢谢:)
  • 剩下的问题是我仍然不知道是否应该将j映射到day
【解决方案2】:

在我看来,您不应该首先将该字符串存储在数据库中,而应使用时间戳。

如果你这样做,你可以使用类似的东西:

$dateTime = new DateTime($theTimestamp);
$date = array(
    'day' => $dateTime->format('j'),
    'month' => $dateTime->format('F'),
    'year' => $dateTime->format('y'),
);

如果您想灵活地确定数组中的内容,您可以创建如下函数:

function buildDateArray($theTimestamp, $elements) {
    $dateTime = new DateTime($theTimestamp);
    $date = array();
    foreach($elements as $key => $format) {
        $date[$key] = $dateTime->format($format);
    }
}

$theArray = buildDateArray($theTimestamp, array(
    'day' => 'j',
    'month' => 'F',
    'year' => 'y',
));

注意:DateTime 自 5.2.0 起可用

【讨论】:

  • 我的问题是,我仍然不知道j是否属于dayF属于month等等。
  • 正如我在问题中所写:我有一个用户设置。可以是F j, Ym/d/Y。所以我需要知道是否有可能映射它们,所以我不必强迫用户编辑模板来添加 'day' => 'j' 数组来映射它们。
  • 在我的第二个示例(函数)中,您可以轻松映射它。
  • 取决于用户设置?从问题:“由于不知道用户如何设置她/他的日期,我有一个问题,我不能简单地说 F = 月,j = 日,Y = 年。php 日期的所有内容() 函数允许,在系统中是允许的。”.那么你的函数将如何做到这一点?它需要用户定义映射。
  • 我误读了那部分。但是你不能像我在回答中所说的那样在数据库中插入时间戳吗? (幸运的是不知道 WP)。
【解决方案3】:

正如您现在所写的那样,您手头没有 PHP 5.3(真的很遗憾),因此您需要“手动”解析字符串。在 PCRE 正则表达式旁边,还有sscanf。示例:

$date = 'September 24, 2012';
$result = sscanf($date, '%s %2d, %4d', $month, $day, $year);
$parsed = array(
    'day'   => $day,
    'month' => $month,
    'year'  => $year
);
var_dump($parsed);

输出:

array(3) {
  'day' =>
  int(24)
  'month' =>
  string(9) "September"
  'year' =>
  int(2012)
}

这将根据您的格式解析输入日期字符串。如果您需要更灵活,则需要动态构建模式,并将值与结果数组相关联。

我已经编译了另一个执行此操作的示例。它可能有点脆弱(我已经添加了一些注释),但它确实有效。当然,我会将其包装到一个函数中以更好地处理错误情况,但我保留了原始代码,以便更好地显示它是如何工作的:

// input variables:
$date = 'September 24, 2012';
$format = 'F j, Y';

// define the formats:
$formats = array(
    'F' => array('%s',  'month'),  # A full textual representation of a month, such as January or March
    'j' => array('%2d', 'day'),    # Day of the month, 2 digits with or without leading zeros
    'Y' => array('%4d', 'year'),   # A full numeric representation of a year, 4 digits
    # NOTE: add more formats as you need them
);

// compile the pattern and order of values
$pattern = '';
$order = array();
for($l = strlen($format), $i = 0; $i < $l; $i++) {
    $c = $format[$i];

    // handle escape sequences
    if ($c === '\\') {
        $i++;
        $pattern .= ($i < $l) ? $format[$i] : $c;
        continue;
    }

    // handle formats or if not a format string, take over literally
    if (isset($formats[$c])) {
        $pattern .= $formats[$c][0];
        $order[] = $formats[$c][1];
    } else {
        $pattern .= $c;
    }
}

// scan the string based on pattern
// NOTE: This does not do any error checking
$values = sscanf($date, $pattern);

// combine with their names
// NOTE: duplicate array keys are possible, this is risky,
//       write your own logic this is for demonstration
$result = array_combine($order, $values);

// NOTE: you can then even check by type (string/int) and convert
//       month or day names into integers

var_dump($result);

那么这种情况下的结果是:

array(3) {
  'month' =>
  string(9) "September"
  'day' =>
  int(24)
  'year' =>
  int(2012)
}

注意笔记。在我写它之前,我已经检查了 PHP 手册中的用户注释,但是那里提供的函数仅用于解析一种特定的模式,而这个变体应该在一定程度上是可扩展的。如果你只有那一种格式,你自然可以非动态地创建 sscanf 字符串。

另请参阅:date_create_from_format equivalent for PHP 5.2 (or lower)

还要注意,因为这是 wordpress,所以可能会翻译月份名称。

而且我很确定您也可以获取时间戳格式的帖子日期。对于插件而言,仅根据帖子 ID 获取该值而不是解析某些字符串可能会更轻松。

最后一点:只有 Wordpress 有最低 PHP 版本,这并不意味着您的插件也需要这个最低版本。特别是在您概述的情况下,PHP 5.2 不再获得任何支持(它已经死了),您可以帮助您的插件用户告诉他们应该更新他们的 PHP 版本。

看起来 Wordpress 仍然没有给出关于 PHP 版本的警告,它们以某种方式停止使用浏览器和他们自己的软件 ;) 没有必要模仿这种糟糕的做法。告诉您的用户他们处于危险之中并把他们吓跑(或者做闪亮的弹出气泡以一种不那么具有威胁性的方式传达信息。为您的用户提供善意的服务,那么双方都会有所收获双方,做一些优雅的后备来展示你的好态度)。

另见:Is there a Wordpress version that is incompatible with PHP 5.3?

如果您有兴趣,可以在 PHP.net 上找到当前 PHP 的发布周期:https://wiki.php.net/rfc/releaseprocess

【讨论】:

    【解决方案4】:

    已经在原生phpDateTime类中找到答案的第一部分:使用date_parse( get_date() );即可。 自 PHP 5.2 起可用

    // @example
    'year' => int 2012
    'month' => int 9
    'day' => int 24
    'hour' => boolean false
    'minute' => boolean false
    'second' => boolean false
    'fraction' => boolean false
    'warning_count' => int 0
    'warnings' => 
       array
       empty
    'error_count' => int 0
    'errors' => 
       array
       empty
    'is_localtime' => boolean false
    

    这个答案仍然没有解决问题,我不知道如何将j映射到dayFmonth等。

    【讨论】:

    • 不过,您可能会遇到歧义。 d/m/Ym/d/Y,有人吗?
    • @minitech 我刚刚尝试了常见的英语和中欧字符串,它们可以工作,但你是对的:那行不通,因为它不应该存在:P
    • 无论如何,你不能这样做。 date_parse 只是自己弄清楚格式,我认为它通常是正确的。但如果你愿意,我也可以为DateTime::createFromFormat 写一个 shiv :)
    • 如果我知道什么是“shiv”,那可能吗?好吧,就去做吧;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-08
    • 2016-02-18
    • 1970-01-01
    • 2012-04-01
    • 1970-01-01
    • 2022-08-18
    • 1970-01-01
    相关资源
    最近更新 更多