Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/Instant.php
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,9 @@ public function jsonSerialize(): string
/**
* Returns the ISO 8601 representation of this instant.
*
* The time part always includes the seconds, as RFC 3339 section 5.6
* requires, even when they are zero.
*
* @return non-empty-string
*/
public function toISOString(): string
Expand Down
24 changes: 23 additions & 1 deletion src/ZonedDateTime.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@

use function assert;
use function intdiv;
use function rtrim;
use function str_pad;

use const STR_PAD_LEFT;

/**
* A date-time with a time-zone in the ISO-8601 calendar system.
Expand Down Expand Up @@ -735,11 +739,29 @@ public function jsonSerialize(): string
/**
* Returns the ISO 8601 representation of this zoned date time.
*
* Unlike {@see LocalTime::toISOString()}, the time part always includes the
* seconds, as RFC 3339 section 5.6 requires, even when they are zero.
*
* @return non-empty-string
*/
public function toISOString(): string
{
$string = $this->localDateTime . $this->timeZoneOffset;
$time = $this->localDateTime->getTime();

$hour = $time->getHour();
$minute = $time->getMinute();
$second = $time->getSecond();
$nano = $time->getNano();

$string = $this->localDateTime->getDate()
. 'T'
. ($hour < 10 ? '0' . $hour : $hour)
. ':'
. ($minute < 10 ? '0' . $minute : $minute)
. ':'
. ($second < 10 ? '0' . $second : $second)
. ($nano !== 0 ? '.' . rtrim(str_pad((string) $nano, 9, '0', STR_PAD_LEFT), '0') : '')
. $this->timeZoneOffset;

if ($this->timeZone instanceof TimeZoneRegion) {
$string .= '[' . $this->timeZone . ']';
Expand Down
11 changes: 7 additions & 4 deletions tests/InstantTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -573,11 +573,11 @@ public function testGetIntervalTo(int $second1, int $nano1, int $second2, int $n
public static function providerGetIntervalTo(): array
{
return [
[1672567200, 0, 1672567200, 0, '2023-01-01T10:00Z/2023-01-01T10:00Z'],
[1672567200, 0, 1672567210, 0, '2023-01-01T10:00Z/2023-01-01T10:00:10Z'],
[1672567200, 0, 1672567200, 0, '2023-01-01T10:00:00Z/2023-01-01T10:00:00Z'],
[1672567200, 0, 1672567210, 0, '2023-01-01T10:00:00Z/2023-01-01T10:00:10Z'],
[1672567200, 1000000, 1672567210, 2000000, '2023-01-01T10:00:00.001Z/2023-01-01T10:00:10.002Z'],
[1672567200, 1, 1672567200, 9, '2023-01-01T10:00:00.000000001Z/2023-01-01T10:00:00.000000009Z'],
[1672567200, 0, 1672653600, 0, '2023-01-01T10:00Z/2023-01-02T10:00Z'],
[1672567200, 0, 1672653600, 0, '2023-01-01T10:00:00Z/2023-01-02T10:00:00Z'],
];
}

Expand Down Expand Up @@ -648,11 +648,14 @@ public static function providerToString(): array
[-2000000000, 0, '1906-08-16T20:26:40Z'],
[-1, 0, '1969-12-31T23:59:59Z'],
[-1, 123, '1969-12-31T23:59:59.000000123Z'],
[0, 0, '1970-01-01T00:00Z'],
[0, 0, '1970-01-01T00:00:00Z'],
[0, 123456, '1970-01-01T00:00:00.000123456Z'],
[1, 0, '1970-01-01T00:00:01Z'],
[1, 123456789, '1970-01-01T00:00:01.123456789Z'],
[2000000000, 0, '2033-05-18T03:33:20Z'],
// whole minute and whole hour must keep the full ":00" seconds (RFC 3339 section 5.6)
[1700000040, 0, '2023-11-14T22:14:00Z'],
[1700002800, 0, '2023-11-14T23:00:00Z'],
];
}

Expand Down
2 changes: 1 addition & 1 deletion tests/IntervalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ public function testGetIntersectionWithInvalidParams(): void
$interval2 = Interval::of(Instant::of(300000), Instant::of(400000));

$this->expectException(DateTimeException::class);
$this->expectExceptionMessage('Intervals "1970-01-02T03:46:40Z/1970-01-03T07:33:20Z" and "1970-01-04T11:20Z/1970-01-05T15:06:40Z" do not intersect.');
$this->expectExceptionMessage('Intervals "1970-01-02T03:46:40Z/1970-01-03T07:33:20Z" and "1970-01-04T11:20:00Z/1970-01-05T15:06:40Z" do not intersect.');

$interval1->getIntersectionWith($interval2);
}
Expand Down
63 changes: 33 additions & 30 deletions tests/ZonedDateTimeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ public static function providerFromNativeDateTime(): array
{
return [
['2018-07-21 14:09:10.23456', 'America/Los_Angeles', '2018-07-21T14:09:10.23456-07:00[America/Los_Angeles]'],
['2019-01-21 17:59', 'America/Los_Angeles', '2019-01-21T17:59-08:00[America/Los_Angeles]'],
['2019-01-21 17:59', 'America/Los_Angeles', '2019-01-21T17:59:00-08:00[America/Los_Angeles]'],
['2019-01-23 09:10:11.123', '+05:30', '2019-01-23T09:10:11.123+05:30'],
];
}
Expand Down Expand Up @@ -753,12 +753,12 @@ public static function providerPlusWeeks(): array
['2000-01-01T12:34:56.123456789-08:00[America/Los_Angeles]', 25, '2000-06-24T12:34:56.123456789-07:00[America/Los_Angeles]'],

