@@ -3288,7 +3288,7 @@ static bool php_date_modify(zval *object, char *modify, size_t modify_len) /* {{
32883288 php_date_obj * dateobj ;
32893289 timelib_time * tmp_time ;
32903290 timelib_error_container * err = NULL ;
3291- timelib_sll rel_h , rel_i , rel_s , rel_us ;
3291+ timelib_sll rel_h , rel_i , rel_s , rel_us ;
32923292
32933293 dateobj = Z_PHPDATE_P (object );
32943294
@@ -3357,10 +3357,8 @@ static bool php_date_modify(zval *object, char *modify, size_t modify_len) /* {{
33573357
33583358 timelib_time_dtor (tmp_time );
33593359
3360- /* Strip relative h/i/s/us before timelib_update_ts() so that
3361- * do_adjust_relative() does not add them to wall-clock fields.
3362- * Wall-clock addition breaks at DST boundaries; SSE arithmetic
3363- * (applied below) is always correct. */
3360+ /* do_adjust_relative() applies h/i/s as wall-clock, which breaks across
3361+ * DST. Strip them before timelib_update_ts and re-apply via SSE below. */
33643362 rel_h = dateobj -> time -> relative .h ;
33653363 rel_i = dateobj -> time -> relative .i ;
33663364 rel_s = dateobj -> time -> relative .s ;
@@ -3373,34 +3371,21 @@ static bool php_date_modify(zval *object, char *modify, size_t modify_len) /* {{
33733371 timelib_update_ts (dateobj -> time , NULL );
33743372 timelib_update_from_sse (dateobj -> time );
33753373
3376- /* Fold microsecond overflow into seconds so that the seconds
3377- * component goes through SSE arithmetic, not wall-clock.
3378- * Matches timelib_add_wall()'s do_range_limit() call
3379- * (interval.c:317). */
3380- if (rel_us >= 1000000 || rel_us <= -1000000 ) {
3381- rel_s += rel_us / 1000000 ;
3382- rel_us = rel_us % 1000000 ;
3383- }
3384-
3385- /* Apply h/i/s via SSE (Unix timestamp) arithmetic, matching
3386- * the approach in timelib_add_wall() (interval.c:312). */
3387- if (rel_h || rel_i || rel_s ) {
3388- dateobj -> time -> sse +=
3389- timelib_hms_to_seconds (rel_h , rel_i , rel_s );
3390- timelib_update_from_sse (dateobj -> time );
3391- }
3392-
3393- /* Apply remaining sub-second microseconds. After the above
3394- * normalization rel_us is in (-1000000, 1000000), so the
3395- * cascade into seconds is at most +/-1s -- safe to go through
3396- * wall-clock normalize + update_ts (have_relative is already
3397- * cleared by the first timelib_update_ts call). */
3398- if (rel_us ) {
3399- dateobj -> time -> us += rel_us ;
3400- timelib_do_normalize (dateobj -> time );
3401- timelib_update_ts (dateobj -> time , NULL );
3402- timelib_update_from_sse (dateobj -> time );
3374+ /* Normalize microseconds: fold full seconds into rel_s, keep rel_us >= 0 */
3375+ rel_s += rel_us / 1000000 ;
3376+ rel_us = rel_us % 1000000 ;
3377+ if (rel_us < 0 ) {
3378+ rel_s -- ;
3379+ rel_us += 1000000 ;
3380+ }
3381+
3382+ dateobj -> time -> sse += timelib_hms_to_seconds (rel_h , rel_i , rel_s );
3383+ dateobj -> time -> us += rel_us ;
3384+ if (dateobj -> time -> us >= 1000000 ) {
3385+ dateobj -> time -> us -= 1000000 ;
3386+ dateobj -> time -> sse ++ ;
34033387 }
3388+ timelib_update_from_sse (dateobj -> time );
34043389
34053390 dateobj -> time -> have_relative = 0 ;
34063391 memset (& dateobj -> time -> relative , 0 , sizeof (dateobj -> time -> relative ));
0 commit comments