[asterisk-dev] Calendaring API

Terry Wilson twilson at digium.com
Wed Oct 8 01:54:36 CDT 2008


> [note to future archive surfers: this syntax does not exist; it is  
> currently
> a figment of my imagination - please keep searching for what you  
> want, or
> feel free to bring this thread back from the depths.]
>
>
> core1*CLI> core show function CALENDAR_STATUS
>  -= Info about function 'CALENDAR_STATUS' =-
>
> [Syntax]
> CALENDAR_STATUS(<calendar_name>,<value>[,<time range>][,<event- 
> number>])

After a cursory glance I think I like the above format, but with some  
changes to the time range functionality.  Perhaps:
CALENDAR_STATUS(<calendar_name>,<value>[,<start-time>][,<duration>] 
[,<event-number>])

>    time range = a time range for the query, in the format of:
>
> YYYYMMDDHHMM["-<tzone-name>","-HH:MM"][&[YYYYMMDDHHMM["-<tzone- 
> name>","-HH:MM"]]
>
>            Special name "now" can replace time and timezone.
>            Special indicators "+" and "-" can be used to add or
>            subtract minutes from a given time.  If no timezone is
>            specified, Asterisk uses the timezone of the system as
>            set locally.  Any references in timezone-names to numeric
>            hour/minute offsets are assumed to be from GMT, and any
>            use of "-" and "+" characters in the timezone names are
>            considered part of the timezone name and not as modifiers.
>            If time range is omitted, assumption is that the time
>            is "now".

My initial inclination is to prefer the times just be in seconds since  
epoch.  We already have the EPOCH variable, so we wouldn't need the  
"now" keyword.  Then ranges from that are easily determined by adding  
seconds.  Time zones and date conversions could be handled with the  
STRFTIME and STRPTIME dialplan functions.  Since the dialplan already  
has these methods for handling time functions, it seems more Asterisk- 
y and interoperable to use them.  Let me see if I can translate all of  
the examples...

>           examples:
>
>            now+5
>              Looks up any events 5 minutes from this moment.

${EPOCH}, 300

>            200810061440
>              Looks up any events (using system timezone) that are
>               occuring on Oct 6, 2008 at 14:40.

${STRPTIME(200810061440,,%Y%m%d%H%M%S)}

>            now&now+30
>             Looks up any events from this moment until one half
>              hour in the future.

${EPOCH}, 1800

>            now-30&now+30
>             Looks up any events from half an hour ago to half
>              an hour in the future.

$[${EPOCH} - 1800], 3600
This and following queries involves a bit of calculation if using a  
duration field, so maybe having a start and end would be easier for  
it, but having to specify a start and endtime for querying just "right  
now" is kind of annoying.  Right now I'm envisioning not providing a  
duration as "just intersecting the start time", and maybe if 0 or a  
negative number maybe being specified meaning an open end time--all  
events after start time (not that I'm sure that is a useful query).   
Otherwise we could do the start and end time and and have an empty  
start or end make the query open (+/- infinity) on that bound.  So  
this query would be:
$[${EPOCH} - 1800], $[${EPOCH} + 1800]

>            200810061450&200810061550
>             Looks up any events for 2:50 PM until 3:50 PM, and uses  
> the
>              timezone of the local machine as the timezone modifier.

${STRPTIME(20810061450,,%Y%m%d%H%M%S)}, 3600
or
${STRPTIME(20810061450,,%Y%m%d%H%M%S)}, ${STRPTIME(200810061550,,%Y%m%d 
%H%M%S)}
>             200810061450-PDT&200810061550-PDT
>             Looks up any events for 2:50 PM Pacific Daylight Time
>              until 3:50 PM Pacific.

${STRPTIME(200810061450,America/Los_Angeles,%Y%m%d%H%M%S)}, 3600
or
${STRPTIME(200810061450,America/Los_Angeles,%Y%m%d%H%M%S)}, $ 
{STRPTIME(200810061550,America/Los_Angeles,%Y%m%d%H%M%S)}

>            200810061450-08:00&200810061550-08:00
>             Looks up any events for October 6, 2008 2:50 PM Pacific
>              until October 6, 2008 3:50 PM Pacific, but doesn't  
> consider
>              daylight savings time - just uses 8 hour offset.

${STRPTIME(200810061450,GMT-8,%Y%m%d%H%M%S)}, 3600
or
${STRPTIME(200810061450,GMT-8,%Y%m%d%H%M%S)},$ 
{STRPTIME(200810061550,GMT-8,%Y%m%d%H%M%S)}

>             now-30&200810061450-08:00-120
>             Looks up any events from half an hour in the past until
>              two hours before October 6, 2008 2:50 Pacific
>              (otherwise known as 12:50 PM Pacific)

$[${EPOCH} - 1800], $[1800 + ${STRPTIME(200810061450,GMT-8,%Y%m%d%H%M 
%S)} - 7200 - ${EPOCH}]
or
$[${EPOCH} - 1800], $[${STRPTIME(200810061450,GMT-8,%Y%m%d%H%M%S)} -  
7200]

Now, I understand that most of those look relatively ugly, but there  
are several benefits: 1) We aren't inventing yet another way to  
represent datetimes and ranges in Asterisk.  2) With STRPTIME you can  
pass in the time in any format you choose and then work with epoch  
times that are easily manipulatable via simple arithmetic.  3) Using $ 
{EPOCH} and offsets lets you completely ignore timezones and  
conversions.  4) The calendaring API internallhy does everything in  
GMT, so no more timezone processing has to be done inside the module.