// https://github.com/brick/date-time/issues/115
['2025-03-23T01:00+01:00[Europe/Prague]', 1, '2025-03-30T01:00+01:00[Europe/Prague]'],
['2025-03-23T01:30+01:00[Europe/Prague]', 1, '2025-03-30T01:30+01:00[Europe/Prague]'],
['2025-03-23T02:00+01:00[Europe/Prague]', 1, '2025-03-30T03:00+02:00[Europe/Prague]'],
['2025-03-23T02:30+01:00[Europe/Prague]', 1, '2025-03-30T03:30+02:00[Europe/Prague]'],
['2025-03-23T03:00+01:00[Europe/Prague]', 1, '2025-03-30T03:00+02:00[Europe/Prague]'],
['2025-03-23T03:30+01:00[Europe/Prague]', 1, '2025-03-30T03:30+02:00[Europe/Prague]'],
['2025-03-23T01:00+01:00[Europe/Prague]', 1, '2025-03-30T01:00:00+01:00[Europe/Prague]'],
['2025-03-23T01:30+01:00[Europe/Prague]', 1, '2025-03-30T01:30:00+01:00[Europe/Prague]'],
['2025-03-23T02:00+01:00[Europe/Prague]', 1, '2025-03-30T03:00:00+02:00[Europe/Prague]'],
['2025-03-23T02:30+01:00[Europe/Prague]', 1, '2025-03-30T03:30:00+02:00[Europe/Prague]'],
['2025-03-23T03:00+01:00[Europe/Prague]', 1, '2025-03-30T03:00:00+02:00[Europe/Prague]'],
['2025-03-23T03:30+01:00[Europe/Prague]', 1, '2025-03-30T03:30:00+02:00[Europe/Prague]'],
];
}

Expand All @@ -782,12 +782,12 @@ public static function providerPlusDays(): array
['2000-04-03T12:34:56.123456789-07:00[America/Los_Angeles]', -2, '2000-04-01T12:34:56.123456789-08:00[America/Los_Angeles]'],

