【问题标题】:Problem to convert unix time to human time将unix时间转换为人类时间的问题
【发布时间】:2019-06-05 13:45:17
【问题描述】:

我有一个在线控制器,我想知道我的接入点的正常运行时间和最后一次看到的时间。为此,我使用 epoch convert 方法将 unix 时间转换为人类可读时间。

这是我使用的代码

// getting controller ap info //

    $name=$status=$uptime=$last_seen=[];
foreach ($ligowave->result as $index => $obj) {
    $name[]      = $obj->name;
    $status[]    = $obj->status;
    $uptime[]    = $obj->uptime;
    $last_seen[] = $obj->last_seen;
}


// time settings //

$epoch = $uptime;
$uptimetime = (new DateTime("@$epoch"))->format(' H:i:s');

$epoch = $last_seen;
$lastseendate = (new DateTime("@$epoch"))->SetTimeZone(new DateTimeZone('Europe/Amsterdam'))->format(' d-m-Y H:i:s');

if ($status == "up") {
    echo $name;
    echo " is up, ";
    echo "uptime is:" . $uptimetime;
} else {
    echo $name;
    echo " is down, ";
    echo "device is last seen:" . $lastseendate;
}
return array($name, $status, $epoch, $uptimetime, $lastseendate);
}

我得到的错误是:

PHP 致命错误:未捕获的异常:DateTime::__construct(): 失败 在位置 0 (@) 解析时间字符串 (@Array):意外字符

【问题讨论】:

  • 什么被覆盖了?你在循环之外做什么?逻辑猜测会建议您想要 $var[] .. 但实际情况可能与逻辑不同
  • 我感觉之前已经在 SO(可能是昨天)上问过这个问题,并且也得到了接受的答案。
  • 这是link@vivek_23吗?
  • @quickSwap 是的。
  • 是的,但现在我得到的是第一个或最后一个

标签: php arrays foreach


【解决方案1】:

请注意:

此答案关于解决问题中所述的特定 PHP 错误。有关如何有效编写代码以迭代数组的更广泛的答案,请参阅Fyrye's answer

您收到的错误是:

PHP 致命错误:未捕获异常:DateTime::__construct():无法在位置 0 (@) 解析时间字符串 (@Array):意外字符

究竟出了什么问题,为什么?

1) 您有一个未捕获的异常,由于未捕获,它会引发致命错误。异常是对象编程的核心,在您的 PHP 脚本中应该是 researched and implemented

2) 为什么你首先有一个例外?该错误指出异常是由“无法解析时间字符串(@Array)”引起的。所以你试图给DateTime 对象一个array,而它需要一个string。它会帮助你Read the PHP DateTime __construct Manual Page

3) 此外,更具体地说,@ 字符是出乎意料的;这意味着它不应该在那里。该字符仅在后跟 string 格式的 timestamp 整数值时有效。

因为数组作为字符串(即引号)输出,所以最终结果是“@Array”,所以@DateTime 直接采用;但当然,在任何非数字传入时间字符串中,DateTime 都不会期望该字符。这是您的致命错误的根本原因。

虽然 PHP 确实在一定程度上采用了松散的类型转换,但将数组 $var 括在引号中实在是太松散了,因此该数组只输出“Array”并发出相应的 PHP 通知:

注意:数组到字符串的转换.....

要获得正确的 DateTime 字符串格式的有效列表以提供对象,您可以view this page from the PHP Manual

4) 我不明白你为什么需要那些外括号?

那么,这应该怎么做呢?

从 4 到 1 以相反的顺序阅读问题;解决此特定错误的正确方法是:

  • 将尝试包装到 try/catch 块中以避免这些致命错误。
  • 确保赋予DateTime 对象的值是字符串
  • 从该字符串中删除不必要和无效的字符。

所以:

$epoch = $uptime;

try{ 
     /***
      * Uptime appears to be a numeric array of time string values 
      * Therefore go for the first one. 
      * You may want to wrap this code in a loop to catch each one.  
      ***/
     $uptimeTime = new DateTime("@".(string)$epoch[0]);
}
catch (Exception $ex){
    /***
     * If you wish to ignore these errors simply leave this block empty
     ***/
    error_log("There was a problem on line ".__LINE__."! ".print_r($ex));
}
/***
 * By default UTC timestamps are not zoned.   
 ***/
// $uptimeTime->setTimeZone(new DateTimeZone('Europe/Amsterdam'));

$uptimeTimeOutput = $uptimeTime->format('H:i:s');
/***
 * $uptimeTimeOutput is the correctly formatted date from $epoch[0]
 ***/
 print $uptimeTimeOutput; 

我希望通过上面给出的信息,您能够自己更正第二个DateTime 实例化代码(即new DateTime 行)。 :-)

TL;DR

请阅读 PHP 手册并允许它告知您的编码选择。