Most of the above is mostly academic, one is probably never going to  
do queries in the dialplan based on specific datetimes that aren't  
actually tied to some offset from "now".  I agree with the sentiment  
of making queries flexible for people who might find a need for them  
(people are really good at using things in ways you don't anticipate),  
but implementing a new way to parse dates just inside the calendar  
module seems to me to be a lot of work for what amounts to a semantic  
difference which would need to be converted with STRPTIME anyway to be  
used with other time-related dialplan functions.

> Examples:
>
>  These examples use a calendar which has two (poorly scheduled)  
> events:
>        Oct 6, 2008 1:00 - 1:30 PM Pacific: "Get Lunch with Penny  
> Preddy"
>        Oct 6, 2008 1:15 - 1:45 PM Pacific: "Mrs. Johnson conference  
> call"
>  The calendar exists in calendar.conf as "calendar1".
>  The realtime clock at the moment of this example is 1:20 PM
> Pacific, October 6 2008.
>
>   ${CALENDAR_STATUS(calendar1,busystate)}
>     Returns "2", since there is at least one event at this moment.

Assuming that 2 is the greatest value of busystate for the two events.

>   ${CALENDAR_STATUS(calendar1,getnum)}
>     Returns "2", since there are two events active at this moment.
>
>   ${CALENDAR_STATUS(calendar1,summary)}
>     Returns "Get Lunch with Penny Preddy" as the first ordered result.
>      (see "Sorting Order..." in calendar.README)
>
>   ${CALENDAR_STATUS(calendar1,summary,,2)}
>     Returns "Mrs. Johnson conference call"
>       (see "Sorting Order..." in calendar.README)
>
>   ${CALENDAR_STATUS(calendar1,summary,now+20)}
>     Returns "Mrs. Johnson conference call" since at 1:40 we only  
> have that one
>       active event.

${CALENDAR_STATUS(calendar1,summary,$[${EPOCH} + 1200])}

>   ${CALENDAR_STATUS(calendar1,summary,now+60&now+120)}
>     Returns a null string, since there are no entries on the calendar
>       that match that time span.

${CALENDAR_STATUS(calendar1,summary,$[${EPOCH} + 3600],3600)}

> ${CALENDAR_STATUS(calendar1,busystate,now+60&now+120)}
>     Returns a null string, since there are no entries on the calendar
>       that match that time span.  Note that this is different than
>       replying with "0", which means there is an event but it is not
>       a "busy" event.

${CALENDAR_STATUS(calendar1,busystate,$[${EPOCH} + 3600, 3600)}

After going through this I think I might prefer the start/end time  
with leaving them empty for open ended queries instead of start and  
duration.  Also, one problem is that if these queries are on an  
unnamed calendar, each query would most likely be pulling back the  
information for the calendar each time, which would really suck.  It  
would be nice to come up with a way to query the range that you are  
going to be working with, then be able to access the data with  
successive calls w/o having to make separate http requests for each.   
With named calendars, we would just be querying data from within the  
timerange that is set in calendar.conf and is already cached.

On a side note, unnamed calendars would not be accessible via the  
hints interface and each call that hit them in the dialplan would most  
likely result in a new http request.  So users would need to be aware  
of how bad that would be on a busy system--from both a delay  
standpoint and a hammering your calendar server standpoint.

> From a snippet of a hypothetical calendar.README file:
>
> SORTING ORDER MULTIPLE EVENTS
>
> If there are multiple events resulting from a query that is not a
> time range and is a specific moment im time, the system will create
> an ordered list, with the events being stacked by the nearest start
> time to the given query time, nearest times to the query moment
> ordered lowest in the list.  If one or more events have the same
> start time, then those events will be sub-ordered by nearest end
> time, nearest times to the query moment ordered lowest in the list.
> If one or more of those events have the same end time, then they will
> be further sub-ordered by their UIDs, alphabetically/numerically,
> with the highest ranking members appearing lowest in the resulting
> list.
>
> If there are multiple events resulting from a query that consists of
> a time start/end range, the system will create an ordered list.
> Events that span or are equal to the starting edge of the query range
> will be ordered by their start time, earliest start times lowest on
> the list.  If one or more are equal, then sort by duration, with
> longer durations being lower on the list.  If one or more of those
> are equal, then sort alphabetically/numerically by UID, with highest
> ranking members appearing lowest in the resulting list.  The
> remaining events are sorted by earliest start time, with earlier
> start times being lower on the list.  If one or more of these are the
> same, then sort by duration, with longer durations being lower on the
> list.  If one or more of those are equal, then sort
> alphabetically/numerically by UID, with highest ranking members
> appearing lowest in the resulting list.
>
> For example, if a calendar event ("Management Retreat Meeting") spans
> from 8:00A to 8:00P, and then another event ("Lunch") spans from
> 12:00P to 1:00P, and yet another event ("Get a Soda") spans from
> 12:00P to 12:05P, then a query about 12:03P would give an ordered
> list of:
>  1: Get a Soda
>  2: Lunch
>  3: Management Retreat Meeting
>
> and a query about 12:00P-1:00P time span would give an ordered list  
> of:
>  1: Management Retreat Meeting
>  2: Lunch
>  3: Get a Soda
>
> Maximum number of stacked events is 255.
>
> If the query is a "busystate" query without a specific event-number
> provided, and there is more than 1 concurrent event, then the highest
> busystate of all of the events will be returned.

After a cursory read of the ordering stuff, it seems reasonable.

Terry



More information about the asterisk-dev mailing list