Skip to content

Commit 9294c13

Browse files
committed
Set created board timezones to the local host tz
1 parent a7f2697 commit 9294c13

5 files changed

Lines changed: 95 additions & 1 deletion

File tree

src/QuickInstall/Sandbox/BoardRefreshService.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ private function runtimeConfig(array $board): array
4545
'admin_pass' => 'password',
4646
'admin_email' => 'admin@example.test',
4747
'board_email' => 'board@example.test',
48+
'board_timezone' => 'UTC',
4849
'populate' => 'none',
4950
'debug' => false,
5051
'extensions' => [],

src/QuickInstall/Sandbox/BoardService.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ public function create(string $name, string $version = 'latest', string $db = 'm
9292
'admin_pass' => 'password',
9393
'admin_email' => 'admin@example.test',
9494
'board_email' => 'board@example.test',
95+
'board_timezone' => $this->hostTimezone(),
9596
'extensions' => [],
9697
'styles' => [],
9798
];
@@ -124,6 +125,7 @@ public function create(string $name, string $version = 'latest', string $db = 'm
124125
'path' => $boardDir,
125126
'populate' => $populate,
126127
'debug' => $debug,
128+
'board_timezone' => $config['board_timezone'],
127129
'extensions' => [],
128130
'styles' => [],
129131
'created_at' => gmdate('c'),
@@ -142,6 +144,53 @@ public function create(string $name, string $version = 'latest', string $db = 'm
142144
return ['board' => $board, 'paths' => $paths];
143145
}
144146

147+
/** Returns the host's IANA timezone, falling back to UTC. */
148+
protected function hostTimezone(): string
149+
{
150+
$candidates = [];
151+
$environment = getenv('TZ');
152+
if (is_string($environment))
153+
{
154+
$candidates[] = ltrim(trim($environment), ':');
155+
}
156+
157+
$localtime = realpath('/etc/localtime');
158+
if (is_string($localtime) && preg_match('#/zoneinfo/(.+)$#', $localtime, $match))
159+
{
160+
$candidates[] = $match[1];
161+
}
162+
163+
if (is_readable('/etc/timezone'))
164+
{
165+
$timezone = file_get_contents('/etc/timezone');
166+
if (is_string($timezone))
167+
{
168+
$candidates[] = trim($timezone);
169+
}
170+
}
171+
172+
$candidates[] = date_default_timezone_get();
173+
foreach ($candidates as $candidate)
174+
{
175+
if ($candidate === '')
176+
{
177+
continue;
178+
}
179+
180+
try
181+
{
182+
// Match phpBB's own timezone validation semantics.
183+
new \DateTimeZone($candidate);
184+
return $candidate;
185+
}
186+
catch (\Exception $e)
187+
{
188+
}
189+
}
190+
191+
return 'UTC';
192+
}
193+
145194
private function backupBoardState(string $name): array
146195
{
147196
$token = str_replace('.', '', uniqid('replace-', true));

src/QuickInstall/Sandbox/DockerComposeWriter.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ private function compose(string $name, array $config): string
143143
environment:
144144
QUICKINSTALL_PHPBB_VERSION: "{$config['phpbb']}"
145145
QUICKINSTALL_POPULATE: "{$config['populate']}"
146+
QUICKINSTALL_BOARD_TIMEZONE: "{$config['board_timezone']}"
146147
147148
$dbService
148149
@@ -274,6 +275,12 @@ private function entrypoint(): string
274275
if [ ! -s /var/www/html/config.php ] && [ -f /var/www/html/install/phpbbcli.php ]; then
275276
php /var/www/html/install/phpbbcli.php install /opt/quickinstall/install-config.yml
276277
rm -rf /var/www/html/install
278+
if php -r 'try { new DateTimeZone((string) getenv("QUICKINSTALL_BOARD_TIMEZONE")); } catch (Exception $e) { exit(1); }'; then
279+
php /var/www/html/bin/phpbbcli.php config:set board_timezone "$QUICKINSTALL_BOARD_TIMEZONE"
280+
else
281+
echo "Host timezone '$QUICKINSTALL_BOARD_TIMEZONE' is unsupported by this PHP runtime; using UTC."
282+
php /var/www/html/bin/phpbbcli.php config:set board_timezone UTC
283+
fi
277284
chown -R www-data:www-data /var/www/html
278285
fi
279286

tests/Unit/BoardServiceTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,27 @@ public function testCreateWritesBoardAndRuntimeConfig(): void
2727
self::assertSame(8090, $result['board']['port']);
2828
self::assertSame('tiny', $result['board']['populate']);
2929
self::assertTrue($result['board']['debug']);
30+
self::assertSame('America/Los_Angeles', $result['board']['board_timezone']);
3031
self::assertSame('demo', $project->boards()['demo']['name']);
3132
self::assertFileExists($project->composePath('demo'));
3233
}
3334

35+
public function testHostTimezoneUsesPhpCompatibleEnvironmentValue(): void
36+
{
37+
$previous = getenv('TZ');
38+
putenv('TZ=US/Pacific');
39+
40+
try
41+
{
42+
$project = $this->projectWithSource('3.3.14');
43+
self::assertSame('US/Pacific', (new HostTimezoneTestBoardService($project))->detectedHostTimezone());
44+
}
45+
finally
46+
{
47+
$previous === false ? putenv('TZ') : putenv('TZ=' . $previous);
48+
}
49+
}
50+
3451
public function testCreateRejectsDuplicateWithoutReplace(): void
3552
{
3653
$project = $this->projectWithSource('3.3.14');
@@ -236,6 +253,14 @@ private function projectWithSource(string $version, ?string $osFamily = null): P
236253
}
237254
}
238255

