2

In Drupal 6 user timezones are stored as second offset, such as: -3600. In Drupal 7 it's the timezone string, eg: Europe/Berlin. I would to migrate users with their timezone setting to D7, but it's not obvious how to convert timezone offsets to strings.

My current solution is to create a full mapping table built from the timezone strings but I'm sure it's not the most elegant:

$d6_offset = -3600; // Input.
$zones = timezone_identifiers_list();
foreach ($zones as $zone) {
  $offset = format_date(time(), 'custom', 'Z', $zone);
  if (!isset($map[$offset])) {
    $map[$offset] = $zone;
  }
}
$d7_timezone = $map[$d6_offset]; // Output.

Do you know a better workflow?

1

I would use the following code.

$map = array();

foreach (timezone_identifiers_list() as $zone) {
  if ($timezone = timezone_open($zone)) {
    if ($datetime = date_create("now", $timezone)) {
      if (($offset = $timezone->getOffset($datetime)) !== FALSE && !isset($map[$offset])) {
        $map[$offset][] = $zone;
      }
    }
  }
}

Keep in mind that the same offset is used for different timezone identifies. Showing just an identifier for each offset would be less useful for users.

For example, for Europe you would show the following list. (The list is partial.)

  • Europe/Amsterdam 7200
  • Europe/Athens 10800
  • Europe/Dublin 3600

In your list, Europe/Rome, Europe/Madrid, Europe/Malta, and Europe/Kiev would not appear because the offset is already used for the three entries I shown.

A better code would the following one.

function mymodule_get_timezones() {
  $map = &drupal_static(__FUNCTION__);

  if (isset($map)) {
    return $map;
  }

  foreach (timezone_identifiers_list() as $zone) {
    if ($timezone = timezone_open($zone)) {
      if ($datetime = date_create("now", $timezone)) {
        if (($offset = $timezone->getOffset($datetime)) !== FALSE && !isset($map[$offset])) {
          $map[$offset][] = $zone;
        }
      }
    }
  }

  return $map;
}

As side note, I would not use format_date() if you use "custom" as date format, and you are not interesting in translating the returned date. In such case, the following code that is executed from format_date() is extra, and useless, for you.

  // Encode markers that should be translated. 'A' becomes '\xEF\AA\xFF'.
  // xEF and xFF are invalid UTF-8 sequences, and we assume they are not in the
  // input string.
  // Paired backslashes are isolated to prevent errors in read-ahead evaluation.
  // The read-ahead expression ensures that A matches, but not \A.
  $format = preg_replace(array('/\\\\\\\\/', '/(?<!\\\\)([AaeDlMTF])/'), array("\xEF\\\\\\\\\xFF", "\xEF\\\\\$1\$1\xFF"), $format);

  // Call date_format().
  $format = date_format($date_time, $format);

  // Pass the langcode to _format_date_callback().
  _format_date_callback(NULL, $langcode);

  // Translate the marked sequences.
  return preg_replace_callback('/\xEF([AaeDlMTF]?)(.*?)\xFF/', '_format_date_callback', $format);

In the case I described, that code can be replaced with the following one.

return date_format($date_time, $format);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.