skip to Main Content

My application compares time zone names and determines whether they match. For different reasons, a different time zone can still be okay if it has the same effects. Currently, I’m doing this for Europe only. According to Wikipedia’s page about time zones, I collected this data:

$equalGroups = [
    // WET/GMT
    ['Europe/Lisbon', 'Europe/Dublin', 'Europe/London'],
    // CET
    ['Europe/Andorra', 'Europe/Belgrade', 'Europe/Berlin', 'Europe/Brussels',
        'Europe/Budapest', 'Europe/Gibraltar', 'Europe/Madrid', 'Europe/Malta',
        'Europe/Paris', 'Europe/Prague', 'Europe/Rome', 'Europe/Tirane',
        'Europe/Vienna', 'Europe/Warsaw', 'Europe/Zurich'],
    // EET
    ['Europe/Athens', 'Europe/Bucharest', 'Europe/Chisinau', 'Europe/Helsinki',
        'Europe/Kaliningrad', 'Europe/Kyiv', 'Europe/Riga', 'Europe/Sofia',
        'Europe/Tallinn', 'Europe/Vilnius'],
    // MSK
    ['Europe/Kirov', 'Europe/Moscow', 'Europe/Simferopol', 'Europe/Volgograd'],
];

(I’m fully aware that this contains disputed information, I’m not going to discuss that.)

So all names in the same subarray are considered equal for this test.

Examples:

function isEqual($a, $b)
{
    // TODO
}

isEqual('Europe/Vienna', 'Europe/Berlin')   // true (in same group)
isEqual('Europe/Malta', 'Europe/Athens')   // false (in different groups)

I could surely write an extensive set of loops and stuff to do it manually. But PHP already has a huge set of array and other functions and I’m wondering if some of those can be used to do it with less code.

PHP has the array_search function but it can only find exact matches. JavaScript has a find method that takes a predicate callback which I could combine with PHP’s in_array. But I couldn’t find such a find method for PHP. Are there elegant solutions for this? Maybe a completely different approach?

3

Answers


  1. Well, pre-process the timezones and run as many queries of isEqual as you like. This will make things faster without having to re-compute the entire timezones thing again for every new call of isEqual.

    • Run a loop on the timezones dataset and assign the subarray key index to each timezone inside an associative array.

    • Compare both the keys’ values when called via isEqual. If they are the same, return true, else, a false.

    Snippet:

    <?php
    
    $flag = false;
    $map = [];
    
    function preProcess(){
        global $flag, $equalGroups, $map;
        
        if($flag) return;
        
        $flag = true;
        
        foreach($equalGroups as $key => $group){
            foreach($group as $timezone){
                $map[ $timezone ] = $key;
            }
        }
    }
    
    
    function isEqual($a, $b){
        preProcess();
        global $map;
        return $map[ $a ] === $map[ $b ];
    }
    

    Online Demo

    Login or Signup to reply.
  2. The best performing approach would be to restructure your 2 dimensional data into a flat lookup array. PHP is great at searching by keys, and not as great at searching by values.

    Once the lookup array is populated, access the cached group number (previously the group’s index) and compare. Done with unnecessary code convolution.

    Code: (Demo)

    $map = [];
    foreach ($equalGroups as $i => $timezones) {
        $map += array_fill_keys($timezones, $i);
    }
    
    var_export($map['Europe/Vienna'] === $map['Europe/Berlin']);
    
    Login or Signup to reply.
  3. Why not go with a simple comparision loop with early return?

    class TimezoneComparator
    {
        protected const EQUAL_GROUPS = [
            // WET/GMT
            ['Europe/Lisbon', 'Europe/Dublin', 'Europe/London'],
            // CET
            ['Europe/Andorra', 'Europe/Belgrade', 'Europe/Berlin', 'Europe/Brussels',
             'Europe/Budapest', 'Europe/Gibraltar', 'Europe/Madrid', 'Europe/Malta',
             'Europe/Paris', 'Europe/Prague', 'Europe/Rome', 'Europe/Tirane',
             'Europe/Vienna', 'Europe/Warsaw', 'Europe/Zurich'],
            // EET
            ['Europe/Athens', 'Europe/Bucharest', 'Europe/Chisinau', 'Europe/Helsinki',
             'Europe/Kaliningrad', 'Europe/Kyiv', 'Europe/Riga', 'Europe/Sofia',
             'Europe/Tallinn', 'Europe/Vilnius'],
            // MSK
            ['Europe/Kirov', 'Europe/Moscow', 'Europe/Simferopol', 'Europe/Volgograd'],
        ];
    
        public function isEqual(string $a, string $b): bool
        {
            foreach (self::EQUAL_GROUPS as $group) {
                if (in_array($a, $group) && in_array($b, $group)) {
                    return true;
                }
            }
    
            return false;
        }
    }
    
    $timezoneComparator = new TimezoneComparator();
    
    echo (int)$timezoneComparator->isEqual('Europe/Vienna', 'Europe/Berlin'), PHP_EOL; // true (in same group)
    echo (int)$timezoneComparator->isEqual('Europe/Malta', 'Europe/Athens'), PHP_EOL; // false (in different groups)
    

    Output

    1
    0
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search