diff --git a/ext/date/lib/interval.c b/ext/date/lib/interval.c index da9262da999b6..d9c751a78eaf0 100644 --- a/ext/date/lib/interval.c +++ b/ext/date/lib/interval.c @@ -146,6 +146,7 @@ static timelib_rel_time *timelib_diff_with_tzid(timelib_time *one, timelib_time timelib_rel_time *timelib_diff(timelib_time *one, timelib_time *two) { timelib_rel_time *rt; + timelib_sll sse_diff; if (one->zone_type == TIMELIB_ZONETYPE_ID && two->zone_type == TIMELIB_ZONETYPE_ID && strcmp(one->tz_info->name, two->tz_info->name) == 0) { return timelib_diff_with_tzid(one, two); @@ -172,6 +173,17 @@ timelib_rel_time *timelib_diff(timelib_time *one, timelib_time *two) rt->days = timelib_diff_days(one, two); + /* Use SSE diff when wall-clock dates are inverted */ + if ((rt->y < 0 || (rt->y == 0 && rt->m < 0)) && (sse_diff = two->sse - one->sse) >= 0) { + rt->y = rt->m = rt->d = 0; + rt->h = sse_diff / 3600; + rt->i = (sse_diff % 3600) / 60; + rt->s = sse_diff % 60; + rt->days = sse_diff / 86400; + timelib_do_rel_normalize(two, rt); + return rt; + } + timelib_do_rel_normalize(rt->invert ? one : two, rt); return rt; diff --git a/ext/date/tests/gh13857.phpt b/ext/date/tests/gh13857.phpt new file mode 100644 index 0000000000000..8164866616bda --- /dev/null +++ b/ext/date/tests/gh13857.phpt @@ -0,0 +1,30 @@ +--TEST-- +Bug GH-13857 (Unexpected Results with date_diff for Different Timezones) wall-clock dates are inverted. +--FILE-- +setTimeZone(new DateTimeZone('Asia/Tokyo')); +$endDate = (new DateTime('2024-04-01 08:48:22'))->setTimeZone(new DateTimeZone('UTC')); + +echo "nowDate: ", $nowDate->format('Y-m-d H:i:s T'), "\n"; +echo "endDate: ", $endDate->format('Y-m-d H:i:s T'), "\n"; + +$diff = date_diff($nowDate, $endDate); +echo "diff: ", $diff->format('%R %Y-%M-%D %H:%I:%S'), "\n"; +echo "days: ", $diff->days, "\n"; + +$diff2 = date_diff($endDate, $nowDate); +echo "reversed: ", $diff2->format('%R %Y-%M-%D %H:%I:%S'), "\n"; + +$a = new DateTime('2024-04-01 00:49:22', new DateTimeZone('+09:00')); +$b = new DateTime('2024-03-31 23:48:22', new DateTimeZone('+00:00')); +$diff3 = $a->diff($b); +echo "offset TZ: ", $diff3->format('%R %Y-%M-%D %H:%I:%S'), "\n"; +?> +--EXPECT-- +nowDate: 2024-04-01 00:49:22 JST +endDate: 2024-03-31 23:48:22 UTC +diff: + 00-00-00 07:59:00 +days: 0 +reversed: - 00-00-00 07:59:00 +offset TZ: + 00-00-00 07:59:00