views:

59

answers:

3

Hi,

We are building a scheduling application wherein one user may set his "general availability" for all weeks like the following:

Sunday | Monday | ... | Friday | Saturday

When we ask a person A in India to indicate his "availability", we ask him to select from a drop down of values something like this:

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

We ask him to select BOTH the "From" time (starting) and the "Till" time (ending).

What we SAVE in the database is JUST these values (see the following example):

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

So, in essence, it looks like the following (in his LOCAL time zone)

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

As a separate piece of information, we know that he has selected to work in the IST (Indian Standard Time), which is presently GMT + 5:30 hours, so we can assume that the values he chooses are FOR the time zone he's presently in.

Now, for a person B on the East Coast, which is presently GMT - 4 hours (EDT), this time would be actually

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

We need help in figuring out how to:
(a) convert the earlier "text value" of the person A in IST to the local value of the EST person (NOTE that we know JUST the day and hours of availability as TEXT values)
(b) AND, then, we need to figure out how to display it on a "Standard week" beginning on a Sunday and ending on a Saturday. What we want displayed should be something like this:

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

Any smart ways of converting (A) into (B)?


Artefacto's code made into a generic function (Revision 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;
}
A: 

Hi!

How about this:

  • Ask user to provide his time zone (maybe you can even detect it by getting the user's location based on IP address, but the user still might want to change it)
  • Convert the provided time to you webserver's time and save it.
  • When displaying the time convert to the viewing user's time zone.

The Pear::Date package may help you doing this:
http://www.go4expert.com/forums/showthread.php?t=3494

Hope this helps, Manuel

sprain
Please see comment made to jmz
DrMHC
A: 

Use PHP's build-in DateTime class to do timezone conversions. Save the data in UTC to the database. When displaying your standard week schedule, use local timezone. To handle ±23 hours of timezone differences, you'll have to query 9 days (±1 days) from the DB before conversion.

Edit: To convert times to current user's local time, you need to get the timezone of each event. Join the scheduled events to user information for the user who made the event. This way you'll have the timezone from which to convert to the user's timezone.

The following pseudoish PHP will show:

 $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 */

Of course, it would all be a lot simpler if you could save the start and end times with TZ to the DB and let the DB do all the hard work for you.

jmz
The time zone conversion is NOT a problem. The problem is doing it from "what"... the data we have is JUST input on the local "time" availability for a general week.
DrMHC
Make the local time zone a setting for each user, or use GeoIP to get their country/state and derive from that.
jmz
No no jmz - I'm afraid you're not getting the problem that I've specified above. This has nothing to do with geo/IPs at all. Please read the question above again...
DrMHC
Oh, you mean the splitting of a single entry to two days? If an entry has it's ending time less than it's starting time, then split it to two entries. Or if you get dates along with the times, compare the dates to know if you need to split an event. You most likely need to do this in PHP.
jmz
Hi jmz - revised the description to make myself clearer... :)
DrMHC
Hi DrMHC - I revised my answer.
jmz
A: 

Your question doesn't make sense considering weekdays in the vacuum. These weekdays must be actual days, because the time conversion rules change along the year (DST) and through the years (politicians sometimes change the timezones and/or the date in which DST starts/ends).

That said, let's say you have you have a week availability plan for the first week of August, here defined as the week Aug 1 to Aug 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);

gives

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
        )

)

This may put in the same basket weekdays that are actually different days, but there's obviously no way to avoid it without explicitly indicating the day (or adding something like "Saturday (week after)" and "Saturday (week before)". This appears to be what you want, though.

Artefacto
This actually looks great! I still need to run some tests on it, but the sample output you showed looks ideal!
DrMHC
Just thinking about it some more... will this code also allow "rolling over" from Saturday end to Sunday beginning in the "viewing" timezone? Eg an event begins at whatever time elsewhere, but translates into Saturday night from 11pm to Sunday morning at 1:00am - will the above code handle that fine?
DrMHC
@DrMHC Sure, but it can put in the "Sunday" basket periods that belong to different weeks. See the last paragraph. btw, this requires PHP 5.3, at least
Artefacto
Hi Artefacto - I parameterized your code (see main question) - can you comment if there are any issues you can see in my approach?
DrMHC
Hi Artefacto - hope you have a chance to look at this... need your expertise!
DrMHC
@Future visitors - have a look at the edited question which contains this as a parameterized function...
DrMHC