Как отобразить преобразованные часовые пояса в «общую неделю» (с воскресенья по субботу)? - PullRequest
1 голос
/ 02 августа 2010

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

Sunday | Monday | ... | Friday | Saturday

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

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

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

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

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 (ОБРАТИТЕ ВНИМАНИЕ, что мы знаем ПРОСТО день и часы доступности как значения TEXT)
(б) И, затем, мы должны выяснить, как отобразить его на «Стандартной неделе», начинающейся в воскресенье и заканчивающейся в субботу. То, что мы хотим отобразить, должно выглядеть примерно так:

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

Какие-нибудь умные способы преобразования (A) в (B)?


Artefacto * Код 1029 *, преобразованный в универсальную функцию (Редакция 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;
}

Ответы [ 3 ]

1 голос
/ 02 августа 2010

Ваш вопрос не имеет смысла, учитывая рабочие дни в вакууме. Эти рабочие дни должны быть фактическими днями, потому что правила преобразования времени меняются по году (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);

дает

Array
(
    [Sunday] => Array
        (
            [0] => 12:30am to 2:45am
        )

    [Friday] => Array
        (
            [0] => 5:30pm to 11:59pm
        )

    [Saturday] => Array
        (
            [0] => 12:00am to 1:30am
        )

)

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

0 голосов
/ 02 августа 2010

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

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

Будет показан следующий псевдоиш PHP:

 $usersTZ = new DateTimeZone('EDT');
 $now = new DateTime("now", $usersTZ);
 $today = $now->format("Y-m-d");
 $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("Y-m-d") != $eventEndDate->format("Y-m-d")) {
          /* 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 в БД и позволить БД сделать всю тяжелую работу за вас.

0 голосов
/ 02 августа 2010

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

  • Попросить пользователя указать его часовой пояс (возможно, вы даже можете определить его, узнав местоположение пользователя по IP-адресу, но пользователь все равно может захотеть изменить его)
  • Конвертируйте предоставленное время в время вашего веб-сервера и сохраните его.
  • При отображении времени конвертируйте в часовой пояс пользователя, просматривающего.Пакет может помочь вам в этом:
    http://www.go4expert.com/forums/showthread.php?t=3494

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...