La clase DateTime

(PHP 5 >= 5.2.0, PHP 7, PHP 8)

Introducción

Representación de la fecha y la hora.

Sinopsis de la Clase

class DateTime implements DateTimeInterface {
/* Constantaes heredadas constants */
const string DateTimeInterface::ATOM = "Y-m-d\TH:i:sP";
const string DateTimeInterface::COOKIE = "l, d-M-Y H:i:s T";
const string DateTimeInterface::ISO8601 = "Y-m-d\TH:i:sO";
const string DateTimeInterface::RFC822 = "D, d M y H:i:s O";
const string DateTimeInterface::RFC850 = "l, d-M-y H:i:s T";
const string DateTimeInterface::RFC1036 = "D, d M y H:i:s O";
const string DateTimeInterface::RFC1123 = "D, d M Y H:i:s O";
const string DateTimeInterface::RFC2822 = "D, d M Y H:i:s O";
const string DateTimeInterface::RFC3339 = "Y-m-d\TH:i:sP";
const string DateTimeInterface::RFC3339_EXTENDED = "Y-m-d\TH:i:s.vP";
const string DateTimeInterface::RSS = "D, d M Y H:i:s O";
const string DateTimeInterface::W3C = "Y-m-d\TH:i:sP";
/* Métodos */
public __construct(string $time = "now", DateTimeZone $timezone = null)
public add(DateInterval $interval): DateTime
public static createFromFormat(string $format, string $time, DateTimeZone $timezone = ?): DateTime
public static createFromImmutable(DateTimeImmutable $object): static
public static getLastErrors(): array|false
public modify(string $modify): DateTime
public static __set_state(array $array): DateTime
public setDate(int $year, int $month, int $day): DateTime
public setISODate(int $year, int $week, int $day = 1): DateTime
public setTime(int $hour, int $minute, int $second = 0): DateTime
public setTimestamp(int $unixtimestamp): DateTime
public setTimezone(DateTimeZone $timezone): DateTime
public sub(DateInterval $interval): DateTime
public diff(DateTimeInterface $datetime2, bool $absolute = false): DateInterval
public format(string $format): string
public getOffset(): int
public getTimestamp(): int
public __wakeup()
}

Historial de cambios

Versión Descripción
7.2.0 Las constantes de clase de DateTime ahora están definidas en DateTimeInterface.
7.0.0 Constantes agregadas: DATE_RFC3339_EXTENDED y DateTime::RFC3339_EXTENDED.
5.5.0 La clase ahora implementa DateTimeInterface.
5.4.24 La constante COOKIE se cambió para reflejar el RFC 1036 usando un año de cuatro dígitos en lugar de un año de dos dígitos (RFC 850) como en versiones anteriores.
5.2.2 La comparación de un objeto DateTime con los operadores de comparación se cambió para que funcionara correctamente. Anteriormente, todos los objetos DateTime eran considerados iguales (usando ==).

Tabla de contenidos

add a note add a note

User Contributed Notes 26 notes

up
45
michael at smith-li dot com
8 years ago
DateTime supports microseconds since 5.2.2. This is mentioned in the documentation for the date function, but bears repeating here. You can create a DateTime with fractional seconds and retrieve that value using the 'u' format string.

<?php
// Instantiate a DateTime with microseconds.
$d = new DateTime('2011-01-01T15:03:01.012345Z');

// Output the microseconds.
echo $d->format('u'); // 012345

// Output the date with microseconds.
echo $d->format('Y-m-d\TH:i:s.u'); // 2011-01-01T15:03:01.012345
up
12
david dot p dot mclaughlin at gmail dot com
4 years ago
Example displaying each time format:

$dateTime = new DateTime();

foreach ([
   'ATOM',
   'COOKIE',
   'ISO8601',
   'RFC822',
   'RFC850',
   'RFC1036',
   'RFC1123',
   'RFC2822',
   'RFC3339',
   'RFC3339_EXTENDED',
   'RSS',
   'W3C',
   ] as $format) {
   eval("print 'DateTimeInterface::$format\t'.\$dateTime->format(DateTimeInterface::$format).\"\n\";");
}

The above example will output:

