Browse Source

Merge pull request #11780 from cakephp/3.next-datetime-db-type-tz

Allow changing timezone when generating datetime string for db.
Mark Story 8 years ago
parent
commit
ccbfea6483

+ 35 - 1
src/Database/Type/DateTimeType.php

@@ -19,6 +19,7 @@ use Cake\Database\Type;
 use Cake\Database\TypeInterface;
 use Cake\Database\Type\BatchCastingInterface;
 use DateTimeInterface;
+use DateTimeZone;
 use Exception;
 use PDO;
 use RuntimeException;
@@ -102,6 +103,13 @@ class DateTimeType extends Type implements TypeInterface, BatchCastingInterface
     protected $_className;
 
     /**
+     * Timezone instance.
+     *
+     * @var \DateTimeZone|null
+     */
+    protected $dbTimezone;
+
+    /**
      * {@inheritDoc}
      */
     public function __construct($name = null)
@@ -114,7 +122,7 @@ class DateTimeType extends Type implements TypeInterface, BatchCastingInterface
     /**
      * Convert DateTime instance into strings.
      *
-     * @param string|int|\DateTime $value The value to convert.
+     * @param string|int|\DateTime|\DateTimeImmutable $value The value to convert.
      * @param \Cake\Database\Driver $driver The driver instance to convert with.
      * @return string|null
      */
@@ -130,10 +138,36 @@ class DateTimeType extends Type implements TypeInterface, BatchCastingInterface
 
         $format = (array)$this->_format;
 
+        if ($this->dbTimezone !== null
+            && $this->dbTimezone->getName() !== $value->getTimezone()->getName()
+        ) {
+            $value = $value->setTimezone($this->dbTimezone);
+        }
+
         return $value->format(array_shift($format));
     }
 
     /**
+     * Set database timezone.
+     *
+     * Specified timezone will be set for DateTime objects before generating
+     * datetime string for saving to database. If `null` no timezone conversion
+     * will be done.
+     *
+     * @param string|\DateTimeZone|null $timezone Database timezone.
+     * @return $this
+     */
+    public function setTimezone($timezone)
+    {
+        if (is_string($timezone)) {
+            $timezone = new DateTimeZone($timezone);
+        }
+        $this->dbTimezone = $timezone;
+
+        return $this;
+    }
+
+    /**
      * Convert strings into DateTime instances.
      *
      * @param string $value The value to convert.

+ 19 - 0
tests/TestCase/Database/Type/DateTimeTypeTest.php

@@ -18,6 +18,7 @@ use Cake\Database\Type\DateTimeType;
 use Cake\I18n\FrozenTime;
 use Cake\I18n\Time;
 use Cake\TestSuite\TestCase;
+use DateTimeZone;
 
 /**
  * Test for the DateTime type.
@@ -145,6 +146,24 @@ class DateTimeTypeTest extends TestCase
         $result = $this->type->toDatabase($date, $this->driver);
         $this->assertEquals('2013-08-12 15:16:17', $result);
 
+        $this->type->setTimezone('Asia/Kolkata'); // UTC+5:30
+        $result = $this->type->toDatabase($date, $this->driver);
+        $this->assertEquals('2013-08-12 20:46:17', $result);
+
+        $this->type->setTimezone(new DateTimeZone('Asia/Kolkata'));
+        $result = $this->type->toDatabase($date, $this->driver);
+        $this->assertEquals('2013-08-12 20:46:17', $result);
+        $this->type->setTimezone(null);
+
+        $date = new FrozenTime('2013-08-12 15:16:17');
+        $result = $this->type->toDatabase($date, $this->driver);
+        $this->assertEquals('2013-08-12 15:16:17', $result);
+
+        $this->type->setTimezone('Asia/Kolkata'); // UTC+5:30
+        $result = $this->type->toDatabase($date, $this->driver);
+        $this->assertEquals('2013-08-12 20:46:17', $result);
+        $this->type->setTimezone(null);
+
         $date = 1401906995;
         $result = $this->type->toDatabase($date, $this->driver);
         $this->assertEquals('2014-06-04 18:36:35', $result);