// https://github.com/brick/date-time/issues/115
['2025-03-29T01:00+01:00[Europe/Prague]', 1, '2025-03-30T01:00+01:00[Europe/Prague]'],
['2025-03-29T01:30+01:00[Europe/Prague]', 1, '2025-03-30T01:30+01:00[Europe/Prague]'],
['2025-03-29T02:00+01:00[Europe/Prague]', 1, '2025-03-30T03:00+02:00[Europe/Prague]'],
['2025-03-29T02:30+01:00[Europe/Prague]', 1, '2025-03-30T03:30+02:00[Europe/Prague]'],
['2025-03-29T03:00+01:00[Europe/Prague]', 1, '2025-03-30T03:00+02:00[Europe/Prague]'],
['2025-03-29T03:30+01:00[Europe/Prague]', 1, '2025-03-30T03:30+02:00[Europe/Prague]'],
['2025-03-29T01:00+01:00[Europe/Prague]', 1, '2025-03-30T01:00:00+01:00[Europe/Prague]'],
['2025-03-29T01:30+01:00[Europe/Prague]', 1, '2025-03-30T01:30:00+01:00[Europe/Prague]'],
['2025-03-29T02:00+01:00[Europe/Prague]', 1, '2025-03-30T03:00:00+02:00[Europe/Prague]'],
['2025-03-29T02:30+01:00[Europe/Prague]', 1, '2025-03-30T03:30:00+02:00[Europe/Prague]'],
['2025-03-29T03:00+01:00[Europe/Prague]', 1, '2025-03-30T03:00:00+02:00[Europe/Prague]'],
['2025-03-29T03:30+01:00[Europe/Prague]', 1, '2025-03-30T03:30:00+02:00[Europe/Prague]'],
];
}

Expand Down Expand Up @@ -815,12 +815,12 @@ public static function providerPlusHours(): array
['2000-04-02T04:12:34.123456789-07:00[America/Los_Angeles]', 1, '2000-04-02T05:12:34.123456789-07:00[America/Los_Angeles]'],

// https://github.com/brick/date-time/issues/115
['2025-03-29T01:00+01:00[Europe/Prague]', 24, '2025-03-30T01:00+01:00[Europe/Prague]'],
['2025-03-29T01:30+01:00[Europe/Prague]', 24, '2025-03-30T01:30+01:00[Europe/Prague]'],
['2025-03-29T02:00+01:00[Europe/Prague]', 24, '2025-03-30T03:00+02:00[Europe/Prague]'],
['2025-03-29T02:30+01:00[Europe/Prague]', 24, '2025-03-30T03:30+02:00[Europe/Prague]'],
['2025-03-29T03:00+01:00[Europe/Prague]', 24, '2025-03-30T04:00+02:00[Europe/Prague]'],
['2025-03-29T03:30+01:00[Europe/Prague]', 24, '2025-03-30T04:30+02:00[Europe/Prague]'],
['2025-03-29T01:00+01:00[Europe/Prague]', 24, '2025-03-30T01:00:00+01:00[Europe/Prague]'],
['2025-03-29T01:30+01:00[Europe/Prague]', 24, '2025-03-30T01:30:00+01:00[Europe/Prague]'],
['2025-03-29T02:00+01:00[Europe/Prague]', 24, '2025-03-30T03:00:00+02:00[Europe/Prague]'],
['2025-03-29T02:30+01:00[Europe/Prague]', 24, '2025-03-30T03:30:00+02:00[Europe/Prague]'],
['2025-03-29T03:00+01:00[Europe/Prague]', 24, '2025-03-30T04:00:00+02:00[Europe/Prague]'],
['2025-03-29T03:30+01:00[Europe/Prague]', 24, '2025-03-30T04:30:00+02:00[Europe/Prague]'],
];
}

Expand Down Expand Up @@ -848,10 +848,10 @@ public static function providerPlusMinutes(): array
['2000-04-02T03:01:01.654321-07:00[America/Los_Angeles]', 1, '2000-04-02T03:02:01.654321-07:00[America/Los_Angeles]'],