DateTimeInterface::ATOM    2020-01-28T16:22:37-07:00
DateTimeInterface::COOKIE    Tuesday, 28-Jan-2020 16:22:37 MST
DateTimeInterface::ISO8601    2020-01-28T16:22:37-0700
DateTimeInterface::RFC822    Tue, 28 Jan 20 16:22:37 -0700
DateTimeInterface::RFC850    Tuesday, 28-Jan-20 16:22:37 MST
DateTimeInterface::RFC1036    Tue, 28 Jan 20 16:22:37 -0700
DateTimeInterface::RFC1123    Tue, 28 Jan 2020 16:22:37 -0700
DateTimeInterface::RFC2822    Tue, 28 Jan 2020 16:22:37 -0700
DateTimeInterface::RFC3339    2020-01-28T16:22:37-07:00
DateTimeInterface::RFC3339_EXTENDED    2020-01-28T16:22:37.803-07:00
DateTimeInterface::RSS    Tue, 28 Jan 2020 16:22:37 -0700
DateTimeInterface::W3C    2020-01-28T16:22:37-07:00
up
46
gmblar+php at gmail dot com
14 years ago
Small but powerful extension to DateTime

<?php

class Blar_DateTime extends DateTime {

   
/**
     * Return Date in ISO8601 format
     *
     * @return String
     */
   
public function __toString() {
        return
$this->format('Y-m-d H:i');
    }

   
/**
     * Return difference between $this and $now
     *
     * @param Datetime|String $now
     * @return DateInterval
     */
   
public function diff($now = 'NOW') {
        if(!(
$now instanceOf DateTime)) {
           
$now = new DateTime($now);
        }
        return
parent::diff($now);
    }

   
/**
     * Return Age in Years
     *
     * @param Datetime|String $now
     * @return Integer
     */
   
public function getAge($now = 'NOW') {
        return
$this->diff($now)->format('%y');
    }

}

?>

Usage:

<?php

$birthday
= new Blar_DateTime('1879-03-14');

// Example 1
echo $birthday;
// Result: 1879-03-14 00:00

// Example 2
echo '<p>Albert Einstein would now be ', $birthday->getAge(), ' years old.</p>';
// Result: <p>Albert Einstein would now be 130 years old.</p>

// Example 3
echo '<p>Albert Einstein would now be ', $birthday->diff()->format('%y Years, %m Months, %d Days'), ' old.</p>';
// Result: <p>Albert Einstein would now be 130 Years, 10 Months, 10 Days old.</p>

// Example 4
echo '<p>Albert Einstein was on 2010-10-10 ', $birthday->getAge('2010-10-10'), ' years old.</p>';
// Result: <p>Albert Einstein was on 2010-10-10 131 years old.</p>

?>
up
38
tim at timfennis dot com
11 years ago
There is a subtle difference between the following two statments which causes JavaScript's Date object on iPhones to fail.

<?php
$objDateTime
= new DateTime('NOW');
echo
$objDateTime->format('c'); // ISO8601 formated datetime
echo $objDateTime->format(DateTime::ISO8601); // Another way to get an ISO8601 formatted string

/**
On my local machine this results in:

2013-03-01T16:15:09+01:00
2013-03-01T16:15:09+0100

Both of these strings are valid ISO8601 datetime strings, but the latter is not accepted by the constructor of JavaScript's date object on iPhone. (Possibly other browsers as well)
*/

?>

Our solution was to create the following constant on our DateHelper object.

<?php
class DateHelper
{
   
/**
     * An ISO8601 format string for PHP's date functions that's compatible with JavaScript's Date's constructor method
     * Example: 2013-04-12T16:40:00-04:00
     *
     * PHP's ISO8601 constant doesn't add the colon to the timezone offset which is required for iPhone
    **/
   
const ISO8601 = 'Y-m-d\TH:i:sP';
}
?>
up
16
Ray.Paseur sometimes uses Gmail
7 years ago
At PHP 7.1 the DateTime constructor incorporates microseconds when constructed from the current time.  Make your comparisons carefully, since two DateTime objects constructed one after another are now more likely to have different values.

http://php.net/manual/en/migration71.incompatible.php
up
17
stevenmattera at gmail dot com
10 years ago
This caused some confusion with a blog I was working on and just wanted to make other people aware of this. If you use createFromFormat to turn a date into a timestamp it will include the current time. For example:

