10

I have a text column in mysql and it stores a date value in the format yyyy-mm-dd. Now, in my php page, I use this code to parse into a date value.

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

Now, I just read that strtotime() parses values only after January 1, 1970. I have lot of date values before that date. Is there a work around? I don't want to change my database structure.

Ctroy
  • 577
  • 1
  • 10
  • 20

7 Answers7

13

From the documentation for strtotime():

strtotime() has a range limit between Fri, 13 Dec 1901 20:45:54 GMT and Tue, 19 Jan 2038 03:14:07 GMT; although prior to PHP 5.1.0 this range was limited from 01-01-1970 to 19-01-2038 on some operating systems (Windows).

What version of PHP are you running? And on what platform? Perhaps it's time for an upgrade.

If you're working with dates outside the 13 Dec 1901 to 19 Jan 2038 range, then consider using PHP's DateTime objects which can work with a much wider range of dates.

Procedural:

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

OOP:

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

echo $date->format("F j, Y");
Amal Murali
  • 75,622
  • 18
  • 128
  • 150
Mark Baker
  • 209,507
  • 32
  • 346
  • 385
  • Thanks - I'm using the Apache Solr search engine, so using the mysql date_format function is not an option as all dates need to be indexed in YYYY-MM-DDTHH-MM-SSZ format. This must then be parsed using PHP (I'm using the PHP api to retrieve search results), DateTime was the ticket. edit: this could be an answer for others running into this issue with Apache Solr: http://wiki.apache.org/solr/DataImportHandler#DateFormatTransformer – johnny_bgoode Apr 06 '11 at 02:57
  • @Mark: I have php5.2.6, strtotime still shows blank of date prior to 1970. Where did you see "prior to 5.1.0..." thing? – Scott Chu Oct 22 '14 at 07:37
  • @ScottChu - A timestamp is a signed integer; negative values are used for seconds prior to 1970-01-01 00:00:00 GMT, and have been on all platforms since 5.1.0..... reference to this is in the Notes section on the [docs](http://www.php.net/manual/en/function.strtotime.php) page (note 2) – Mark Baker Oct 22 '14 at 07:38
  • @Mark: Thanks! I just miss the Notes part. – Scott Chu Oct 22 '14 at 07:45
1

you should use a date columnn, not text one.
and date_format() SQL function to format date in the query

Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
  • I can't change the column type. I have several values in a text column and some of these are dates (in the format yyyy-mm-dd). There is also another column which specifies if the row contains a date value or a text value. – Ctroy May 20 '10 at 05:57
  • 1
    In that case, you need to redesign your database. – Jacco May 20 '10 at 06:15
  • Are you saying there is no work around to this problem, without redesigning the database? I just want to convert a text of format yyyy-mm-dd to date format F j, Y. Eg: 1820-05-20 to May 20, 1820. – Ctroy May 20 '10 at 06:31
  • 2
    there is no problem at all for the date. And the solution I had written. Bot for the whole your database, you already ruined it, if you have data of different kind in one column. There is no solution and it will lead you straight to disaster – Your Common Sense May 20 '10 at 06:48
1
$date = DateTime::createFromFormat('d M Y','17 Jan 1900');
echo $date->format('Y-m-d');
katamaraju
  • 33
  • 6
1

Just to update this for modern times, PHP7 strtotime() on a 64 bit system can handle virtually any AD date, although for some reason the man page still says 1970.

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

Result:

Stamp: -15076350000
04/01/1492

And

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

Result

Stamp: 93142933200
08/01/4921
Danial
  • 1,496
  • 14
  • 15
  • This does not seem to work for me although I'm using PHP7.1.10 or are you saying this will always change any date before 1970 to 1970? – Wanjia Oct 12 '18 at 08:32
  • What OS are you on? Is it a 64 bit OS? It works on Linux, FreeBSD and OSX. strtotime() generates a negative date for dates before 1970. To go beyond 65 years, you need a 64 bit version. – Danial Oct 12 '18 at 17:11
  • Windows 10 64 bit, when I copy your code it only shows "stamp:" – Wanjia Oct 12 '18 at 17:46
  • Sounds like strtotime is returning false? Would we be surprised if windows is 5 years behind the times? Sorry but I don't have php on a windows system so i can't test it. – Danial Oct 12 '18 at 19:13
  • Found this https://stackoverflow.com/a/10924871/4220457 to be very useful as I can't figure out why it's not working – Wanjia Oct 14 '18 at 21:39
  • Perhaps if you're stuck on windows. As I've pointed out, it works in most modern operating system implementations. My servers run Apache on unix so I have no need for Windows workarounds. There's no reason that timestamps should overflow at the 32-bit boundry. At Y2K time, just about all OSes were 32 bit, so that was a big issue. Now they're not, and I'm sure microsoft will catch up eventually. In a 64-bit OS, strtotime would have to return a short int, which it shouldn't. The native integer is 64 bits on a 64 bit system. – Danial Oct 18 '18 at 22:14
1
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
}
Gombo
  • 708
  • 2
  • 10
  • 20
  • 1
    strtotime returns a timestamp, your function returns an ISO 8601 date. This is an extremely important difference! – Andrew Aug 17 '12 at 12:26
  • indeed you're right. However what @Ctroy is asking is a way to have an ISO 8601 date, so I guess my imprecision could be forgiven! – Gombo Sep 30 '12 at 12:24
0

I'm a noob, and was having some similar issues regarding the use of strtotime vs explode. I ran across this thread and was greatly helped by the comments on the change in date limit by Mark Baker (thanks!). So I wrote this code just to play with the concept. Perhaps it will help other noobs such as myself.

Just change the date on the top PHP line and see what happens to the dates below - very interesting. Thanks again!

<?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>
TimSPQR
  • 2,964
  • 3
  • 20
  • 29
0

I have a Sql database dealing with when each state within the U.S. was founded, going back to 1787. This field is set DATE within the database, in the YYYY-MM-DD format (ex. 1787-12-07). I tried many methods but the most simple and effective I found was: (the exact clip of code I use. change the information & variables as you need.)

    <?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>"; } ?>

The output for the first 2 rows is:

Delaware Friday December 07, 1787

Pennsylvania Wednesday December 12, 1787

FatPurple
  • 1
  • 1
  • 2
    Thanks for the answer, but could you please remove all the boilerplate code that is not related to the solution to the question? For example, all the HTML part is irrelevant to the solution. If the answer is related to PHP's `date_create` function, you can always add a link to this function's documentation, or explain why it works (by the way, I don't know if your solution works, I didn't check). Just a few suggestions to make your answer more useful ;) – Óscar Gómez Alcañiz Mar 06 '20 at 20:23
  • I add the entire clip of code to give it context. Plus, the date that I am converting is declared variable within a while statement. To understand where the date came from, I showed the selection from the database. Too many answers on here don't give the background to HOW they got their solution. I just included the HOW. – FatPurple Mar 06 '20 at 20:33