Как отображать преобразованные часовые пояса в «общую неделю» (с воскресенья по субботу)?

Мы создаем приложение для планирования, в котором один пользователь может установить свою «общую доступность» на все недели, как показано ниже:

Sunday | Monday | ... | Friday | Saturday 

Когда мы просим человека А в Индии указать его «доступность», мы просим его выбрать из выпадающего значения что-то вроде этого:

 12:00am 12:30am 01:00am ... 11:30pm 

Мы просим его выбрать «ОБО» время «От» (начало) и «Время до» (окончание).

Что мы SAVE в базе данных JUST эти значения (см. Следующий пример):

 user_id avail_day from to 1 Sunday 12:00:00 12:15:00 2 Monday 12:00:00 12:15:00 

Таким образом, по сути, это выглядит следующим образом (в его ЛОКАЛЬНОМ часовом поясе)

 (A) Sunday | Monday | ... | Friday | Saturday ----------------------------------------- | | | | 8:30am to 10:30am 

Как отдельная информация, мы знаем, что он выбрал работу в IST (индийское стандартное время), в настоящее время GMT + 5:30 часов, поэтому мы можем предположить, что значения, которые он выбирает, относятся к часовому поясу, который он сейчас в.

Теперь, для человека B на Восточном побережье, который сейчас GMT-4 часа (EDT), на этот раз будет фактически

 Friday, 23:00:00 to Saturday, 01:00:00 

Нам нужна помощь в определении того, как:
(a) конвертировать более раннее «текстовое значение» лица A в IST в локальное значение лица EST (ПРИМЕЧАНИЕ, что мы знаем JUST день и часы доступности как значения TEXT)
(b) И тогда нам нужно выяснить, как отобразить его на «стандартной неделе», начинающейся в воскресенье и заканчивая в субботу. То, что мы хотим отобразить, должно быть примерно таким:

 (B) Sunday | Monday | ... | Friday | Saturday -------------------------------------------------------------- | | | 11:00pm to 12:00am | 12:00am to 1:00am 

Любые умные способы преобразования (A) в (B)?


Код Artefacto превращен в общую функцию (вариант 2)

 // This function should be used relative to a "from_date" // The $from_timebegin and $from_timeend MUST be for the same day, not rolling over to the next function shift_timezones_onweek3($from_timezone, $from_date, $from_timebegin, $from_timeend, $to_timezone) { $tz1 = new DateTimezone($from_timezone); $datetime1 = new DateTime("$from_date $from_timebegin", $tz1); $datetime2 = new DateTime("$from_date $from_timeend", $tz1); $interval = $datetime1->diff($datetime2); $indiaAvail = array( array($datetime1, $datetime2) ); $tz2 = new DateTimezone($to_timezone); //convert periods: $times = array_map( function (array $p) use ($tz2) { $res = array(); foreach ($p as $d) { $res[] = $d->setTimezone($tz2); } return $res; }, $indiaAvail ); $res = array(); foreach ($times as $t) { $t1 = reset($t); $t2 = next($t); if ($t1->format("d") == $t2->format("d")) { $res[$t1->format("l")][] = $t1->format("g:ia") . " to ". $t2->format("g:ia"); } else { $res[$t1->format("l")][] = $t1->format("g:ia") . " to 11:59pm"; $res[$t2->format("l")][] = "12:00am to ". $t2->format("g:ia"); } } return $res; } 

Ваш вопрос не имеет смысла, учитывая будние дни в вакууме. Эти будни должны быть фактическими днями, потому что правила преобразования времени изменяются в течение года (DST) и на протяжении многих лет (политики иногда изменяют часовые пояса и / или дату начала / окончания DST).