// https://github.com/brick/date-time/issues/115
['2025-03-30T01:30+01:00[Europe/Prague]', 50, '2025-03-30T03:20+02:00[Europe/Prague]'],
['2025-03-30T01:30+01:00[Europe/Prague]', 100, '2025-03-30T04:10+02:00[Europe/Prague]'],
['2025-03-30T03:20+02:00[Europe/Prague]', -50, '2025-03-30T01:30+01:00[Europe/Prague]'],
['2025-03-30T04:10+02:00[Europe/Prague]', -100, '2025-03-30T01:30+01:00[Europe/Prague]'],
['2025-03-30T01:30:00+01:00[Europe/Prague]', 50, '2025-03-30T03:20:00+02:00[Europe/Prague]'],
['2025-03-30T01:30:00+01:00[Europe/Prague]', 100, '2025-03-30T04:10:00+02:00[Europe/Prague]'],
['2025-03-30T03:20:00+02:00[Europe/Prague]', -50, '2025-03-30T01:30:00+01:00[Europe/Prague]'],
['2025-03-30T04:10:00+02:00[Europe/Prague]', -100, '2025-03-30T01:30:00+01:00[Europe/Prague]'],
Comment on lines +851 to +854

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Input does not need to be modified:

Suggested change
['2025-03-30T01:30:00+01:00[Europe/Prague]', 50, '2025-03-30T03:20:00+02:00[Europe/Prague]'],
['2025-03-30T01:30:00+01:00[Europe/Prague]', 100, '2025-03-30T04:10:00+02:00[Europe/Prague]'],
['2025-03-30T03:20:00+02:00[Europe/Prague]', -50, '2025-03-30T01:30:00+01:00[Europe/Prague]'],
['2025-03-30T04:10:00+02:00[Europe/Prague]', -100, '2025-03-30T01:30:00+01:00[Europe/Prague]'],
['2025-03-30T01:30:00+01[Europe/Prague]', 50, '2025-03-30T03:20:00+02:00[Europe/Prague]'],
['2025-03-30T01:30:00+01[Europe/Prague]', 100, '2025-03-30T04:10:00+02:00[Europe/Prague]'],
['2025-03-30T03:20:00+02[Europe/Prague]', -50, '2025-03-30T01:30:00+01:00[Europe/Prague]'],
['2025-03-30T04:10:00+02[Europe/Prague]', -100, '2025-03-30T01:30:00+01:00[Europe/Prague]'],

];
}

Expand All @@ -878,10 +878,10 @@ public static function providerPlusSeconds(): array
['2000-04-02T03:00:01.654321-07:00[America/Los_Angeles]', 1, '2000-04-02T03:00:02.654321-07:00[America/Los_Angeles]'],

// https://github.com/brick/date-time/issues/115
['2025-03-30T01:30+01:00[Europe/Prague]', 3000, '2025-03-30T03:20+02:00[Europe/Prague]'],
['2025-03-30T01:30+01:00[Europe/Prague]', 6000, '2025-03-30T04:10+02:00[Europe/Prague]'],
['2025-03-30T03:20+02:00[Europe/Prague]', -3000, '2025-03-30T01:30+01:00[Europe/Prague]'],
['2025-03-30T04:10+02:00[Europe/Prague]', -6000, '2025-03-30T01:30+01:00[Europe/Prague]'],
['2025-03-30T01:30:00+01:00[Europe/Prague]', 3000, '2025-03-30T03:20:00+02:00[Europe/Prague]'],
['2025-03-30T01:30:00+01:00[Europe/Prague]', 6000, '2025-03-30T04:10:00+02:00[Europe/Prague]'],
['2025-03-30T03:20:00+02:00[Europe/Prague]', -3000, '2025-03-30T01:30:00+01:00[Europe/Prague]'],
['2025-03-30T04:10:00+02:00[Europe/Prague]', -6000, '2025-03-30T01:30:00+01:00[Europe/Prague]'],
Comment on lines +881 to +884

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Input does not need to be modified:

