Skip to content

Commit 48f6780

Browse files
committed
wip: Use UTC internally
According to https://dev.mysql.com/doc/refman/8.0/en/time-zone-support.html > MySQL converts `TIMESTAMP` values from the current time zone to UTC for storage, and back from UTC to the current time zone for retrieval. (This does not occur for other types such as `DATETIME`.) That is bad. - [ ] Check that we do not use TIMESTAMP anywhere or set MySQL timezone to UTC. - [ ] Verify that PostgreSQL includes timezone offsets when selecting datetime values with timezone. - [ ] Check that MySQL correctly compares datetimes in db with values containing tz offset as produced by `daos\mysql\statements::datetime()`. - [ ] Add migrations for sqlite local → UTC when `date.timezone` is not UTC.
1 parent f14546b commit 48f6780

File tree

6 files changed

+17
-16
lines changed

6 files changed

+17
-16
lines changed

src/controllers/Items/Sync.php

+2-4
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ public function sync(): void {
4949
$this->view->jsonError(['sync' => 'missing since argument']);
5050
}
5151

52-
$since = new \DateTimeImmutable($params['since']);
53-
$since = $since->setTimeZone(new \DateTimeZone(date_default_timezone_get()));
52+
// The client should include a timezone offset but let’s default to UTC in case it does not.
53+
$since = new \DateTimeImmutable($params['since'], new \DateTimeZone('UTC'));
5454

5555
$lastUpdate = $this->itemsDao->lastUpdate();
5656

@@ -66,9 +66,7 @@ public function sync(): void {
6666
$sinceId = $this->itemsDao->lowestIdOfInterest() - 1;
6767
// only send 1 day worth of items
6868
$notBefore = new \DateTimeImmutable();
69-
$notBefore = $notBefore->setTimeZone(new \DateTimeZone(date_default_timezone_get()));
7069
$notBefore = $notBefore->sub(new \DateInterval('P1D'));
71-
$notBefore = $notBefore->setTimeZone(new \DateTimeZone(date_default_timezone_get()));
7270
}
7371

7472
$itemsHowMany = $this->configuration->itemsPerpage;

src/daos/ItemOptions.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,17 @@ public static function fromUser(array $data): self {
7171
}
7272

7373
if (isset($data['fromDatetime']) && is_string($data['fromDatetime']) && strlen($data['fromDatetime']) > 0) {
74-
$options->fromDatetime = new \DateTimeImmutable($data['fromDatetime']);
74+
// The client should include a timezone offset but let’s default to UTC in case it does not.
75+
$options->fromDatetime = new \DateTimeImmutable($data['fromDatetime'], new \DateTimeZone('UTC'));
7576
}
7677

7778
if (isset($data['fromId']) && is_numeric($data['fromId'])) {
7879
$options->fromId = (int) $data['fromId'];
7980
}
8081

8182
if (isset($data['updatedsince']) && is_string($data['updatedsince']) && strlen($data['updatedsince']) > 0) {
82-
$options->updatedSince = new \DateTimeImmutable($data['updatedsince']);
83+
// The client should include a timezone offset but let’s default to UTC in case it does not.
84+
$options->updatedSince = new \DateTimeImmutable($data['updatedsince'], new \DateTimeZone('UTC'));
8385
}
8486

8587
if (isset($data['tag']) && is_string($data['tag']) && strlen($tag = trim($data['tag'])) > 0) {

src/daos/mysql/Items.php

+5-2
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,9 @@ public function lastUpdate(): ?DateTimeImmutable {
569569
FROM ' . $this->configuration->dbPrefix . 'items;');
570570
$lastUpdate = $res[0]['last_update_time'];
571571

572-
return $lastUpdate !== null ? new DateTimeImmutable($lastUpdate) : null;
572+
// MySQL and SQLite do not support timezones, load it as UTC.
573+
// PostgreSQL will include the timezone offset as the part of the returned value and it will take precedence.
574+
return $lastUpdate !== null ? new DateTimeImmutable($lastUpdate, new \DateTimeZone('UTC')) : null;
573575
}
574576

575577
/**
@@ -627,7 +629,8 @@ public function bulkStatusUpdate(array $statuses): void {
627629

628630
// sanitize update time
629631
if (array_key_exists('datetime', $status)) {
630-
$updateDate = new \DateTimeImmutable($status['datetime']);
632+
// The client should include a timezone offset but let’s default to UTC in case it does not.
633+
$updateDate = new \DateTimeImmutable($status['datetime'], new \DateTimeZone('UTC'));
631634
} else {
632635
$updateDate = null;
633636
}

src/daos/mysql/Statements.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,8 @@ public static function ensureRowTypes(array $rows, array $expectedRowTypes): arr
177177
}
178178
break;
179179
case DatabaseInterface::PARAM_DATETIME:
180-
$value = new \DateTimeImmutable($row[$columnIndex]);
180+
// MySQL and SQLite do not support timezones, load it as UTC.
181+
$value = new \DateTimeImmutable($row[$columnIndex], new \DateTimeZone('UTC'));
181182
break;
182183
default:
183184
$value = null;

src/daos/pgsql/Statements.php

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ public static function ensureRowTypes(array $rows, array $expectedRowTypes): arr
104104
}
105105
break;
106106
case DatabaseInterface::PARAM_DATETIME:
107+
// PostgreSQL will include the timezone offset as the part of the returned value.
107108
$value = new \DateTimeImmutable($row[$columnIndex]);
108109
break;
109110
default:

src/daos/sqlite/Statements.php

+3-7
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,10 @@ public static function bool(bool $bool): string {
5050
* @return string representation of datetime
5151
*/
5252
public static function datetime(\DateTimeImmutable $date): string {
53-
// SQLite does not support timezones.
54-
// The client previously sent the local timezone
55-
// but now it sends UTC time so we need to adjust it here
56-
// to avoid fromDatetime mismatch.
57-
// TODO: Switch to UTC everywhere.
58-
$date = $date->setTimeZone((new \DateTimeImmutable())->getTimeZone());
53+
// SQLite does not support timezones so we store all dates in UTC.
54+
$utcDate = $date->setTimeZone(new \DateTimeZone('UTC'));
5955

60-
return $date->format('Y-m-d H:i:s');
56+
return $utcDate->format('Y-m-d H:i:s');
6157
}
6258

6359
/**

0 commit comments

Comments
 (0)