[icalendar-dev] util.py/tools.py uid patches
Alan Milligan
alan at balclutha.org
Fri Dec 30 16:43:48 CET 2005
Max M wrote:
> Alan Milligan wrote:
>
>> Similarly, the vDatetime stuff could also support these __add__ and
>> __sub__ features to behave as full first-class citizens (a __len__
>> function would also help in this regard). Any thoughts on getting these
>> into the next release??
>>
>
> I tried that approach at first, but it wasn't practical. datetime
> arithmetic returns subclasses of the same type as itself.
>
> So to be able to do datetime arithmetic in vDateTime, vDate, vDuration
> etc. they would need to subclass their corresponding datetime classes,
> and overwrite all the arithmetic methods, just to do the arithemtic. And
> then they would still need to be converted to datetime in most cases.
> And if you need to do arithmetic with objects of a third type you cannot
> do that either. So for each kind of datetime subclass you will need to
> do those conversions. Which makes it a squared problem to the number of
> different datetime types.
I must say, I don't see the problem you're describing. That would be
somewhat synonymous with multiple dispatch in a statically typed
language - see Scott Myer's classic "More Effective C++" for an
excellent treatise on this ;)
Besides, this is a closed system - unless someone is considering
describing geological or quantum physics timeframes of course, we have
all the types we expect ;)
>
> so I decided that it would be smarter to simply return datetime objects
> and then do the arithmetic in those.
Well, we definitely need proper arithmetic for the future. For example,
adding a vDuration to a vEvent would be fairly common in any project
management application. Similarly, one could wish to know how long 50%
of a vEvent represented as a vDuration say ...
However, there is no clean API returning these datetime objects yet. In
many cases, I'm being surprised by the dt member being of an
incompatible datetime type, and I'd rather call API methods than rely
upon an implementation artifact in the first place.
>
> I think that the simplest and most pratical approach would be to make a
> small library of functions, or perhapse better, an adapter for doing
> arithmetics and conversions for objects supporting the datetime
> interfaces. That library should then allways return straight datetime
> types. Pseudocode::
>
>
>>>> dt1 = DTWrapper(vDateTime())
>>>> dt2 = DTWrapper(SomeOtherSubclass())
>>>> dt1 + dt2
> datetime.datetime()
>
I don't think that this is necessary, nor advisable, as we've excellent
run-time dispatch working for us in Python and DTWrapper is going to
have the same ugly construct you'd write in existing classes anyway.
I actually took the effort to do a quick UML scribble for the icalendar
Date/Time classes and have some suggestions for moving ahead.
Firstly, there is an anomaly within the vTime class directly inheriting
from time. In many respects, all of these classes could inherit from
their datetime equivalent, and it's certainly necessary to provide an
icalendar abstraction layer over these classes. I have a preference for
the containment model you've mostly used, simply because we might find
ourselves surprised by default arithmetic operations in these
superclasses, which would also need to be overridden to return correct
types regardless. I'd suggest making vTime contain a time instance for
consistency more than anything ;)
vDate, vDateTime, vTime, vDDDTypes all should implement an as_datetime()
function from which to provide common implementation to perform
arithmetic. vDuration, vPeriod should have an as_timedelta() function
similarly (maybe even start_datetime, end_datetime for vPeriod). With
these, one can explicitly map to/from icalendar to datetime API's if
required.
If one was to be a little lazy, one could implement a base class for
vDate, vDateTime, vTime, vDDDTypes with:
def __sub__(self, other):
return vDuration(self.as_datetime(), other.as_datetime())
But I think things may be more subtle than that, and stronger type
checking may be a good thing.
I've made a cursory mapping of the kinds of arithmetic I see as worthy
of implementing immediately:
vDate - vDate = vDuration
vTime - vTime = vDuration
vDatetime -[vDatetime|vDate|vTime] = vDuration
vDDDType - [vDDDType|vDatetime|vDate|vTime] = vDuration
vDate +- vDuration = vDate || TypeError
vDatetime +- vDuration = vDatetime
vTime +- vDuration = vTime || TypeError
vDDDType +- vDuration = vDDDType
vDuration +- vDuration = vDuration
vDuration */ [int/float/decimal] = vDuration
vUTCOffset +- vUTCOffset = vUTCOffset
vUTCOffset */ [int/float/decimal] = vUTCOffset ??
vPeriod */ [int/float/decimal] = vPeriod ??
I'm sure that there are other useful arithmetic interations with other
types, but I'm quite confident that *meaningful* results from operations
with other types apply for a *very* limited group of types (which can be
discovered and extended over time). Seeing this well-described in
(admittedly rather ugly if isinstance.. then.. elif ... else raise
TypeError constructs) the class definitions would provide the basic
contract for these features.
I currently have a lot of ugliness in PloneiCalendar because of the
vDDDType - vDDDType stuff requiring hacked into this code to determine
event durations for display on calendars. I'd be happy to provide
patches for something along the lines of what I've outlined here,
incorporating the thoughts of participants on this list of course.
I know its early days for this library, but we do need to evolve this
type of functionality so it can elegantly express a wide range of
calendaring problem domains.
Thoughts?
Alan
More information about the icalendar-dev
mailing list