Dahab
Dahab

Reputation: 514

PHP DateTime Manager based on locale

I am working on a project that support multi countries, so far it is European counties.

I store date in datebase with UTC timezone for all countries. When i select i want to show the corresponding time for each country. For example if saved datetime is [2016-12-20 07:00:00] UTC

So for Germany should be 2016-12-20 08:00:00 and for UK should 2016-12-20 07:00:00

So instead of checking which country is it

if($country === 'DE'){
   return (new DateTime($time))->setTimeZone(new DateTimeZone('Europe/Berlin'));
}else if ($country === 'UK'){
return (new DateTime($time))->setTimeZone(new DateTimeZone('Europe/London'));
}

etc.

I am thinking about creating a DateTime Manager to manage setting the TimeZone.

I came up with the following try

<?php

namespace App\Library\Values;

use App\Library\System\Locale;

final class DateTimeImmutableTimeZone extends \DateTimeImmutable
{
    /**
     * @var array
     */
    private $timezones = [
        'GB' => 'Europe/London',
        'DE' => 'Europe/Berlin',
        'FR' => 'Europe/Paris',
        'ES' => 'Europe/Madrid',
        'IT' => 'Europe/Rome',
        'SE' => 'Europe/Stockholm',
        'NL' => 'Europe/Amsterdam',
        'BE' => 'Europe/Brussels',
        'DK' => 'Europe/Copenhagen',
    ];

    /**
     * @param Locale $locale
     */
    public function __construct(Locale $locale)
    {
        $this->setTimezone(
            new \DateTimeZone($this->timezones[(string)$locale->country()])
        );
    }
}

But when i try to: var_dump(new DateTime()); //output:

DateTimeImmutable {#1673
  +"date": "2016-12-20 07:00:00"
  +"timezone_type": 3
  +"timezone": "UTC"
}

var_dump(new DateTimeImmutableTimeZone(new Locale())); //output:

DateTimeImmutable {#1673
  +"date": "2016-12-20 07:00:00"
  +"timezone_type": 3
  +"timezone": "UTC"
}

I am not sure what is wrong? in addition i am not sure if this a write approach to have such TimeZone manager class

Upvotes: 2

Views: 880

Answers (2)

Matt Johnson-Pint
Matt Johnson-Pint

Reputation: 241673

I'll address this part of your question:

... i am not sure if this a write approach to have such TimeZone manager class

No, it is not the right approach. Many countries have more than one time zone. You cannot select time zone from country alone. Examples: US, RU, AU, BR, MN many others.

Even within the list you provided, ES (Spain) has two time zones. Europe/Madrid applies on the mainland, and Atlantic/Canary applies for the Canary Islands. They are an hour apart.

Additionally, time zone and locale are two completely separate and unrelated subjects. A locale such as en-US means that I would like to use the English language with American (US) dialect and conventions. It does NOT mean I am located in the United States. I very may well be traveling and located in Japan, for example.

Upvotes: 0

cb0
cb0

Reputation: 8613

If you just want to have a class which takes care of creating different DateTime objects depending on the country code try this.

It's a modified version of your code without the use of immutable classes and Locale.

class DateTimeManager
{
    /**
     * @var array
     */
    private $timezones = [
        'GB' => 'Europe/London',
        'DE' => 'Europe/Berlin',
        'FR' => 'Europe/Paris',
        'ES' => 'Europe/Madrid',
        'IT' => 'Europe/Rome',
        'SE' => 'Europe/Stockholm',
        'NL' => 'Europe/Amsterdam',
        'BE' => 'Europe/Brussels',
        'DK' => 'Europe/Copenhagen',
    ];

    private $currentLocal;

    /**
     * @param string country
     */
    public function __construct($country)
    {
        if(!in_array($country, array_keys($this->timezones))){
            throw new InvalidArgumentException(sprintf("Country %s not found.", $country));
        }
        $this->currentLocal = $this->timezones[$country];
    }

    /**
     * Return a new DateTime object for the timestamp
     * @param $time
     *
     * @return \DateTime
     */
    public function getDateTime($time = null){
        return (new DateTime($time))->setTimezone(new DateTimeZone($this->currentLocal));
    }
}

Now the results of the var_dump would look like this:

var_dump(new Datetime());
var_dump((new DateTimeManager("DE"))->getDateTime());
var_dump((new DateTimeManager("GB"))->getDateTime());

object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2016-12-20 17:42:03.860627"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(13) "Europe/Berlin"
}
object(DateTime)#2 (3) {
  ["date"]=>
  string(26) "2016-12-20 17:42:03.860854"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(13) "Europe/Berlin"
}
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2016-12-20 16:42:03.861053"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(13) "Europe/London"
}

For your second question it's not that easy. Depends on what exactly you want to do with the class and in which context it is used.

It wouldn't be to bad to write just the line from my getDateTime function every time you need something like this. But in a larger code base it could make things more easy for you.

Upvotes: 0

Related Questions