UTC storage. * * @package Rentbaik */ namespace Rentbaik\Support; use DateTimeImmutable; use DateTimeZone; use Exception; defined( 'ABSPATH' ) || exit; /** * Converts between the site timezone (what people type) and UTC (what is stored). */ final class Time { /** * MySQL datetime format. */ public const MYSQL = 'Y-m-d H:i:s'; /** * Parse a local date-time string (e.g. "2026-11-05T10:00" from datetime-local) into UTC. * * @param string $local Local date-time in the site timezone. * @return DateTimeImmutable|null UTC time, or null when invalid. */ public static function from_local( string $local ): ?DateTimeImmutable { $local = trim( str_replace( 'T', ' ', $local ) ); if ( ! preg_match( '/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}(:\d{2})?$/', $local ) ) { return null; } try { $date = new DateTimeImmutable( $local, wp_timezone() ); } catch ( Exception $e ) { return null; } return $date->setTimezone( new DateTimeZone( 'UTC' ) ); } /** * Parse a stored UTC MySQL datetime. * * @param string $utc UTC datetime (Y-m-d H:i:s). * @return DateTimeImmutable|null */ public static function from_utc( string $utc ): ?DateTimeImmutable { if ( '' === $utc || 0 === strpos( $utc, '0000-00-00' ) ) { return null; } try { return new DateTimeImmutable( $utc, new DateTimeZone( 'UTC' ) ); } catch ( Exception $e ) { return null; } } /** * Current UTC time. * * @return DateTimeImmutable */ public static function now(): DateTimeImmutable { return new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) ); } /** * UTC time as MySQL string. * * @param DateTimeImmutable $date Any time. * @return string */ public static function to_mysql( DateTimeImmutable $date ): string { return $date->setTimezone( new DateTimeZone( 'UTC' ) )->format( self::MYSQL ); } /** * Value for a datetime-local input, in the site timezone. * * @param DateTimeImmutable|null $date UTC time. * @return string */ public static function to_input( ?DateTimeImmutable $date ): string { return $date ? $date->setTimezone( wp_timezone() )->format( 'Y-m-d\TH:i' ) : ''; } /** * The same moment in the site timezone. * * @param DateTimeImmutable $date Any time. * @return DateTimeImmutable */ public static function local( DateTimeImmutable $date ): DateTimeImmutable { return $date->setTimezone( wp_timezone() ); } /** * Start of today in the site timezone, as UTC. * * @param int $offset_days Days to add (negative for the past). * @return DateTimeImmutable */ public static function local_midnight( int $offset_days = 0 ): DateTimeImmutable { $today = new DateTimeImmutable( 'today', wp_timezone() ); if ( 0 !== $offset_days ) { $today = $today->modify( sprintf( '%+d days', $offset_days ) ); } return $today->setTimezone( new DateTimeZone( 'UTC' ) ); } }