@@ -16,9 +16,6 @@ final class TimeFormatter
16
16
private const TIME_FORMAT = 'Y-m-d\TH:i:s\Z ' ;
17
17
private const TIME_ZONE = 'UTC ' ;
18
18
19
- private const RFC3339_FORMAT = 'Y-m-d\TH:i:sP ' ;
20
- private const RFC3339_EXTENDED_FORMAT = 'Y-m-d\TH:i:s.uP ' ;
21
-
22
19
public static function encode (?DateTimeImmutable $ time ): ?string
23
20
{
24
21
if ($ time === null ) {
@@ -34,19 +31,45 @@ public static function decode(?string $time): ?DateTimeImmutable
34
31
return null ;
35
32
}
36
33
37
- /** @psalm-suppress UndefinedFunction */
38
- $ decoded = DateTimeImmutable::createFromFormat (
39
- \str_contains ($ time , '. ' ) ? self ::RFC3339_EXTENDED_FORMAT : self ::RFC3339_FORMAT ,
40
- \strtoupper ($ time ),
41
- new DateTimeZone (self ::TIME_ZONE )
42
- );
34
+ $ time = self ::trimMicroseconds ($ time );
43
35
44
- if ($ decoded === false ) {
36
+ try {
37
+ $ decoded = new DateTimeImmutable ($ time );
38
+ } catch (\Throwable $ th ) {
45
39
throw new ValueError (
46
40
\sprintf ('%s(): Argument #1 ($time) is not a valid RFC3339 timestamp ' , __METHOD__ )
47
41
);
48
42
}
49
43
50
- return $ decoded ;
44
+ return self ::shiftWithTimezone ($ time , $ decoded );
45
+ }
46
+
47
+ private static function trimMicroseconds (string $ time ): string
48
+ {
49
+ $ microseconds = explode ('. ' , $ time , 2 );
50
+ if (isset ($ microseconds [1 ])) {
51
+ $ microsecondsAndTimezone = explode ('+ ' , $ microseconds [1 ], 2 );
52
+ if (count ($ microsecondsAndTimezone ) === 1 ) {
53
+ $ microsecondsAndTimezone = explode ('- ' , $ microseconds [1 ], 2 );
54
+ }
55
+ $ timezone = isset ($ microsecondsAndTimezone [1 ]) ? sprintf ('+%s ' , $ microsecondsAndTimezone [1 ]) : '' ;
56
+ $ time = sprintf (
57
+ "%s.%s%s " ,
58
+ $ microseconds [0 ],
59
+ substr ($ microsecondsAndTimezone [0 ], 0 , 6 ),
60
+ $ timezone
61
+ );
62
+ }
63
+
64
+ return $ time ;
65
+ }
66
+
67
+ private static function shiftWithTimezone (string $ time , DateTimeImmutable $ datetime ): DateTimeImmutable
68
+ {
69
+ if (\strpos ($ time , '+ ' ) === false && \strpos ($ time , '- ' ) === false && \strtoupper (\substr ($ time , -1 )) !== 'Z ' ) {
70
+ return $ datetime ->setTimezone (new \DateTimeZone ('UTC ' ));
71
+ }
72
+
73
+ return $ datetime ;
51
74
}
52
75
}
0 commit comments