3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[PHP] MySQLをつかったDateTimeの補完

Last updated at Posted at 2015-04-27

動機

PHPのDateTime型において、1ヶ月の加減算は仕様により都合がわるい。
DateTime::add
DateTime::sub

test_add.php
<?php
$datetime = new DateTime('2015-03-31');
var_dump($datetime);

$datetime->add(new DateInterval('P1M'));
var_dump($datetime);

$ php test_add.php
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2015-03-31 00:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(10) "Asia/Tokyo"
}
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2015-05-01 00:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(10) "Asia/Tokyo"
}

3/31の1ヶ月後は4/30になってほしい

test_sub.php
<?php
$datetime = new DateTime('2015-03-31');
var_dump($datetime);

$datetime->sub(new DateInterval('P1M'));
var_dump($datetime);
$ php test_sub.php
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2015-03-31 00:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(10) "Asia/Tokyo"
}
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2015-03-03 00:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(10) "Asia/Tokyo"
}

3/31の1ヶ月前は2/28になってほしい

そこで、大変野蛮なやり方であるが、MySQLくんの力を借りてみる試験を行った。

MyDateTime.class.php
<?php
class MyDateTime
{
    private static $_dbh;
    private static $_datetime;

    private static $_dbInfo = array(
        'dbhost'  => 'dbhost',
        'dbuser'  => 'dbuser',
        'dbpass'  => 'dbpass',
        'dbname'  => '',
        'charset' => 'utf8',
        'driver'  => 'mysql',
        'dbport'  => '1234',
    );


    /**
     * create instance guard
     *
     * @return void
     */
    private function __construct(){}


    /**
     * func doc comment
     *
     * @return void
     */
    public static function create($_string='')
    {
        self::_init($_string);
        return self::$_datetime;
    }


    /**
     * https://dev.mysql.com/doc/refman/5.6/en/date-and-time-functions.html#function_date-add
     *
     * @return void
     */
    public static function add($_string='')
    {
        if (! empty($_string)) {
            $query = "SELECT DATE_ADD('".self::$_datetime->format('Y-m-d H:i:s')."', INTERVAL ".$_string.") AS datetime";
            return self::_addsub($query);
        }
    }


    /**
     * https://dev.mysql.com/doc/refman/5.6/en/date-and-time-functions.html#function_date-add
     *
     * @return void
     */
    public static function sub($_string='')
    {
        if (! empty($_string)) {
            $query = "SELECT DATE_SUB('".self::$_datetime->format('Y-m-d H:i:s')."', INTERVAL ".$_string.") AS datetime";
            return self::_addsub($query);
        }
    }


    /**
     * func doc comment
     *
     * @return void
     */
    private static function _addsub($query)
    {
        $rslt = self::$_dbh->query($query);
        $row = $rslt->fetch_assoc();
        $rslt->close();
        return DateTime::createFromFormat('Y-m-d H:i:s', $row['datetime']);
    }


    /**
     * function doc comment
     *
     * @return void
     */
    private static function _connect()
    {
        if (self::$_dbh === null) {
            self::$_dbh = new mysqli(
                self::$_dbInfo['dbhost'],
                self::$_dbInfo['dbuser'],
                self::$_dbInfo['dbpass'],
                self::$_dbInfo['dbname']
            );
            self::$_dbh->set_charset(self::$_dbInfo['charset']);
        }
    }


    /**
     * func doc comment
     *
     * @return void
     */
    private static function _init($_string)
    {
        self::_connect();

        if (empty($_string)) {
            $query = "SELECT NOW() AS datetime";
        } else {
            $query = "SELECT DATE_FORMAT('".$_string."', '%Y-%m-%d %H:%i:%s') AS datetime";
        }

        $rslt = self::$_dbh->query($query);
        $row  = $rslt->fetch_assoc();
        $rslt->close();

        self::$_datetime = DateTime::createFromFormat('Y-m-d H:i:s', $row['datetime']);
    }
}

test.php
<?php
require_once 'MyDateTime.class.php';

// 指定なし
$datetime = MyDateTime::create();
var_dump($datetime);

// 指定あり
$datetime = MyDateTime::create('2015-03-31');
var_dump($datetime);

// 加算
$dateadd = MyDateTime::add('1 MONTH');
var_dump($dateadd);

// 減算
$datesub = MyDateTime::sub('1 MONTH');
var_dump($datesub);
$ php test.php
object(DateTime)#4 (3) {
  ["date"]=>
  string(26) "2015-04-27 11:34:12.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(10) "Asia/Tokyo"
}
object(DateTime)#3 (3) {
  ["date"]=>
  string(26) "2015-03-31 00:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(10) "Asia/Tokyo"
}
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2015-04-30 00:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(10) "Asia/Tokyo"
}
object(DateTime)#5 (3) {
  ["date"]=>
  string(26) "2015-02-28 00:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(10) "Asia/Tokyo"
}

うまくいった。

ご注意

上記は試験スクリプトです。セキュリティ的パフォーマンス的使い勝手的な考慮は含まれていません。

追記

CarbonというDateTime拡張ライブラリが、便利かも。

Official: Carbon
packagist: nesbot/carbon

3
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?