• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • DateTime::__construct()

    date_create

    (PHP 5 >= 5.2.0, PHP 7)

    返回一个新的 DateTime 对象

    说明

    面向对象风格

    publicDateTime::__construct([string $time="now"[,DateTimeZone$timezone=NULL]])
    过程化风格
    date_create([string $time="now"[,DateTimeZone$timezone=NULL]]): DateTime

    返回一个新的 DateTime 对象。

    参数

    $time

    日期/时间字符串。正确格式的说明详见日期与时间格式。

    如果这个参数为字符串"now"表示获取当前时间。如果同时指定了$timezone参数,那么获取指定时区的当前时间。

    $timezone

    DateTimeZone对象,表示要获取哪个时区的$time

    如果省略了$timezone参数,那么会使用当前时区。

    Note:

    $time参数是 UNIX 时间戳(例如@946684800),或者已经包含时区信息(例如2010-01-28T15:00:00+02:00)的时候,$timezone参数和当前时区都将被忽略。

    返回值

    返回一个新的 DateTime 对象实例,或者在发生错误的时候返回过程化风格在失败时返回FALSE。。

    错误/异常

    如果发生错误,会抛出Exception。

    更新日志

    版本说明
    7.1微秒部分不再是'00000'了,而是真实的微秒数据。
    5.3.0如果$time参数不是一个有效的日期/时间格式,会抛出异常。在之前的版本中是会发出一个错误。

    范例

    Example #1DateTime::__construct()例程

    面向对象风格

    <?php
    try {
        $date = new DateTime('2000-01-01');
    } catch (Exception $e) {
        echo $e->getMessage();
        exit(1);
    }
    echo $date->format('Y-m-d');
    ?>
    

    过程化风格

    <?php
    $date = date_create('2000-01-01');
    if (!$date) {
        $e = date_get_last_errors();
        foreach ($e['errors'] as $error) {
            echo "$error\n";
        }
        exit(1);
    }
    echo date_format($date, 'Y-m-d');
    ?>
    

    以上例程会输出:

    2000-01-01
    

    Example #2DateTime::__construct()的复杂用法

    <?php
    // 指定时间,但是使用电脑的时区
    $date = new DateTime('2000-01-01');
    echo $date->format('Y-m-d H:i:sP') . "\n";
    // 指定时间和时区
    $date = new DateTime('2000-01-01', new DateTimeZone('Pacific/Nauru'));
    echo $date->format('Y-m-d H:i:sP') . "\n";
    // 使用当前时间以及电脑的时区
    $date = new DateTime();
    echo $date->format('Y-m-d H:i:sP') . "\n";
    // 使用当前时间和指定的时区
    $date = new DateTime(null, new DateTimeZone('Pacific/Nauru'));
    echo $date->format('Y-m-d H:i:sP') . "\n";
    // 使用 UNIX 时间戳作为时间,请注意这里的生成的 DateTime 对象对应的是 UTC 时区
    $date = new DateTime('@946684800');
    echo $date->format('Y-m-d H:i:sP') . "\n";
    // 指定一个无效的时间,会自动对应到有效的时间
    $date = new DateTime('2000-02-30');
    echo $date->format('Y-m-d H:i:sP') . "\n";
    ?>
    

    以上例程的输出类似于:

    2000-01-01 00:00:00-05:00
    2000-01-01 00:00:00+12:00
    2010-04-24 10:24:16-04:00
    2010-04-25 02:24:16+12:00
    2000-01-01 00:00:00+00:00
    2000-03-01 00:00:00-05:00
    

    参见

    • DateTime::createFromFormat() 根据给定的格式解析日期时间字符串
    • DateTimeZone::__construct() 创建新的DateTimeZone对象
    • 日期时间格式
    • date.timezoneini 设置
    • date_default_timezone_set() 设定用于一个脚本中所有日期时间函数的默认时区
    • DateTime::getLastErrors() 获取警告和错误信息
    • checkdate() 验证一个格里高里日期
    There's a reason for ignoring the time zone when you pass a timestamp to __construct. That is, UNIX timestamps are by definition based on UTC. @1234567890 represents the same date/time regardless of time zone. So there's no need for a time zone at all.
    The theoretical limits of the date range seem to be "-9999-01-01" through "9999-12-31" (PHP 5.2.9 on Windows Vista 64):
    <?php
    $d = new DateTime("9999-12-31"); 
    $d->format("Y-m-d"); // "9999-12-31"
    $d = new DateTime("0000-12-31"); 
    $d->format("Y-m-d"); // "0000-12-31"
    $d = new DateTime("-9999-12-31"); 
    $d->format("Y-m-d"); // "-9999-12-31"
    ?>
    Dates above 10000 and below -10000 do not throw errors but produce weird results:
    <?php
    $d = new DateTime("10019-01-01"); 
    $d->format("Y-m-d"); // "2009-01-01"
    $d = new DateTime("10009-01-01"); 
    $d->format("Y-m-d"); // "2009-01-01"
    $d = new DateTime("-10019-01-01"); 
    $d->format("Y-m-d"); // "2009-01-01"
    ?>
    
    Note that the DateTime ctor also accepts boolean false and empty strings, and treats them the same as NULL (i.e. result is current date and time). This may lead to unexpected results if you forward function return values without explicitly checking them first.
    Empty arrays and boolean true trigger PHP warnings OTOH.
    (checked with PHP 5.5.18)
    It is worth noting:
    If you have not setup a default timezone, an Exception (or error if PHP < 5.3.0) will be thrown even when the $time parameter of the constructor includes a timezone or is a UNIX timestamp.
    At least for me, this was unexpected considering that the $timezone parameter is ignored in the cases when "the $time parameter either is a UNIX timestamp (e.g. @946684800) or specifies a timezone (e.g. 2010-01-28T15:00:00+02:00)."
    If time cannot be parsed an exception of type Exception is thrown which can be caught, however an E_WARNING is emitted as well. This might be confusing if you are converting warnings to exceptions in your error or shutdown handler.
    <?php
    try {
      $var = new DateTime('some invalid date format');
    }
    catch (Exception $ex) {}
    $warning = error_get_last(); // will contain warning info
    ?>
    
    A definite "gotcha" (while documented) that exists in the __construct is that it ignores your timezone if the $time is a timestamp. While this may not make sense, the object does provide you with methods to work around it.
    <?php
    // New Timezone Object
    $timezone = new DateTimeZone('America/New_York');
    // New DateTime Object
    $date = new DateTime('@1306123200', $timezone);  
    // You would expect the date to be 2011-05-23 00:00:00
    // But it actually outputs 2011-05-23 04:00:00
    echo $date->format('Y-m-d H:i:s');
    // You can still set the timezone though like so...    
    $date->setTimezone($timezone);
    // This will now output 2011-05-23 00:00:00
    echo $date->format('Y-m-d H:i:s');
    ?>
    
    Also forgot to mention, that MySQL "zeroed" dates do not throw an error but produce a non-sensical date:
    <?php
    $d = new DateTime("0000-00-00");
    $d->format("Y-m-d"); // "-0001-11-30"
    ?>
    Another good reason to write your own class that extends from DateTime.
    About constructing a DateTime, instead of just using the year it seems working when date matches the pattern "YYYY-MM"
    - Returns the year correctly: "YYYY-MM"
    $ cat date.php 
    <?php
    $date = new DateTime('2015-12');
    echo($date->format('Y'));
    ?>
    $ php date.php 
    2015
    - Ignores the given input and returns the year from NOW: "YYYY"
    $ cat date.php 
    <?php
    $date = new DateTime('2015');
    echo($date->format('Y'));
    ?>
    $ php date.php 
    2019
    RESULTS/SCOPE: 
    - Linux (May 24, 2019)
    - PHP 7.2.17 (cli)
    <?php
    $timestampNow = time();
    $timestamp = $timestampNow + 13;
    $datetime = new \DateTime("@{$timestamp}", new \DateTimeZone('Europe/Berlin'));
    echo $datetime->getTimezone() >getName(); // +00:00 !!!!
    ?>
    Does NOT work. You get UTC always.
    See comment http://php.net/manual/en/datetime.construct.php#106979
    use relative format instead:
    <?php
    $sec = 13;
    $datetime = new \DateTime("now + {$sec} sec", new \DateTimeZone('Europe/Berlin'));
    echo $datetime->getTimezone() >getName(); // Europe/Berlin
    ?>
    see http://php.net/manual/en/datetime.formats.relative.php
    Since PHP 7.1 behavior of this constructor without arguments have changed. 
    From now on microseconds are filled with actual value. In versions <=7.0 microseconds ware set to '000000'
    I'm surprised this hasn't been mentioned, but when constructing a DateTime with just the year as a string, DateTime will pre-initialize itself with NOW and then replace the year, so if today is 7/12/2016:
     <?php
    print((new DateTime('2015'))->modify('+1 day')->format('Y-m-d'));
    ?> 
    results in 2016-07-13
    Using this in a try catch to verify a string is in a valid date format is unreliable. Single letter strings used for the first argument (time string) of the constructor allows a new instance of the class to be created, without any exception or error.
    So the below code would not fail or throw an exception. So $time would not be an empty string.
    $value = 'y';
    try {
       $time = new \DateTimeZone($value);
    } catch (\Exception $e) {
        $time = '';
    }
    Be careful working with MySQL dates representing point of transition to Daylight Saving Time.
    The constructor of DateTime will convert timezone abbreviation to DST but not the time.
    <?php
    $timeZone = new DateTimeZone('Europe/Sofia');
          
    $transitionToDst = '2014-03-30 03:00:00';
    $date = new DateTime($transitionToDst, $timeZone);
    // Outputs: Sun Mar 30, 2014 3:00:00 EEST
    // Correct: Sun Mar 30, 2014 4:00:00 EEST 
    echo $date->format('D M j, Y G:i:s T') . '<br>';
    // Explicitly setting timezone or adding one second fixes this
    $cloneForAdding = clone $date;
    $date->setTimezone($timeZone);
    // Outputs: Sun Mar 30, 2014 4:00:00 EEST 
    echo $date->format('D M j, Y G:i:s T') . '<br>';
    $cloneForAdding->add(new DateInterval('PT1S'));
    // Outputs: Sun Mar 30, 2014 4:00:01 EEST
    echo $cloneForAdding->format('D M j, Y G:i:s T');
    ?>
    
    Although this function throws an exception on invalid $time values (empty strings, for example), the exception can't be caught because it's a fatal exception. Use functions such as checkdate() and strtotime() to validate the string first. should be changed to remove the try/catch block, since it's misleading.
    "The $timezone parameter and the current timezone are ignored when the $time parameter […] is a UNIX timestamp."
    Watch out – this means that these two are NOT equivalent, they result in different timezones (unless your current timezone is GMT):
    <?php
    $d = new DateTime(); $d->setTimestamp($t);
    echo $o->format('O');
    // +0200
    $d = new DateTime('@' . $t);
    echo $o->format('O');
    // +0000
    ?>
    
    When passing a non US or SQL date string the date will be formatted incorrectly.
    // UK date d/m/Y.
    $date_time = "08/03/2016 00:00:00";
    $dt = new DateTime($date_time, new DateTimeZone("Europe/London"));
    // Gives 2016-08-03
    echo $dt->format("Y-m-d");
    Impossible times due to daylight savings are handled by this function in a way similar to impossible dates, with the difference that this is not an error (i.e. a consequent call to DateTime::getLastError() yields nothing).
    For example:
    In the timezone "Europe/Berlin" on Sunday, March 30 2014 there was no 02:30 am, because that our is being skipped due to daylight savings on that day.
    <?php
    $tz = new DateTimeZone("Europe/Berlin");
    $impossible_time = "2014-03-30T02:30:00";
    $date = new DateTime($impossible_time, $tz);
    var_dump($date->getLastErrors());
    echo "The impossible time '$impossible_time' is interpreted as: " . $date->format(DateTime::ISO8601) . "\n";
    /*
    Yields:
    array(4) {
     'warning_count' =>
     int(0)
     'warnings' =>
     array(0) {
     }
     'error_count' =>
     int(0)
     'errors' =>
     array(0) {
     }
    }
    The impossible time '2014-03-30T02:30:00' is interpreted as: 2014-03-30T03:30:00+0200
    */
    ?>
    That is similar to how, for example, Febuary 29, 2014 would be handled, which would be interpreted as March 1, 2014. The difference is, that with the date that would be an error, with the time it is not.
    Ambigous times due to daylight savings are handled as the second possibility. For example the time 2:30 am occurred twice on October 26, 2014 in the timezone "Europe/Berlin".
    <?php
    $tz = new DateTimeZone("Europe/Berlin");
    $ambiguous_time = "2014-10-26T02:30:00";
    $date = new DateTime($ambiguous_time, $tz);
    echo "The ambiguous time '$ambiguous_time' is interpreted as: " . $date->format(DateTime::ISO8601) . "\n";
    /*
    Yields:
    The ambiguous time '2014-10-26T02:30:00' is interpreted as: 2014-10-26T02:30:00+0100
    */
    ?>
    Note that "2014-10-26T02:30:00+0200", one hour earlier, would be a correct answer as well.
    This seems to work as expected, at least now:
    <?php
    $timezone1 = new \DateTimeZone('Europe/Sofia');
    $timezone2 = new \DateTimeZone('UTC');
    $sometime1 = '2014-03-30 02:59:59';
    $sometime2 = '2014-03-30 03:00:00';
    $date1 = new \DateTime($sometime1, $timezone1);
    $date2 = new \DateTime($sometime2, $timezone1);
    echo $date1->format('D M j, Y G:i:s T') . '<br>';
    echo $date2->format('D M j, Y G:i:s T') . '<br>';
    $date1->setTimezone($timezone1);
    $date2->setTimezone($timezone1);
    echo $date1->format('D M j, Y G:i:s T') . '<br>';
    echo $date2->format('D M j, Y G:i:s T') . '<br>';
    $date1->setTimezone($timezone2);
    $date2->setTimezone($timezone2);
    echo $date1->format('D M j, Y G:i:s T') . '<br>';
    echo $date2->format('D M j, Y G:i:s T') . '<br>';
    This outputs:
    Sun Mar 30, 2014 2:59:59 EET
    Sun Mar 30, 2014 4:00:00 EEST
    Sun Mar 30, 2014 2:59:59 EET
    Sun Mar 30, 2014 4:00:00 EEST
    Sun Mar 30, 2014 0:59:59 UTC
    Sun Mar 30, 2014 1:00:00 UTC