views:

83

answers:

2

A part of my web app involves creating 'appointments' (shifts) using a drag-and-drop selector for each day. Currently, this data is serialized to something like this:

9,10,11,12,13,14,15,16,76,77,78,298,299,300,301,302,303,304,

Where each number represents the nth half-hour of the week (so 304 is the 300th half-hour of the week, or 8am Saturday).

I then parse this on the server with Python into something a bit more sensible:

[[9,16],[76,78],[298,304]]

But then I am having trouble converting them to datetime objects neatly, mainly because of how... tacky the data is sent to the server is in the first place.

My question is this: What is the 'best' way to serialize the selected 'shifts' and convert them to datetime objects with Javascript and Python

I have a live version of the shoddy HTML/Javascript that I came up with. I am using Javascript/jQuery on the client-side, and Python/Django on the server.

+1  A: 

Well, assuming you have the code in place to extract the ranges (i.e. 1,2,3,4 is converted to [1,4]), I don't see why you cannot use standard date/time arithmetic.

from datetime import datetime, timedelta

def get_shift(start_of_week, start, end):
    """Returns a 2-tuple of datetimes"""
    HALF_HOUR = timedelta(minutes=30)
    return start_of_week + start * HALF_HOUR, start_of_week + (end + 1) * HALF_HOUR

start_of_week should be monday 00:00. To use this, you need a way of calculating "monday 00:00" for any given week.

This function returns monday 00:00 for the week containing the date passed to it. Try for instance start_of_week_containing(datetime.now()).

def start_of_week_containing(dt):
    while dt.weekday() > 0:
        dt = dt - timedelta(days=1)
    return datetime(dt.year, dt.month, dt.day, 0, 0, 0)

Full example:

start_of_week = start_of_week_containing(datetime.now())
shift_start, shift_end = get_shift(start_of_week, 4, 9)
# now shift_start and shift_end will contain datetime objects
codeape
Need to change `end` to `(end + 1)` in that last line, it looks like.
Jason Orendorff
What is start_of_week? Does start = 0 == start_of_week?
joshhunt
Edited to fix and clarify. start_of_week is monday 00:00 for a particular week.
codeape
And yes: If start == 0, the first item of the tuple returned is start_of_week.
codeape
+2  A: 

You're talking about intervals.

The best way to have an interval is a start time and a duration.

class Shift( object ):
    def __init__( self, start, length ):
         self.start= start
         self.length= length
    def __repr__( self ):
         return "Shift(%d,%d)" % ( self.start, self.length )
    def ends( self ):
         return self.start + self.length

You can serialize these objects.

[ Shift(9,6), Shift(76,2), Shift(298,6) ]

You can implement operators to compare shifts to see if they overlap or if one contains the other.

Why length? Why not end time?

It turns out that some of the math for detecting overlaps and containment seem very slightly simpler if you think of the intervals as starting at a particular time and running for given duration. I've found it slightly easier to prove there are no gaps between shifts done this way.

You want to use a "half-open" interval. The start time is included in the shift, but the end time is not included.

def contains( self, aTime ):
    return self.start <= aTime < self.start + self.length

def before( self, nextShift ):
    return self.start + self.length == nextShift.start

def after( self, prevShift ):
    return prevShift.ends() == self.start

To convert to datetime, you need a base date for the start of the week. You can then do some math to work out the shift start time. The length is (trivially) an interval.

def startDatetime( self, week_start_datetime ):
    offset= datetime.timedelta( seconds= self.start*30*60 )
    return week_start_datetime + offset

def lengthTimedelta( self ):
    return datetime.timedelta( seconds= self.length*30*60 )

def endDatetime( self, week_start_datetime ):
    return self.startDatetime( week_start_datetime ) + self.lengthTimedelta()
S.Lott
...but I still don't have any datetime objects.
joshhunt