Reputation: 3337
Every question I have read deals with converting a DateTime
object from one timezone to another and the process is usually the same:
$date->setTimezone($newTimezone);
$date->format($format);
$date->setTimezone($oldTimezone);
or as a batch process, looping through the first two items as necessary, or changing date_default_timezone_set
as necessary.
What I have is a widget that displays times of appointments in multiple timezones and I am finding that I have to either:
DateTime
objects and change each and every one of them when the due date arrives in the widget, orDateTime
object but iterate through each timezone required, actively change it to each timezone, display it, rinse and repeat.What I am trying to do is have ONE DateTime
object set to the users timezone and never changing it, but displaying it relevant to the other timezones. I know this is not supported out-of-the-bag but how can I best achieve this?
I don't like managing multiple DateTime
objects, it's simply not needed. What I would prefer is a method like:
DateTime::formatForTimezone($format, $timezone)
or
DateTime::inTimezone($timezone)
which I could then use:
$date->inTimezone($timezone)->format($format)
and $date
's timezone would remain unchanged. I could just iterate through the required timezones and the original object would be preserved.
I did write a function to achieve this, but I had forgotten that all objects are passed by reference so that when my function returned the objects timezone had changed which I was required to revert and so the function generated more work (so I scrapped it). But it looked something like:
function DateInTimezone(DateTime $date, DateTimeZone $tz, $format){
$backup = $date->getTimezone();
$date->setTimezone($tz);
$output = $date->format($format);
$date->setTimezone($backup);
return $output;
}
which I have just now made a class extends
. Basically the same thing, just cutting out one variable.
class DateTimeForTimezone extends DateTime {
public function formatForTimezone($format, DateTimeZone $tz){
$backup = $this->getTimezone();
$this->setTimezone($tz);
$output = $this->format($format);
$this->setTimezone($backup);
return $output;
}
}
I am the first to admit, I don't fully comprehend OOP, any pointers would be helpful
For example, this does what I'm after:
CODE:
echo '<pre>';
function p($arg){
echo "$arg\n";
}
class DateTimeForTimezone extends DateTime {
public function formatForTimezone($format, DateTimeZone $tz){
$backup = $this->getTimezone();
$this->setTimezone($tz);
$output = $this->format($format);
$this->setTimezone($backup);
return $output;
}
}
$f = "Y-m-d H:i:s A T O e";
$date = new DateTimeForTimezone('now',new DateTimeZone('UTC'));
$tzAUS = new DateTimeZone("Australia/Sydney");
$tzBKK = new DateTimeZone("Asia/Bangkok");
$tzLOS = new DateTimeZone("America/Los_Angeles");
// output ending with '*' should all be UTC
p($date->format($f."*"));
p($date->formatForTimezone($f,$tzLOS));
p($date->format($f."*"));
p($date->formatForTimezone($f,$tzAUS));
p($date->format($f."*"));
p($date->formatForTimezone($f,$tzBKK));
p($date->format($f."*"));
OUTPUT:
2017-09-29 23:37:20 PM UTC +0000 UTC*
2017-09-29 16:37:20 PM PDT -0700 America/Los_Angeles
2017-09-29 23:37:20 PM UTC +0000 UTC*
2017-09-30 09:37:20 AM AEST +1000 Australia/Sydney
2017-09-29 23:37:20 PM UTC +0000 UTC*
2017-09-30 06:37:20 AM +07 +0700 Asia/Bangkok
2017-09-29 23:37:20 PM UTC +0000 UTC*
I have achieved my goal but technically the timezone is changed, it's just reverted back.
Am I just looking at this wrong? Is there a better way to achieve what I'm after?
Upvotes: 1
Views: 96
Reputation: 39434
You're doing it correctly. Zone isn't just about display, it's an integral part of a time's state. You can't work with a time value, like "2017-05-13T21:54:00", without knowing its zone. Forget calculations, forget comparisons, until you know the zone. And don't for a minute think that changing the time zone is trivial. It's notoriously complicated. So, keep on as you are.
If you want to loop this without managing objects, just do:
$date = new DateTime('2017-05-13T21:54:00', new DateTimeZone('America/New_York'));
$zones = [
new DateTimeZone('Antarctica/Casey'),
new DateTimeZone('Europe/Helsinki'),
];
foreach ($zones as $zone) {
echo (clone $date)->setTimezone($zone)->format('c') . PHP_EOL;
}
Upvotes: 1