PHP Add n Minutes to Time/Date string and RETAIN timezone

Viewed 38

After an hour exploring Stack Overflow, I'm more confused than ever (and based on the number of posts, I'm probably missing something painfully obvious). All I want to do is add n minutes to an existing date/time string (formatted as $start = '2022-09-10T09:00:00-07:00') WITHOUT losing the time zone.

Based on my reading, it looks like I need to use 'date' and 'strtotime' but when I do I lose the time zone. For example ...

$start = date('m:d:y H:i:s', strtotime($start . ' +90 minutes'));

...returns '09:10:22 14:30:00'

When I try adding formatting like this to get the exact format I'm looking for...

$start = date(DATE_W3C, strtotime($start . ' +90 minutes'));

...it returns the correct format but changes the time zone: '2022-09-10T14:30:00+00:00'

All I am trying to do is to take '2022-09-10T09:00:00-07:00' and add 90 minutes to make it '2022-09-10T10:30:00-07:00'. What am I missing?

2 Answers

Although there's nothing wrong with the date and strtotime functions, they force you to deal with strings and ints which makes things muddy. Instead, if you can elevate that to a higher level thing, specifically the DateTime (or DateTimeImmutable) you can reason about things easier.

$date = new DateTime('2022-09-10T09:00:00-07:00');
$date->modify('+5 minutes');
echo $date->format(DateTime::RFC3339);

// Result: 2022-09-10T09:05:00-07:00

Demo here: https://3v4l.org/FpQlf

Chris Haas' answer points in the right direction, but doesn't adequately explain what's wrong in the code from the question.

strtotime takes into account a time zone in the date expression just like DateTime does. DateTime saves this time zone correctly in the object. strtotime always converted the time zone to the UTC and a time stamp is returned as the result. Date, on the other hand, always returns the date from the server's default time zone. The following code clarifies this:

$start = '2022-09-10T00:00:00-07:00';  //TZ=-7:00 Time: 00:00

$timeStamp = strtotime($start);
echo "start as UTC: ".gmdate(DATE_W3C,$timeStamp)."\n";
//start as UTC: 2022-09-10T07:00:00+00:00

date_default_timezone_set('Europe/Berlin');  //my local timezone
echo "start as Localtime: ".date(DATE_W3C,$timeStamp)."\n";
//start as Localtime: 2022-09-10T09:00:00+02:00

The date expression $start has the time 00:00 and the time zone -07:00. The UTC time output from the time stamp has the time 07:00 (and the time zone 00:00 = UTC). When outputting with Date, the local time is then converted. Output 09:00 for the time and +02:00 for the Berlin time zone.

Demo: https://3v4l.org/v7231

Related