Тем не менее, предположим, что у вас есть недельный план доступности на первую неделю августа, здесь определяется как неделя с 1 августа по 7 августа 2010 года:

 <?php $tz1 = new DateTimezone("Asia/Calcutta"); $indiaAvail = array( new DatePeriod(new DateTime("2010-08-01 10:00:00", $tz1), new DateInterval("PT2H15M"), 1), new DatePeriod(new DateTime("2010-08-07 03:00:00", $tz1), new DateInterval("PT8H"), 1), ); $tz2 = new DateTimezone("America/New_York"); //convert periods: $times = array_map( function (DatePeriod $p) use ($tz2) { $res = array(); foreach ($p as $d) { $res[] = $d->setTimezone($tz2); } return $res; }, $indiaAvail ); $res = array(); foreach ($times as $t) { $t1 = reset($t); $t2 = next($t); if ($t1->format("d") == $t2->format("d")) { $res[$t1->format("l")][] = $t1->format("g:ia") . " to ". $t2->format("g:ia"); } else { $res[$t1->format("l")][] = $t1->format("g:ia") . " to 11:59pm"; $res[$t2->format("l")][] = "12:00am to ". $t2->format("g:ia"); } } print_r($res); 

дает

 массив
 (
     [Sunday] => Array
         (
             [0] => 12:30 утра до 2:45 утра
         )

     [Пятница] => Массив
         (
             [0] => с 17:30 до 23:59
         )

     [Суббота] => Массив
         (
             [0] => 12:00 с 1:30 утра
         )

 )

Это может привести к тому же дни недели корзины, которые на самом деле разные дни, но, очевидно, нет способа избежать этого, не указывая явным образом день (или добавляя что-то вроде «Суббота (неделя после)» и «Суббота (неделя раньше)». быть тем, что вы хотите.

Как насчет этого:

  • Попросите пользователя предоставить свой часовой пояс (возможно, вы даже можете обнаружить его, установив местоположение пользователя на основе IP-адреса, но пользователь все равно может захотеть его изменить)
  • Преобразуйте предоставленное время на веб-сервере и сохраните его.
  • При отображении времени конвертирования в часовой пояс просмотра пользователя.

Пакет Pear :: Date может помочь вам в этом:
http://www.go4expert.com/forums/showthread.php?t=3494

Надеюсь, это поможет, Мануэль

Используйте встроенный класс времени DateTime для преобразования часовых поясов. Сохраните данные в формате UTC в базе данных. При отображении стандартного недельного графика используйте локальный часовой пояс. Чтобы обрабатывать ± 23 часа разницы в часовом поясе, вам нужно будет запросить 9 дней (± 1 дней) из БД перед конверсией.

Изменить. Чтобы преобразовать время в локальное время текущего пользователя, вам нужно получить часовой пояс для каждого события. Присоедините запланированные события к пользовательской информации для пользователя, который сделал это событие. Таким образом, у вас будет часовой пояс, из которого можно конвертировать в часовой пояс пользователя.

Следующий псевдоязычный PHP покажет:

  $usersTZ = new DateTimeZone('EDT'); $now = new DateTime("now", $usersTZ); $today = $now->format("Ymd"); $sql = "SELECT A.date, A.start, A.end, B.tz FROM schedule A JOIN users B ON (schedule.user_id = users.user_id) WHERE A.date BETWEEN '$sunday_minus_1_day' AND '$saturday_plus_1_day' ORDER BY A.date, A.start"; foreach ($db->dothequery($sql) as $event) { $eventTZ = new DateTimeZone($event['tz']); $eventStartDate = new DateTime("$today {$event['start']}", $eventTZ); $eventStartDate->setTimeZone($usersTZ); $eventEndDate = /* do the same for the end date */ if ($eventStartDate->format("Ymd") != $eventEndDate->format("Ymd")) { /* create 2 events */ } else { /* save the event to list of events with the new start and end times */ } } /* sort events, their order may be different now */ 

Конечно, все было бы намного проще, если бы вы могли сохранить время начала и окончания с TZ в БД и позволить БД выполнить всю тяжелую работу для вас.