【问题标题】:PHP date format /Date(1365004652303-0500)/PHP日期格式/Date(1365004652303-0500)/
【发布时间】:2013-05-20 22:17:56
【问题描述】:

我正在调用一个 API,从中获取日期 /Date(1365004652303-0500)/,我不明白这是什么格式。这种日期格式怎么称呼?我不知道用什么谷歌搜索这种格式。

谁能帮我以Y-m-d H:i:s 格式获取这个日期?

我调用的 API 在 .NET 服务器上。当我使用 PHP 的 file_get_contentsjson_decode 调用它时,它为我提供了以下创建日期的日期格式:/Date(1365004652303-0500)/

【问题讨论】:

  • 这是 UNIX 时间戳。在输出 JSON 之前,将其从 UNIX 转换为正常的日期时间字符串。
  • 带有时区偏移的 UNIX 时间戳
  • 嗯,这是我看到的一个选项,还有/Date(13650046523030500)/,然后这就是有趣的开始:)
  • 请添加更多信息,这是哪个 API。
  • 这个时间戳的奇怪之处在于它以毫秒为单位。如果除以 1,000,您会看到一个更合理的数字。这就是让我一开始感到困惑的原因。

标签: php json date


【解决方案1】:

稍微调整 Jason 为 Xero API 给出的出色答案:

if (preg_match('#^\\\/Date\(([-]?[0-9]+)([0-9]{3})([+-][0-9]{4})?\)\\\/$#', $data, $matches)) {
    // Handle Xero API DateTime formats. Examples:
    // "\/Date(1436961673000)\/" - unix timestamp with milliseconds
    // "\/Date(1436961673000+0100)\/" - with an additional timezone correction
    // "\/Date(-1436961673000-0530)\/" - before the epoch, 1924 here
    //
    // RE matches for "\/Date(1436961673090+0100)\/":
    // [1] = ([-]?[0-9]+)       "1436961673"    epoch seconds
    // [2] = ([0-9]{3})         "090"           milliseconds
    // [3] = ([+-][0-9]{4})?    "+0100" or ""   optional timezone
    $result = \DateTime::createFromFormat('U.u', $matches[1] . '.' . $matches[2] . '000')
        ->setTimezone(new \DateTimeZone($matches[3] ?? '+0000'));
}

这使用了当前的 Xero 格式和额外的反斜杠,以及 Jason 在评论中建议的减少正则表达式分组的简化。