<?php
$publishDate
= DateTime::createFromFormat('m/d/Y', '1/10/2014');
echo
$publishDate->getTimestamp();
?>

Would not output the expected "1389312000" instead it would output something more like "1389344025". To fix this you would want to do:

<?php
$publishDate
= DateTime::createFromFormat('m/d/Y', '1/10/2014');
$publishDate->setTime(0, 0, 0);
echo
$publishDate->getTimestamp();
?>

I hope this helps someone!
up
2
kim dot jangwook dot 1029 at gmail dot com
4 years ago
Set Timezone and formatting.

<?php

$unixTime
= time();
$timeZone = new \DateTimeZone('Asia/Tokyo');

$time = new \DateTime();
$time->setTimestamp($unixTime)->setTimezone($timeZone);

$formattedTime = $time->format('Y/m/d H:i:s');
echo
$formattedTime;

?>
up
10
divinity76+spam at gmail dot com
7 years ago
if you'd like to print all the built-in formats,

<?php
foreach((new ReflectionClass('DateTime'))->getConstants() as $name=>$format){
    echo
'DateTime::'.$name.' -> '.date($format).PHP_EOL;
}
up
16
nodweber at gmail dot com
13 years ago
IF You want to create clone of $time, use clone..

<?php
  $now  
= new DateTime;
 
$clone = $now;        //this doesnot clone so:
 
$clone->modify( '-1 day' );

  echo
$now->format( 'd-m-Y' ), "\n", $clone->format( 'd-m-Y' );
  echo
'----', "\n";

 
// will print same.. if you want to clone make like this:
 
$now   = new DateTime;
 
$clone = clone $now;   
 
$clone->modify( '-1 day' );
   
  echo
$now->format( 'd-m-Y' ), "\n", $clone->format( 'd-m-Y' );
?>

Results:
18-07-2011
18-07-2011
----
19-07-2011
18-07-2011
up
7
lulzim at orav dot net
7 years ago
This might be unexpected behavior:

<?php

$date1
= DateTime::createFromFormat('Y-m-d H:i:s', '2017-08-31 00:00:00');
$date1->modify('+1 month');

#or use the interval
#$date1->add(new DateInterval("P1M"));

#will produce 2017-10-1
#not 2017-09-30
up
10
bf at tbwb dot nl
14 years ago
If you have timezone information in the time string you construct the DateTime object with, you cannot add an extra timezone in the constructor. It will ignore the timezone information in the time string:

$date = new DateTime("2010-07-05T06:00:00Z", new DateTimeZone("Europe/Amsterdam"));

will create a DateTime object set to "2010-07-05 06:00:00+0200" (+2 being the TZ offset for Europe/Amsterdam)

To get this done, you will need to set the timezone separately:

