【问题标题】:Using strtotime for dates before 1970对 1970 年之前的日期使用 strtotime
【发布时间】:2010-05-20 05:37:41
【问题描述】:

我在 mysql 中有一个文本列,它以 yyyy-mm-dd 格式存储一个日期值。 现在,在我的 php 页面中,我使用此代码解析为日期值。

date("F j, Y", strtotime($row['value']));

现在,我刚刚读到 strtotime() 仅在 1970 年 1 月 1 日之后解析值。我在该日期之前有很多日期值。有解决办法吗?我不想改变我的数据库结构。

【问题讨论】:

    标签: php mysql


    【解决方案1】:

    来自documentation for strtotime()

    strtotime() 的范围限制在格林威治标准时间 1901 年 12 月 13 日星期五 20:45:54 和格林威治标准时间 2038 年 1 月 19 日星期二 03:14:07 之间;尽管在 PHP 5.1.0 之前,此范围在某些操作系统 (Windows) 上被限制在 01-01-1970 到 19-01-2038。

    您运行的是什么版本的 PHP?在什么平台上?也许是时候升级了。

    如果您正在处理 1901 年 12 月 13 日至 2038 年 1 月 19 日范围之外的日期,请考虑使用 PHP 的 DateTime 对象,它可以处理更广泛的日期范围。

    程序:

    $date = date_create($row['value']);
    if (!$date) {
        $e = date_get_last_errors();
        foreach ($e['errors'] as $error) {
            echo "$error\n";
        }
        exit(1);
    }
    
    echo date_format($date, "F j, Y");
    

    面向对象:

    try {
        $date = new DateTime($row['value']);
    } catch (Exception $e) {
        echo $e->getMessage();
        exit(1);
    }
    
    echo $date->format("F j, Y");
    

    【讨论】:

    • 谢谢 - 我正在使用 Apache Solr 搜索引擎,因此不能选择使用 mysql date_format 函数,因为所有日期都需要以 YYYY-MM-DDTHH-MM-SSZ 格式编制索引。然后必须使用 PHP 对其进行解析(我正在使用 PHP api 来检索搜索结果),DateTime 就是票。编辑:这可能是其他使用 Apache Solr 遇到此问题的人的答案:wiki.apache.org/solr/DataImportHandler#DateFormatTransformer
    • @Mark:我有 php5.2.6,strtotime 仍然显示 1970 年之前的空白日期。你在哪里看到“5.1.0 之前...”的东西?
    • @ScottChu - 时间戳是有符号整数;负值用于格林威治标准时间 1970 年 1 月 1 日 00:00:00 之前的秒数,并且自 5.1.0 以来一直在所有平台上......对此的参考在 docs 页面的注释部分(注2)
    • @Mark:谢谢!我只是想念笔记部分。
    【解决方案2】:

    您应该使用date 列,而不是文本列。
    date_format() SQL 函数来格式化查询中的日期

    【讨论】:

    • 我无法更改列类型。我在文本列中有几个值,其中一些是日期(格式为 yyyy-mm-dd)。还有另一列指定该行是否包含日期值或文本值。
    • 在这种情况下,您需要重新设计您的数据库。
    • 您是说不重新设计数据库就无法解决这个问题吗?我只想将格式为 yyyy-mm-dd 的文本转换为日期格式 F j, Y。例如:1820-05-20 到 1820 年 5 月 20 日。
    • 日期完全没有问题。还有我写的解决方案。如果您在一列中有不同类型的数据,那么您已经破坏了整个数据库的机器人。没有解决方案,它会让你直接走向灾难
    【解决方案3】:
    function safe_strtotime($string)
    {
        if(!preg_match("/\d{4}/", $string, $match)) return null; //year must be in YYYY form
        $year = intval($match[0]);//converting the year to integer
        if($year >= 1970) return date("Y-m-d", strtotime($string));//the year is after 1970 - no problems even for Windows
        if(stristr(PHP_OS, "WIN") && !stristr(PHP_OS, "DARWIN")) //OS seems to be Windows, not Unix nor Mac
        {
            $diff = 1975 - $year;//calculating the difference between 1975 and the year
            $new_year = $year + $diff;//year + diff = new_year will be for sure > 1970
            $new_date = date("Y-m-d", strtotime(str_replace($year, $new_year, $string)));//replacing the year with the new_year, try strtotime, rendering the date
            return str_replace($new_year, $year, $new_date);//returning the date with the correct year
        }
        return date("Y-m-d", strtotime($string));//do normal strtotime
    }
    

    【讨论】:

    • strtotime 返回时间戳,您的函数返回 ISO 8601 日期。这是一个极其重要的区别!
    • 确实你是对的。然而,@Ctroy 要求的是一种获得 ISO 8601 日期的方法,所以我想我的不精确可以原谅!
    【解决方案4】:
    $date = DateTime::createFromFormat('d M Y','17 Jan 1900');
    echo $date->format('Y-m-d');
    

    【讨论】:

      【解决方案5】:

      我是一个菜鸟,并且在使用 strtotime 与爆炸时遇到了一些类似的问题。我遇到了这个线程,并且在马克贝克更改日期限制方面得到了 cmets 的极大帮助(谢谢!)。所以我写这段代码只是为了玩这个概念。也许它会帮助像我这样的其他菜鸟。

      只需更改顶部 PHP 行的日期,看看下面的日期会发生什么 - 非常有趣。 再次感谢!

      <?php $dob = "1890-11-11"; ?>
      <html>
      <head>
      <style>
      
      .inputdiv {
          width:200px;
          margin:100px auto 10px auto;
          background-color:#CCC2FC;
          text-align:center;
          border:1px solid transparent;}
      
      .spacer{
          width:199px;
          margin:20px auto 20px auto;}    
      
      </style>
      </head>
      <body>
      
      <div class="inputdiv">
        <div class="spacer"><?php echo "Raw dob: ".$dob ?></div>
        <div class="spacer"><?php echo "Strtotime dob: ".date("m-d-Y", strtotime($dob)) ?></div>
        <div class="spacer"><?php list ($y, $m, $d) = explode('-', $dob);
                             $dob = sprintf("%02d-%02d-%04d", $m, $d, $y);
                             echo "Explode dob: ".$dob ?></div>
      </div>
      </body>
      </html>
      

      【讨论】:

        【解决方案6】:

        为了适应现代,PHP7 strtotime() 在 64 位系统上几乎可以处理任何 AD 日期,尽管出于某种原因手册页仍然显示 1970。

        $t = strtotime("4/1/1492");
        echo "Stamp: $t\n";
        echo date("m/d/Y",$t);
        

        结果:

        Stamp: -15076350000
        04/01/1492
        

        $t = strtotime("8/1/4921");
        echo "Stamp: $t\n";
        echo date("m/d/Y",$t);
        

        结果

        Stamp: 93142933200
        08/01/4921
        

        【讨论】:

        • 这似乎对我不起作用,尽管我使用的是 PHP7.1.10,或者你是说这总是会改变 1970 年到 1970 年之前的任何日期?
        • 您使用的是什么操作系统?它是 64 位操作系统吗?它适用于 Linux、FreeBSD 和 OSX。 strtotime() 为 1970 年之前的日期生成负日期。要超过 65 年,您需要 64 位版本。
        • Windows 10 64 位,当我复制你的代码时它只显示“stamp:”
        • 听起来 strtotime 返回 false?如果 windows 落后于时代 5 年,我们会感到惊讶吗?抱歉,我在 windows 系统上没有 php,所以我无法测试它。
        • 发现这个stackoverflow.com/a/10924871/4220457 非常有用,因为我不知道为什么它不起作用
        【解决方案7】:

        我有一个 Sql 数据库来处理美国每个州的成立时间,可以追溯到 1787 年。该字段在数据库中设置为 DATE,格式为 YYYY-MM-DD(例如 1787-12-07) .我尝试了很多方法,但我发现最简单有效的是: (我使用的确切代码片段。根据需要更改信息和变量。)

            <?php    
            $page = 'geo-usa.php';
            $sort = 'stateName';
             if (isset($_GET['sortBy'])){
              $sortBy = $_GET['sortBy'];
               if($sortBy == 'stateEst'){
                $sort = 'stateEst'; }
               if($sortBy == 'capital'){
                $sort = 'stateCapital'; }      
               if($sortBy == 'capitalEst'){
                $sort = 'stateCapitalEst'; }     }    
            $con=mysqli_connect($servername, $hostname, $password, $database);
             if (mysqli_connect_errno()){ print "Failed to connect to MySQL: " . 
               mysqli_connect_error(); exit(); }
            $stateData = "SELECT * FROM state ORDER BY $sort ASC, stateEst ASC";
            $stateData2 = mysqli_query($con, $stateData);
             while($stateData3 = mysqli_fetch_array($stateData2, MYSQLI_ASSOC)){
              $stateID = $stateData3['stateID'];
              $stateName = $stateData3['stateName'];
              $stateAbr = $stateData3['stateAbr'];
              $stateEstYear = $stateData3['stateEstYear'];
              $stateEst = $stateData3['stateEst'];
              $stateCapital = $stateData3['stateCapital'];
              $stateCapitalEst = $stateData3['stateCapitalEst'];
              $stateMotto = $stateData3['stateMotto'];
        
            //Here is how you format a yyyy-mm--dd date within a database
              $stateEstDate = date_create($stateData3['stateEst']);
              $stateEstFormat = date_format($stateEstDate, "l F d, Y");
            /// <- remove comments -
        
              print "<table border='0' bordercolor='lime' cellpadding='1' 
                    cellspacing='1' width='100%'>
                 <tr>
                   <td align='left' style='padding-top:10px;'>
                     <a href='$page' style='font-size:14px; color:red; text- 
                       decoration:none; padding-left:7px'>
                     $stateName</a></td>
                  </tr>
                 <tr>
                   <td align='left' style='padding-left:20px;'>
                     <a href='$page?sortBy=stateEst' style='font-size:10px; 
                       color:white; text-decoration:none;'>
                     $stateEstFormat </a></td>
                  </tr>
                </table>"; } ?>
        

        前 2 行的输出是:

        特拉华州 1787 年 12 月 7 日星期五

        宾夕法尼亚州 1787 年 12 月 12 日星期三

        【讨论】:

        • 感谢您的回答,但您能否删除所有与问题解决方案无关的样板代码?例如,所有的 HTML 部分都与解决方案无关。如果答案与 PHP 的 date_create 函数有关,您可以随时添加指向该函数文档的链接,或者解释其工作原理(顺便说一下,我不知道您的解决方案是否有效,我没有检查)。只是一些建议,使您的答案更有用;)
        • 我添加了整个代码片段以提供上下文。另外,我正在转换的日期在 while 语句中声明为变量。为了了解日期的来源,我展示了从数据库中选择的内容。这里太多的答案并不能说明他们是如何获得解决方案的。我刚刚包含了 HOW。
        猜你喜欢
        • 1970-01-01
        • 2013-05-26
        • 1970-01-01
        • 1970-01-01
        • 2016-03-29
        • 2023-04-09
        • 2023-03-16
        • 2011-07-02
        • 2017-04-28
        相关资源
        最近更新 更多