【讨论】:

    【解决方案2】:

    你可以使用这个包来解析 JSON 日期:

    https://github.com/webapix/dot-net-json-date-formatter

    use \Webapix\DotNetJsonDate\Date;
    
    $dateTime = Date::toDateTime('/Date(1365004652303-0500)/'); 
    // return with \DateTime object, you can format it: $dateTime->format('Y-m-d H:i:s')
    

    【讨论】:

      【解决方案3】:

      这就是我用来从 Xero API 解析时间戳的方法。它占:

      • 负时间戳,纪元之前的日期。
      • 少于 10 位数字的时间戳(但在纪元 - 时间为零 - 甚至不确定该格式会是什么样子)
      • 几分之一秒。
      • 可选的时区偏移,正负。

      代码:

      if (preg_match('#^(/Date\()([-]?[0-9]+)([0-9]{3})([+-][0-9]{4})?(\)/)$#', $data, $matches)) {
          // Handle Xero API DateTime formats. Examples:
          // "/Date(1436961673000)/" - unix timestamp with milliseconds
          // "/Date(1436961673000+0100)/" - with an additional timezone correction
          // "/Date(-1436961673000-0530)/" - before the epoch, 1924 here
          //
          // RE matches for "/Date(1436961673090+0100)/":
          // [1] = (/Date\()          "/Date("
          // [2] = ([-]?[0-9]+)       "1436961673"    epoch seconds
          // [3] = ([0-9]{3})         "090"           milliseconds
          // [4] = ([+-][0-9]{4})?    "+0100" or ""   optional timezone
          // [5] = (\)/)              ")"
      
          $result = \DateTime::createFromFormat('U u', $matches[2] . ' ' . $matches[3] . '000')
              ->setTimezone(new \DateTimeZone($matches[4] ?: '+0000'));
      }
      

      【讨论】:

      • 回到这一点,它可能可以简化一点。通过从开头和结尾删除括号分组,将只使用中间的三个 RE 匹配项。 [2] 到 [4] 将变为 [1] 到 [3]。
      【解决方案4】:

      Baba's answer 很有帮助,但它不包括我需要的 3 个案例:

      • 时间戳可能为负数
      • 时间戳可能少于 10 位
      • 可能缺少 GMT 偏移量。

      这是我用来获取时间戳的:

      $date_string = '/Date(-594262800300+0100)/';
      preg_match('/([+-]?\d+)([+-]\d{4})?/', $date_string, $matches);
      $timestamp = $matches[1] / 1000;
      $hours = $matches[2] * 36; // Get the seconds
      return $timestamp + $hours;
      

      同样,正如 Ghigo 所说,如果偏移量包含分钟,这是不正确的,但它适用于我的情况。

      【讨论】:

      • 如果您有新问题,请点击 按钮提出问题。如果有助于提供上下文,请包含指向此问题的链接。 - From Review
      • 感谢@Luceos 的评论。我没有新问题,我正在添加更多以前的答案或 cmets 中没有的信息,我相信它可能对其他用户有用。
      • 您的回答是问题的新演变。答案应该只回答给出的问题。您可以针对您的情况提出一个新问题并自己回答。如果自我回答的问题对社区有价值,则允许这样做。
      【解决方案5】:

      首先你需要了解你拥有的格式

      /Date(1365004652303-0500)/
      

      那么你有

      • 时间戳 (U) = 1365004652
      • 毫秒 (u) = 303
      • 与格林威治时间 (GMT) (O) 的差异 = -0500

      构建格式

      $date = '/Date(1365004652303-0500)/';
      preg_match('/(\d{10})(\d{3})([\+\-]\d{4})/', $date, $matches);
      $dt = DateTime::createFromFormat("U.u.O",vsprintf('%2$s.%3$s.%4$s', $matches));
      echo $dt->format('r');
      

      输出

      Wed, 03 Apr 2013 15:57:32 -0500
                                  ^
                                  |= Can you see the GMT ? 
      

      interface DateFormatParser
      {
          /**
           * @param $string
           *
           * @return DateTime
           */
          public function parse($string);
      
      }
      
      abstract class PregDateParser implements DateFormatParser
      {
          protected $pattern, $format, $mask;
      
          public function parse($string) {
              $string = (string)$string;
      
              $pattern = $this->pattern;
              $format  = $this->format;
              $mask    = $this->mask;
      
              $r = preg_match($pattern, $string, $matches);
              if (!$r) {
                  throw new UnexpectedValueException('Preg Regex Pattern failed.');
              }
              $buffer = vsprintf($mask, $matches);
              $result = DateTime::createFromFormat($format, $buffer);
              if (!$result) {
                  throw new UnexpectedValueException(sprintf('Failed To Create from Format "%s" for "%s".', $format, $buffer));
              }
              return $result;
          }
      }
      
      class JsonTimestampWithOffsetParser extends PregDateParser
      {
          protected $pattern = '/^\/Date\((\d{10})(\d{3})([+-]\d{4})\)\/$/';
          protected $format  = 'U.u.O';
          protected $mask    = '%2$s.%3$s.%4$s';
      }
      
      $date   = '/Date(1365004652303-0500)/';
      $parser = new JsonTimestampWithOffsetParser;
      $dt     = $parser->parse($date);
      
      echo $dt->format('r');
      

      【讨论】:

      【解决方案6】:

      我有一些稍微不同的经历,这使我对巴巴的出色回答做了一些细微的改动。

      使用 Newtonsoft 的 JSON 库在 .NET 中编码消息,然后我将其发送到我们的网站(PHP 部分),我在时区偏移前得到一个空格,并且没有 +/- 字符。

      我还看到了前纪元日期的负数,这意味着我需要在毫秒值之前提供 - 符号。

      我将正则表达式更改为此,它对我来说非常有效:

      ^/Date(([-]?\d{10})(\d{3})\s?([+-]?\d{4}))/$

      这两个区别是

      [-]? 在 10 位毫秒值之前,以及 \s? 在时区偏移之前。

      我会将此作为对 Baba 回答的评论,但我缺乏声誉不允许我这样做。我希望这适合我在这里发帖,因为我认为它可能有用。

      【讨论】:

        【解决方案7】:

        如果您的日期类似于/Date(-62135578800000)/,则为不带时区的正整数或负整数:

        $date = substr('/Date(-62135578800000)/', 6, -5);
        $date = date('m/d/Y H:i:s', $date + date('Z', $date) * -1);
        // 01/01/0001 05:00:00
        

        【讨论】:

          【解决方案8】:

          试试这个:

          var_dump(date('Y-m-d H:i:s', '1365004652303'/1000));
          $str = '/Date(1365004652303-0500)/';
          
          $match = preg_match('/\/Date\((\d+)([-+])(\d+)\)\//', $str, $date);
          
          $timestamp = $date[1]/1000;
          $operator = $date[2];
          $hours = $date[3]*36; // Get the seconds
          
          $datetime = new DateTime();
          
          $datetime->setTimestamp($timestamp);
          $datetime->modify($operator . $hours . ' seconds');
          var_dump($datetime->format('Y-m-d H:i:s'));
          

          返回:

          string(19) "2013-04-03 17:57:32"
          string(19) "2013-04-03 12:57:32"
          

          【讨论】:

          • 这是正确答案。我的答案是从偏移量中获取时区,但没有正确考虑夏令时。
          • 小心:当小时也包含分钟时,这将导致错误的转换,例如 0930。必须拆分小时和分钟并正确计算。
          【解决方案9】:

          这个时间戳以毫秒为单位,这就是它这么大的原因。

          您可以根据需要使用 PHP date() 调用来格式化此时间戳。只需先除以 1,000。在标准美国格式中,它将是

          $mydate = date('m d Y', $timestamp);

          (其中 $timestamp 是 1365004652303)

          要将其格式化为您请求的格式(Y-m-d H:i:s),您可以使用“Y-m-d H:i:s”作为格式字符串(第一个参数)。剪掉以“-”开头的文字。

          $stamps = preg_split("/-/", $time);
          $stamps[0] = $stamps[0]/1000; 
          $mydate = date('Y-m-d H:i:s', $stamps[0]); 
          

          这会产生 2013-04-03 11:57:32

          其他人建议 0500 是偏移量;如果是这样,您需要相应地调整 $stamps[0] 。

          【讨论】:

          • 永远不要使用preg_split()explode() 可以做的事情。我从不使用 explode() 来做 strstr()true 第三个参数可以做的事情。
          【解决方案10】:

          让我们把/Date(1365004652303-0500)/分解成:

          • 日期
          • 1365004652303
          • -0500

          第一个字符串很清楚。

          下一个大数是纪元值

          -0500 表示最初存储日期的时区。它与 UTC 相关,因此指的是东部标准时间。


          编辑

          纪元的精度为毫秒。试试这个代码:

          <?php
              $str = "/Date(1365004652303-0500)/";
              preg_match( "#/Date\((\d{10})\d{3}(.*?)\)/#", $str, $match );
              echo date( "r", $match[1] );
          ?>
          

          您还可以使用时区来设置相对于您自己的日期。 http://codepad.viper-7.com/RrSkMy

          【讨论】:

          • @Jimbo 它永远不会变老:P
          • @hjpotter92 输出提前 5 小时.. 可能与时区有关。
          • @KalpeshMehta 正如我在回复中提到的:您还可以使用时区来设置相对于您自己的日期。
          • @hjpotter92 - 如果日期中的时区设置为您自己的,那很好。如果他得到一个偏移量为 -0800 的时间并且他在 EST 会发生什么?
          【解决方案11】:

          以下示例使用preg_match()DateTime 类:

          $date = '/Date(1365004652303-0500)/';
          
          // get the timestamp
          $pattern = '~/Date\(([0-9]*)~';
          preg_match($pattern, $date, $matches);
          $timestamp = round(((int) $matches[1]) / 1000);
          
          $dt = new DateTime();
          $dt->setTimestamp($timestamp);
          
          echo $dt->format('Y-m-d H:i:s');
          

          【讨论】:

          • (integer) $matches[1]; 失败
          • @Baba :O ??哪个 PHP 版本?
          • 32 位系统 ... (int) $matches[1];会一直返回PHP_INT_MAX
          • 我有一个 64 位系统。不知道 (int) 和 (integer) 的行为不同
          猜你喜欢
          • 2014-10-08
          • 1970-01-01
          • 2023-01-03
          • 2021-01-23
          • 1970-01-01
          • 2018-05-19
          • 2016-04-25
          • 2021-11-14
          • 2016-05-22
          相关资源
          最近更新 更多