Hi Jerome,
Most of the people that could give you the feedback you are requesting
are currently working hard to get version 1.1 out the door. If you
wait a couple of weeks for the dust to settle on v1.1, you may find
you get a better response to your requests for review and assistance.
Yours,
Russ Magee %-)
On Mon, May 25, 2009 at 9:27 AM, Jerome Leclanche <ady...@gmail.com> wrote:
>
> Hi Yuri, thanks for the fixes. Two questions:
>
> - Why mention *args at all (l20,21) if it's to assert they don't exist?
Just to show friendlier user message.
Without args TimeDelta(x) is TimeDelta(days=x) so it tells that what
you passed in can't be in day component.
This was not very clean solution, I just hadn't time to figure out the best way.
datetime.timedelta __new__ method shall have the following signature:
def datetime.timedelta(days=0, seconds=0, microseconds=0): pass
We need to acquire data from "12h 30min" and Decimal("7260000") and
datetime.timedelta and "0" in the most pretty way. Of course the
prettiest is TimeDelta(x).
But if data is days, and is int, say "5", we should let existing code work.
I didn't manage to solve this puzzle in those 5 minutes I had for it.
TimeDelta(from=None, days=0, seconds=0, microseconds=0)
will break days handling if anyone will change the datetime.timedelta
into TimeDelta.
So, the best I found was something like
TimeDelta(*args, days=0, seconds=0, microseconds=0) and processing
args by myself.
But since I hadn't much time, I asserted *args to make sure I'm not
using TimeDelta().
That's how I forgot about days handling idea with TimeDelta(5, 3, 1).
After few days passed, I tend to think the best is the most explicit:
TimeDelta(days=0, seconds=0, microseconds=0, from=None)
Changing gist now.
> - Any idea where to put the TimeDelta class? I still don't believe it
> belongs in django.widgets, but I'm not familiar enough with the
> structure to know where to put it.
Somewhere in django.utils, I believe, but from_timetuple method should
move into constructor too, and a single line should stay in
from_timetuple.
> Cheers, I'll try the patch tomorrow.
>
> Jerome
>
> On Mon, May 25, 2009 at 4:12 AM, Yuri Baburov <bur...@gmail.com> wrote:
>>
>> Hi Adys,
>>
>> I solved this problem, wrapping datetime.timedelta into custom TimeDelta.
>> Now everything works: http://gist.github.com/117307
>>
>> Also altered microseconds in one month value so 12 * month are equal to 1 year.
>> This fixes "13m" bug (breaking into smaller parts incl. microseconds).
>> "31d" bug is still there.
Any idea if "31d" bug should be fixed?
On Mon, May 25, 2009 at 9:27 AM, Jerome Leclanche <ady...@gmail.com> wrote:
>
> Hi Yuri, thanks for the fixes. Two questions:
>
> - Why mention *args at all (l20,21) if it's to assert they don't exist?
Just to show friendlier user message.
Without args TimeDelta(x) is TimeDelta(days=x) so it tells that what
you passed in can't be in day component.
This was not very clean solution, I just hadn't time to figure out the best way.
datetime.timedelta __new__ method shall have the following signature:
def datetime.timedelta(days=0, seconds=0, microseconds=0): pass
We need to acquire data from "12h 30min" and Decimal("7260000") and
datetime.timedelta and "0" in the most pretty way. Of course the
prettiest is TimeDelta(x).
But if data is days, and is int, say "5", we should let existing code work.
I didn't manage to solve this puzzle in those 5 minutes I had for it.
TimeDelta(from=None, days=0, seconds=0, microseconds=0)
will break days handling if anyone will change the datetime.timedelta
into TimeDelta.
So, the best I found was something like
TimeDelta(*args, days=0, seconds=0, microseconds=0) and processing
args by myself.
But since I hadn't much time, I asserted *args to make sure I'm not
using TimeDelta().
That's how I forgot about days handling idea with TimeDelta(5, 3, 1).
After few days passed, I tend to think the best is the most explicit:
TimeDelta(days=0, seconds=0, microseconds=0, from=None)
Changing gist now.
> - Any idea where to put the TimeDelta class? I still don't believe it
> belongs in django.widgets, but I'm not familiar enough with the
> structure to know where to put it.
Somewhere in django.utils, I believe, but from_timetuple method should
move into constructor too, and a single line should stay in
from_timetuple.
> Cheers, I'll try the patch tomorrow.
>
> Jerome
>
> On Mon, May 25, 2009 at 4:12 AM, Yuri Baburov <bur...@gmail.com> wrote:
>>
>> Hi Adys,
>>
>> I solved this problem, wrapping datetime.timedelta into custom TimeDelta.
>> Now everything works: http://gist.github.com/117307
>>
>> Also altered microseconds in one month value so 12 * month are equal to 1 year.
>> This fixes "13m" bug (breaking into smaller parts incl. microseconds).
>> "31d" bug is still there.
Any idea if "31d" bug should be fixed?
--
I'll freely admit that this isn't perfectly intuitive either, but I
think it's much more natural than the current proposal. I have a
slightly modified version of my original patch that works a bit better
now, and I'm working on a JavaScript helper like the current TimeField
uses in the admin, which should help relieve the intuitiveness
problem.
More specifically, can someone explain to me just what problems are
solved by adding a custom TimeDelta class? I can only see two benefits
to it: it accepts years and months as units and it maps the new syntax
into meaningful values. I've already spoken on the syntax issue, but
I'd like to point out that accepting years and months is a very bad
idea.
Basically, there are two ways to deal with years and months, depending
on what situation you're trying to use them in. The first is to not
try to flatten it out to a specific value until applied to a reference
date. This is the approach used by calendar applications, for
instance, when you apply a yearly repeating rule with a start date or
set an alarm for one month in advance of a given event. There are
known reference dates to work with, so years and months can be
calculated accurately.
The other approach is to assign some approximate value to years and
months, which is especially useful when *not* dealing with reference
dates. For example, you might use this approach to describe a
university degree program that takes four years or a prison sentence
that lasts 6 months. When speaking in generic terms, these
approximations are appropriate, but only because they're abstract in
our minds. They're never given an absolute length of time that can be
collapsed to days, hours, minutes or seconds. That can only happen
once a true date can be assigned.
What this ticket is doing, however, is trying to formalize the second
approach by explicitly stating some approximate values for years and
months. The intent is admirable, but it's ultimately doomed. What
you're left with is a "solution" that passably works for the second
situation, but outright fails for the first. When a custom TimeDelta
with years and months is applied to a known date, the result will
nearly always be incorrect. All it really does is formalize something
that shouldn't be formalized anyway.
The third option, which is used by Python and many other computing
systems, is to take years and months out of the equation entirely.
Sure, it's a reduction in functionality, but the benefit is that what
remains *actually works*. Weeks are the largest unit of time that can
be accurately collapsed to seconds on its own and applied to date
calculations in all situations. Thus, Python's timedelta supports
weeks as the largest available unit.
I saw this issue raised on the ticket, with the response of, "I just
wanted to get the implementation in. It's easier to remove than to
add-on." Unfortunately, there have been two more patches from the same
author and the year and month support remains. I hope I've explained
the situation well enough now that we can forget about years and
months in future patches.
I'll address the question of input format once I have a new patch up
and running.
-Gul
My only beef here is that Yuri did mention it, with reasonable
justification in the ticket, and you did acknowledge that it could be
removed, yet it remained. I can understand the tendency to support as
much as possible until someone reigns you in, but once someone does,
it's best to listen. But, I've spoken my peace and it sounds like
we're on the same page now, so we move on.
> As for the current syntax, I believe with a small syntax helper
> somewhere next to the field, this would be and feel completely
> natural. 01:30:10 is a bit meaningless if you're not working in
> seconds. One of my application uses standard milliseconds durations,
> would I have to write 01:30:10.5 to have another 500ms? Would I need
> 1-2 other fields for milli/microseconds - which would make us go back
> to the former problem ("Many input boxes is not a nice user
> experience")?
In my view, yes, 01:30:10.5 (or 01:30:10.500000 if you prefer) would
be the better approach. I will, however, freely admit that my support
for that syntax is based on nothing more than personal preference and
a vague idea of what I believe to be more common. I don't have any
research to back it up, but I don't expect any of us do in this area.
A quick search reveals that ISO 8601 is the relevant specification
here, which would leave us with something along the lines of
PT01H30M10S. In addition to being not-so-user-friendly, it seems ISO
8601 doesn't provide for anything smaller than a second, so we're back
to that same problem anyway.
> That's the way I was going until someone came up with the idea of
> parsing a timestring. Looking back, this is much more elegant, as long
> as the user knows what to do. The need for a javascript helper is
> entirely dropped since it's extremely easy to input any kind of value,
> and the user doesn't have to convert any kind of value. If the user
> wants 17 weeks, they just input "17w" instead of having to calculate
> 119 days. If they want "1500 seconds", same thing; so on.
I'll admit, my preferred approach does drop support for weeks, and if
you were to put in more than 24 hours, 60 minutes or 60 seconds, you'd
get a big, fat error message instead of the implicit calculations that
timedelta does behind the scenes. I still disagree with the notion
that the current syntax is "extremely easy to input any kind of
value," but again, neither statement is based on very much, so it's
likely impossible to say which is "better".
We're basically debating between the two representations allowed by
ISO 8601, at least in spirit. It seems an international panel of
experts couldn't decide on one over the other either, so they allow
both. Unfortunately, that's not really in keeping with Python
philosophy ("There should be one-- and preferably only one --obvious
way to do it."), so we need to pick one or the other. Whichever way we
go, it seems some of us will be Dutch, some of us won't. Such is life.
At this point, I'd say we should table the discussion on input syntax
until after 1.1 is out the door, so we can get some input from people
who have more sway in these matters. And yes, I do realize that I'm
the one who brought it up. ;)
> Also remember not everyone has javascript enabled.
I've seen this argument before, and it doesn't hold water. A
JavaScript helper is just that: a helper. It's not required to use the
field, it just makes it a bit easier for those who need a little help.
Those without JavaScript would just get text boxes without the helper,
just like the existing date and time fields.
> As for a wrapper TimeDelta class, that's up to Yuri to explain - I
> don't see the problem with it personally.
I wasn't pointing fingers at anybody in particular, I just don't see
that it adds anything beyond Python's own datetime.timedelta. Once
years and months are removed, it basically just performs unit
conversion and provides an output format in line with the new input
syntax. Python's timedelta already does the unit conversion, so that's
just duplicated effort. As for the output format, I'd rather see that
handled at the widget level anyway, so any other Python code that
deals with timedeltas doesn't get a shock when the output isn't what
Python normally provides.
-Gul