【讨论】:

  • 从 OOP 显示的代码来看,$epoch 是一个有效值数组。如果这些值是时间戳ints,是的,这是行不通的,我个人发现DateTime 构造远不如其他 DateTime 方法灵活。谢谢!
  • 请注意,作者是having issues with understanding array iterationoriginal question 已被现在删除的答案解决,这导致 OP 现在遇到的时间戳数组出现问题。
  • @fyrye 再次感谢。我看到了您关于数组迭代的帖子,这是一个很好的解释,我不想对您的答案大加指责,而是想真正澄清和清除问题上显示的特定错误(仅)。 SO上的许多帖子都是OP问题的多米诺骨牌效应.....
  • @fyrye 我已经大量修改了我的答案。我还删除了关于时区的部分。干杯
【解决方案2】:

主要问题是由将$uptime[] 定义为值数组引起的,导致$epoch = $uptime 包含时间戳字符串数组。当 DateTime() 需要单个 string 值时。

要解决此问题,您需要将 DateTime 调用移动到 foreach 迭代中。

正如 Martin 提供的答案中提到的,另一个问题是您没有在代码中处理异常。如果uptimelast_seen 不是提供给DateTime 构造函数的预期值,则会引发异常。

要处理异常,您可以使用try/catch 块来处理代码中出现的问题。异常旨在指出您代码中的致命错误,以便您可以通过编程方式解决或验证它们,通常不应使用try/catch 忽略它们。更多详情请查看https://www.php.net/manual/en/language.exceptions.php

不知道你想用你的代码完成什么。看来您想要echoreturn 所有来自$ligowave->result 的值。我在下面进行了适当的更改,以反映我猜你的意图。以及一些小的简化。

请澄清您想要returnecho 的内容,我会调整答案。

示例:https://3v4l.org/O0nS6

   //...

    // getting controller ap info //

        $values = [];
        foreach ($ligowave->result as $index => $obj) {
            //convert the unix timestamps to DateTime objects
            $uptime = (new DateTime('@' . $obj->uptime));
            $last_seen = (new DateTime('@' . $obj->last_seen))->setTimeZone(new DateTimeZone('Europe/Amsterdam'));

            //store the return values into an array
            $values[] = $value = [
                'name' => $obj->name,
                'status' => $obj->status,
                'uptimetime' => $uptime->format('H:i:s'),
                'lastseendate' => $last_seen->format('d-m-Y H:i:s')
            ];

            //output each of the statuses
            printf('%s is %s, ', $obj->name, $obj->status);
            if ('up' === $obj->status) {
                echo 'uptime is: ' . $value['uptimetime'];
            } else {
                echo 'device is last seen: ' . $value['lastseendate'];
            }
        }

        return $values;
}

结果:

foo is up, uptime is: 10:20:54
bar is down, device is last seen: 01-06-2019 08:22:30

返回:

array (
  0 => 
  array (
    'name' => 'foo',
    'status' => 'up',
    'uptimetime' => '10:20:54',
    'lastseendate' => '05-06-2019 11:16:21',
  ),
  1 => 
  array (
    'name' => 'bar',
    'status' => 'down',
    'uptimetime' => '10:20:54',
    'lastseendate' => '01-06-2019 08:22:30',
  ),
)

您似乎还使用 24 小时时间来表示持续时间。 如果是这样,您将需要使用DateInterval 而不是DateTime,通过在适当的时间范围内使用DateTime::diff。更多详情请查看https://php.net/manual/en/class.dateinterval.php

假设uptime 是开始时间,last_seen 是当前运行时间,您可以使用$uptime->diff($last_seen) 来检索uptimelast_seen(持续时间)之间经过的时间,而不是 24 uptime 的小时时间值。否则,您可以使用$uptime->diff(new DateTime('now', new DateTimeZone('Europe/Amsterdam'))) 来使用当前日期时间。

需要注意的是,DateInterval 的小时数是不可累积的,这意味着您需要以某种方式添加天数。我使用了最准确的%a,而不是使用days * 24 增加时间

示例:https://3v4l.org/LHdqL

//...

$uptime = (new DateTime('@' . $obj->uptime))->setTimeZone(new DateTimeZone('Europe/Amsterdam'));
$last_seen = (new DateTime('@' . $obj->last_seen))->setTimeZone(new DateTimeZone('Europe/Amsterdam'));
$values[] = $value = [
    'name' => $obj->name,
    'status' => $obj->status,
    'lastseendate' => $last_seen->format('d-m-Y H:i:s'),
    'uptimetime' => $uptime->diff($last_seen)->format('%a.%H:%I:%S'), //DD.HH:MM:SS
];

//...

结果:

foo is up, uptime is: 12.22:48:26

【讨论】:

  • @Martin 谢谢,不确定处理异常的意图,所以我专注于异常的原因,而不是处理它们,但我已经更新包含关于排除异常处理的注释.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-13
  • 1970-01-01
  • 1970-01-01
  • 2021-03-14
  • 2012-10-14
  • 2018-07-30
  • 2010-12-11
相关资源
最近更新 更多