$date = new DateTime("2010-07-05T06:00:00Z");
$date->setTimeZone(new DateTimeZone("Europe/Amsterdam");

This will create a DateTime object set to "2010-07-05 08:00:00+0200"
up
8
julie at earthshod dot co dot uk
10 years ago
It isn't obvious from the above, but you can insert a letter of the alphabet directly into the date string by escaping it with a backslash in the format string.  Note that if you are using "double" speech marks around the format string, you will have to further escape each backslash with another backslash!  If you are using 'single' speech marks around the format string, then you only need one backslash.

For instance, to create a string like "Y2014M01D29T1633", you *could* use string concatenation like so:

<?php
    $dtstring
= "Y" . date("Y", $when) . "M" . date("m", $when) . "D" . date("d", $when) . "T" . date("Hi", $when);
?>

but you could also escape the letters with backslashes like so:

<?php
    $dtstring1
= date('\YY\Mm\Dd\THi', $when);
   
$dtstring2 = date("\\YY\\Mm\\Dd\\THi", $when);
?>

This method involves fewer function calls, so probably is slightly quicker; and also is immune to race conditions if you are not specifying the second argument.  [It's possible that you could evaluate date("d") just *before* midnight and date("H") just *after* midnight.  This will not give you the result you were expecting.]
up
3
lucasfsmartins at gmail dot com
8 years ago
A good way I did to work with millisecond is transforming the time in milliseconds.

function timeToMilliseconds($time) {
    $dateTime = new DateTime($time);
   
    $seconds = 0;
    $seconds += $dateTime->format('H') * 3600;
    $seconds += $dateTime->format('i') * 60;
    $seconds += $dateTime->format('s');
   
    $seconds = floatval($seconds . '.' . $dateTime->format('u'));
   
    return $seconds * 1000;
}
up
3
jlh at gmx dot ch
8 years ago
Note that the ISO8601 constant will not correctly parse all possible ISO8601 compliant formats, as it does not support fractional seconds. If you need to be strictly compliant to that standard you will have to write your own format.

Bug report #51950 has unfortunately be closed as "not a bug" even though it's a clear violation of the ISO8601 standard.
up
2
giorgio dot liscio at email dot it
14 years ago
please note that using

setTimezone
setTimestamp
setDate
setTime
etc..

will modify the original object, and the return value is $this

$original = new DateTime("now");

$modified = $original->setTimezone(new DateTimezone("europe/rome"));

echo $original === $modified ? "THE OBJECT IS THE SAME" : "OBJECTS ARE DIFFERENT";

so a datetime object is mutable

(Editors note: PHP 5.5 adds DateTimeImmutable which does not modify the original object, instead creating a new instance.)
up
0
ph at jokerss dot com dot br
8 years ago
Create function to convert GregorianDate to JulianDayCount

<?php

function dateJulian($date) {
       
$dateTime = new DateTime($date);
       
$limitDate = new DateTime('01-03-'.$dateTime->format('Y'));
       
$diff = $dateTime->diff($limitDate);
       
$soma = 1;
        if (
$dateTime->format('L') && $diff->invert) {
               
$soma = 2;
        }
        return ( (int)
$dateTime->format('z')) + $soma;
}

echo
PHP_EOL,dateJulian('01-03-2015'), PHP_EOL;
echo
PHP_EOL,dateJulian('01-03-2016'), PHP_EOL;

/**
  * returns
  * 60
  * 61
  */

?>
up
-1
James
11 years ago
Be aware that DateTime may ignore fractional seconds for some formats, but not when using the ISO 8601 time format, as documented by this bug:

https://bugs.php.net/bug.php?id=51950

$dateTime = DateTime::createFromFormat(
    DateTime::ISO8601,
    '2009-04-16T12:07:23.596Z'
);
// bool(false)
up
-1
ivijan dot stefan at gmail dot com
4 years ago
Here is easiest way to find the days difference between two dates:

<?php
if(!function_exists('date_between')) :
    function
date_between($date_start, $date_end)
    {
        if(!
$date_start || !$date_end) return 0;
       
        if(
class_exists('DateTime') )
        {
           
$date_start    = new DateTime( $date_start );
           
$date_end    = new DateTime( $date_end );
            return
$date_end->diff($date_start)->format('%a');
        }
        else
        {           
            return
abs( round( ( strtotime($date_start) - strtotime($date_end) ) / 86400 ) );
        }
    }
endif;
?>

In the general, I use 'DateTime' to find days between 2 dates. But if in the some reason, some server setup not have 'DateTime' enabled, it will use simple (but not safe) calculation with 'strtotime()'.
up
-2
anthony at teamug dot net
9 years ago
This is a great class, but unless you need to use it's more advanced features, I would stick to passing times around your scripts as Unix Time Stamps - maybe prefixing with "uts".
Otherwise you will simply be creating more lines of code with no benefit.
up
-2
ryan at amst dot com
9 years ago
It seems like, due to changes in the DateTimeZone class in PHP 5.5, when creating a date and specifying the timezone as a a string like 'EDT', then getting the timezone from the date object and trying to use that to set the timezone on a date object you will have problems but never know it.  Take the following code:

<?php
$date
= new DateTime('2015-08-21 15:00:00 EDT') ;
$tz_string = $date->getTimezone()->getName() ;
$tz = new DateTimeZone($tz_string) ;
$date->setTimezone($tz) ;
?>

You would think this code should not change $date at all, but it does.  It seems like you can create a timezone object like 'EDT' but can't use those to set timezones properly.  The process, however does act like it's working without errors.
up
-4
ccbsschucko at gmail dot com
6 years ago
<?php
   
// PHP >= 7

   
class DatetimeTool {

       
/**
        * @param str => $formato_final = formato de saída
        */
       
public function now(string $formato_final = 'Y-m-d H:i:s'){
            return (new
DateTime('now'))->format($formato_final);
        }

       
/**
        * @param str => $data = data a ser formatada
        * @param str => $formato_final = formato de saída
        */
       
public function format(string $data, string $formato_final){
            return (new
DateTime($data))->format($formato_final);
        }

       
       
/**
        * @param str => $data_inicio = data de inicio que recebe o acréscimo
        * @param arr => $add = valores adicionados [ano,mes,dia,hora,minuto,segundo]
        * @param str => $formato_final = formato de saída
        */
       
public function add(string $data_inicio, array $add = [0,0,0,0,0,0], string $formato_final){
            return (new
DateTime($data_inicio))->add(new DateInterval('P'.$add[0].'Y'.$add[1].'M'.$add[2].'DT'.$add[3].'H'.$add[4].'M'.$add[5].'S'))->format($formato_final);
        }

       
/**
        * @param str => $data_inicio = data de inicio que recebe o decréscimo
        * @param arr => $add = valores adicionados [ano,mes,dia,hora,minuto,segundo]
        * @param str => $formato_final = formato de saída
        */
       
public function sub(string $data_inicio, array $add = [0,0,0,0,0,0], string $formato_final){
            return (new
DateTime($data_inicio))->sub(new DateInterval('P'.$add[0].'Y'.$add[1].'M'.$add[2].'DT'.$add[3].'H'.$add[4].'M'.$add[5].'S'))->format($formato_final);
        }

    }
?>

<?php
    var_dump
((new DatetimeTool)->now('d-m-Y'));

   
var_dump((new DatetimeTool)->format('1970-01-01', 'd-m-Y'));

   
var_dump((new DatetimeTool)->add(date('d-m-Y H:i:s'), [0,1,0,0,10,0], 'd-m-Y'));

   
var_dump((new DatetimeTool)->sub(date('d-m-Y H:i:s'), [0,1,0,0,10,0], 'd-m-Y'));

?>
up
-5
tdp
9 years ago
Be aware of this behaviour:

<?php
$dt1
= new \DateTime( '2014/12/31' );
$dt1->modify( '-1 month' );
$m = (int) $dt1->format( 'm' );
var_dump( $m ); // still 12 !!!

$dt2 = new \DateTime( '2014/12/30' );
$dt2->modify( '-1 month' );
$m = (int) $dt2->format( 'm' );
var_dump( $m ); // 11
?>

The method modify( '-1 month' ) appear to remove 30 days, not to subtract 1 from the month and adjust the day (if needed).

In my opinion, the former date should be adjusted to 2014/11/30, that is, the last day in the previous month.
up
-11
tom at r dot je
15 years ago
If you're stuck on a PHP 5.1 system (unfortunately one of my clients is on a rather horrible webhost who claims they cannot upgrade php) you can use this as a quick workaround:

<?php
if (!class_exists('DateTime')) {
class
DateTime {
    public
$date;
   
    public function
__construct($date) {
       
$this->date = strtotime($date);
    }
   
    public function
setTimeZone($timezone) {
        return;
    }
   
    private function
__getDate() {
        return
date(DATE_ATOM, $this->date);   
    }
   
    public function
modify($multiplier) {
       
$this->date = strtotime($this->__getDate() . ' ' . $multiplier);
    }
   
    public function
format($format) {
        return
date($format, $this->date);
    }
}
}
?>

it is NOT perfect. Timezones and DST are not supported, but if you just need compatible basic functions this works. Feel free to complete this so it's compatible with the 5.2 datetime object.
up
-2
j dot vd dot merwe at enovision dot net
5 years ago
When given 2 variables and you want to change the date of the first variable but not the time, it can be done like this:

<?php
// First date is today
$dateOne = new DateTime();

// Second date is some date
$dateTwo = new DateTime('14-10-1963');

echo
'Date one before change: ' . $dateOne->format('Y-m-d H:i:s');
echo
'<br/>';
echo
'Date two: ' . $dateTwo->format('Y-m-d H:i:s');

// Now modify the date of variable $dateOne with the date of $dateTwo
$dateOne->modify($dateTwo->format('Y-m-d'));
       
echo
'<br/>';
echo
'Date one after change: ' . $dateOne->format('Y-m-d H:i:s');
?>

Outputs:

Date one before change: 2019-08-07 09:32:44
Date two: 1963-10-14 00:00:00
Date one after change: 1963-10-14 09:32:44
up
-16
ediathome
14 years ago
If you need DateTime::createFromFormat functionality in versions <5.3.0 releases you might use the following basic class which can also be combined with Tom's class. It should work for most basic formats, however you should improve this function if you need more complex formats.

<?php
class DateClass extends DateTime{

public function
getTimestamp(){
    return
$this->format ("U");
}

/**
*    This function calculates the number of days between the first and the second date. Arguments must be subclasses of DateTime
**/
static function differenceInDays ($firstDate, $secondDate){
   
$firstDateTimeStamp = $firstDate->format("U");
   
$secondDateTimeStamp = $secondDate->format("U");
   
$rv = round ((($firstDateTimeStamp - $secondDateTimeStamp))/86400);
    return
$rv;
}

/**
* This function returns an object of DateClass from $time in format $format. See date() for possible values for $format
**/
static function createFromFormat ($format, $time){
   
assert ($format!="");
    if(
$time==""){
        return new
DateClass();
    }

   
$regexpArray['Y'] = "(?P<Y>19|20\d\d)";       
   
$regexpArray['m'] = "(?P<m>0[1-9]|1[012])";
   
$regexpArray['d'] = "(?P<d>0[1-9]|[12][0-9]|3[01])";
   
$regexpArray['-'] = "[-]";
   
$regexpArray['.'] = "[\. /.]";
   
$regexpArray[':'] = "[:]";           
   
$regexpArray['space'] = "[\s]";
   
$regexpArray['H'] = "(?P<H>0[0-9]|1[0-9]|2[0-3])";
   
$regexpArray['i'] = "(?P<i>[0-5][0-9])";
   
$regexpArray['s'] = "(?P<s>[0-5][0-9])";

   
$formatArray = str_split ($format);
   
$regex = "";

   
// create the regular expression
   
foreach($formatArray as $character){
        if (
$character==" ") $regex = $regex.$regexpArray['space'];
        elseif (
array_key_exists($character, $regexpArray)) $regex = $regex.$regexpArray[$character];
    }
   
$regex = "/".$regex."/";

   
// get results for regualar expression
   
preg_match ($regex, $time, $result);

   
// create the init string for the new DateTime
   
$initString = $result['Y']."-".$result['m']."-".$result['d'];

// if no value for hours, minutes and seconds was found add 00:00:00
   
if (isset($result['H'])) $initString = $initString." ".$result['H'].":".$result['i'].":".$result['s'];
    else {
$initString = $initString." 00:00:00";}

   
$newDate = new DateClass ($initString);
    return
$newDate;
    }   
}

?>
up
-22
marcio dot barbado at bdslabs dot com dot br
12 years ago
DateTime class does not use locales so here I test and compare its formating with strftime() function's one:

    <?php
     
// Under UNIX, command "$ locale -a" should provide you with your server's options.

     
$data_do_mysql            = "2011-09-29 23:50:26";

      echo
'<strong>' . "\$data_do_mysql" . '</strong>' . ":" . $data_do_mysql . "." . '<br />' .
          
'<br />';

     
$dataInicial            = new DateTime(trim($data_do_mysql));

     
// setlocale() used with strftime().
     
$meu_locale            = setlocale(LC_ALL, "pt_BR.utf8");
     
$data_inicial            = strftime("%d de %b de %Y", strtotime(trim($data_do_mysql)));

     
// Outputs:
      // $data_do_mysql formatada com a classe DateTime:29-Sep-2011.
     
echo '<strong>' . "\$data_do_mysql" . '</strong>' . " formatada com a classe DateTime:" . $dataInicial->format('d-M-Y') . "." . '<br />' .
          
'<br />';

     
// Outputs:
      // $data_do_mysql formatada com a função strftime():29 de Set de 2011.
     
echo '<strong>' . "\$data_do_mysql" . '</strong>' . " formatada com a fun&ccedil;&atilde;o strftime():" . $data_inicial . "." . '<br />' .
          
'<br />';

     
// setlocale() fails :-(
     
if (!$meu_locale)
        {
            echo
"Prefiro usar DateTime.";
        }

     
// Yay setlocale() :-D
     
else
        {
            echo
"Prefiro usar strftime().";
        }

      exit();
   
?>
To Top