Suggested change
['2025-03-30T01:30:00+01:00[Europe/Prague]', 3000, '2025-03-30T03:20:00+02:00[Europe/Prague]'],
['2025-03-30T01:30:00+01:00[Europe/Prague]', 6000, '2025-03-30T04:10:00+02:00[Europe/Prague]'],
['2025-03-30T03:20:00+02:00[Europe/Prague]', -3000, '2025-03-30T01:30:00+01:00[Europe/Prague]'],
['2025-03-30T04:10:00+02:00[Europe/Prague]', -6000, '2025-03-30T01:30:00+01:00[Europe/Prague]'],
['2025-03-30T01:30:00+01[Europe/Prague]', 3000, '2025-03-30T03:20:00+02:00[Europe/Prague]'],
['2025-03-30T01:30:00+01[Europe/Prague]', 6000, '2025-03-30T04:10:00+02:00[Europe/Prague]'],
['2025-03-30T03:20:00+02[Europe/Prague]', -3000, '2025-03-30T01:30:00+01:00[Europe/Prague]'],
['2025-03-30T04:10:00+02[Europe/Prague]', -6000, '2025-03-30T01:30:00+01:00[Europe/Prague]'],

];
}

Expand Down Expand Up @@ -1086,6 +1086,9 @@ public static function providerToString(): array
return [
['2000-01-20T12:34:56.123456789', 'America/Los_Angeles', '2000-01-20T12:34:56.123456789-08:00[America/Los_Angeles]'],
['2000-01-20T12:34:56.123456789', '-07:00', '2000-01-20T12:34:56.123456789-07:00'],
// whole minute and whole hour must keep the full ":00" seconds (RFC 3339 section 5.6)
['2000-01-20T12:34', '-07:00', '2000-01-20T12:34:00-07:00'],
['2000-01-20T12:00', 'America/Los_Angeles', '2000-01-20T12:00:00-08:00[America/Los_Angeles]'],
];
}

Expand Down Expand Up @@ -1121,13 +1124,13 @@ public function testGetIntervalTo(string $firstDate, string $secondDate, string
public static function providerGetIntervalTo(): array
{
return [
['2023-01-01T10:00:00Z', '2023-01-01T10:00:00Z', '2023-01-01T10:00Z/2023-01-01T10:00Z'],
['2023-01-01T10:00:00Z', '2023-01-01T10:00:10Z', '2023-01-01T10:00Z/2023-01-01T10:00:10Z'],
['2023-01-01T10:00:00Z', '2023-01-01T10:00:00Z', '2023-01-01T10:00:00Z/2023-01-01T10:00:00Z'],
['2023-01-01T10:00:00Z', '2023-01-01T10:00:10Z', '2023-01-01T10:00:00Z/2023-01-01T10:00:10Z'],
['2023-01-01T10:00:00.001Z', '2023-01-01T10:00:10.002Z', '2023-01-01T10:00:00.001Z/2023-01-01T10:00:10.002Z'],
['2023-01-01T10:00:00.001Z', '2023-01-01T13:00:10.002+03:00', '2023-01-01T10:00:00.001Z/2023-01-01T10:00:10.002Z'],
['2023-01-01T10:00:00.001+03:00', '2023-01-01T13:00:10.002+03:00', '2023-01-01T07:00:00.001Z/2023-01-01T10:00:10.002Z'],
['2023-01-01T10:00:00.000000001Z', '2023-01-01T10:00:00.000000009Z', '2023-01-01T10:00:00.000000001Z/2023-01-01T10:00:00.000000009Z'],
['2023-01-01T10:00:00Z', '2023-01-02T10:00:00Z', '2023-01-01T10:00Z/2023-01-02T10:00Z'],
['2023-01-01T10:00:00Z', '2023-01-02T10:00:00Z', '2023-01-01T10:00:00Z/2023-01-02T10:00:00Z'],
];
}

Expand Down
Loading