256+
class HostTimezoneTestBoardService extends BoardService
257+
{
258+
public function detectedHostTimezone(): string
259+
{
260+
return $this->hostTimezone();
261+
}
262+
}
263+
239264
class TestBoardService extends BoardService
240265
{
241266
private ?ServiceTestBoardRunner $runner;
@@ -255,6 +280,11 @@ protected function isPortInUse(int $port): bool
255280
return $this->portInUse;
256281
}
257282

283+
protected function hostTimezone(): string
284+
{
285+
return 'America/Los_Angeles';
286+
}
287+
258288
protected function createBoardRunner(): BoardRunner
259289
{
260290
return $this->runner ?? parent::createBoardRunner();

tests/Unit/DockerComposeWriterTest.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,13 @@ public function testWritesDatabaseRuntimeFiles(string $board, string $db, array
2222
self::assertFileExists($paths['install_config']);
2323
self::assertFileExists($paths['dockerfile']);
2424
self::assertFileExists($paths['entrypoint']);
25-
self::assertStringContainsString('apache2-foreground', file_get_contents($paths['entrypoint']));
25+
$entrypoint = file_get_contents($paths['entrypoint']);
26+
self::assertStringContainsString('apache2-foreground', $entrypoint);
27+
self::assertStringContainsString('new DateTimeZone((string) getenv("QUICKINSTALL_BOARD_TIMEZONE"))', $entrypoint);
28+
self::assertStringContainsString('config:set board_timezone "$QUICKINSTALL_BOARD_TIMEZONE"', $entrypoint);
29+
self::assertStringContainsString('config:set board_timezone UTC', $entrypoint);
30+
self::assertStringContainsString("is unsupported by this PHP runtime; using UTC.", $entrypoint);
31+
self::assertStringContainsString('QUICKINSTALL_BOARD_TIMEZONE: "America/Los_Angeles"', file_get_contents($paths['compose']));
2632

2733
$output = file_get_contents($paths['compose']) . "\n" . file_get_contents($paths['install_config']) . "\n" . file_get_contents($paths['dockerfile']);
2834
foreach ($expectedContains as $expected)
@@ -164,6 +170,7 @@ private function config(array $overrides = []): array
164170
'admin_pass' => 'password',
165171
'admin_email' => 'admin@example.test',
166172
'board_email' => 'board@example.test',
173+
'board_timezone' => 'America/Los_Angeles',
167174
'extensions' => [
168175
'acme/demo' => ['mode' => 'bind', 'source' => '/tmp/acme-demo'],
169176
],

0 commit comments

Comments
 (0)